xref: /netbsd-src/sys/dev/wscons/wsdisplay_vcons.c (revision fd6a8bdebd774c17e15769f32449187c9632104f)
1*fd6a8bdeSmlelstv /*	$NetBSD: wsdisplay_vcons.c,v 1.69 2024/10/20 09:25:00 mlelstv Exp $ */
256953335Smacallan 
356953335Smacallan /*-
456953335Smacallan  * Copyright (c) 2005, 2006 Michael Lorenz
556953335Smacallan  * All rights reserved.
656953335Smacallan  *
756953335Smacallan  * Redistribution and use in source and binary forms, with or without
856953335Smacallan  * modification, are permitted provided that the following conditions
956953335Smacallan  * are met:
1056953335Smacallan  * 1. Redistributions of source code must retain the above copyright
1156953335Smacallan  *    notice, this list of conditions and the following disclaimer.
1256953335Smacallan  * 2. Redistributions in binary form must reproduce the above copyright
1356953335Smacallan  *    notice, this list of conditions and the following disclaimer in the
1456953335Smacallan  *    documentation and/or other materials provided with the distribution.
1556953335Smacallan  *
1656953335Smacallan  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
1756953335Smacallan  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
1856953335Smacallan  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1956953335Smacallan  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2056953335Smacallan  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2156953335Smacallan  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2256953335Smacallan  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2356953335Smacallan  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2456953335Smacallan  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2556953335Smacallan  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2656953335Smacallan  * POSSIBILITY OF SUCH DAMAGE.
2756953335Smacallan  */
2856953335Smacallan 
2956953335Smacallan #include <sys/cdefs.h>
30*fd6a8bdeSmlelstv __KERNEL_RCSID(0, "$NetBSD: wsdisplay_vcons.c,v 1.69 2024/10/20 09:25:00 mlelstv Exp $");
3156953335Smacallan 
3256953335Smacallan #include <sys/param.h>
3356953335Smacallan #include <sys/systm.h>
3456953335Smacallan #include <sys/kernel.h>
3556953335Smacallan #include <sys/buf.h>
3656953335Smacallan #include <sys/device.h>
3756953335Smacallan #include <sys/ioctl.h>
3856953335Smacallan #include <sys/malloc.h>
3956953335Smacallan #include <sys/mman.h>
4056953335Smacallan #include <sys/tty.h>
4156953335Smacallan #include <sys/conf.h>
4256953335Smacallan #include <sys/proc.h>
4356953335Smacallan #include <sys/kthread.h>
4456953335Smacallan #include <sys/tprintf.h>
45195f4ebfSmacallan #include <sys/atomic.h>
46a87987a6Sriastradh #include <sys/kmem.h>
4756953335Smacallan 
4856953335Smacallan #include <dev/wscons/wsdisplayvar.h>
4956953335Smacallan #include <dev/wscons/wsconsio.h>
5056953335Smacallan #include <dev/wsfont/wsfont.h>
5156953335Smacallan #include <dev/rasops/rasops.h>
5256953335Smacallan 
5356953335Smacallan #include <dev/wscons/wsdisplay_vconsvar.h>
5456953335Smacallan 
556cb10275Sriastradh #ifdef _KERNEL_OPT
5675a9d6c8Smacallan #include "opt_wsemul.h"
5775a9d6c8Smacallan #include "opt_wsdisplay_compat.h"
5875a9d6c8Smacallan #include "opt_vcons.h"
596cb10275Sriastradh #endif
6075a9d6c8Smacallan 
61c5fb1a74Smacallan #ifdef VCONS_DEBUG
62c5fb1a74Smacallan #define DPRINTF printf
63c5fb1a74Smacallan #else
64c5fb1a74Smacallan #define DPRINTF if (0) printf
65c5fb1a74Smacallan #endif
66c5fb1a74Smacallan 
67a87987a6Sriastradh struct vcons_data_private {
68a87987a6Sriastradh 	/* accessops */
69a87987a6Sriastradh 	int (*ioctl)(void *, void *, u_long, void *, int, struct lwp *);
70a87987a6Sriastradh 
71a87987a6Sriastradh 	/* rasops */
72a87987a6Sriastradh 	void (*copycols)(void *, int, int, int, int);
73a87987a6Sriastradh 	void (*erasecols)(void *, int, int, int, long);
74a87987a6Sriastradh 	void (*copyrows)(void *, int, int, int);
75a87987a6Sriastradh 	void (*eraserows)(void *, int, int, long);
76a87987a6Sriastradh 	void (*cursor)(void *, int, int, int);
77a87987a6Sriastradh 
78a87987a6Sriastradh 	/* virtual screen management stuff */
79a87987a6Sriastradh 	void (*switch_cb)(void *, int, int);
80a87987a6Sriastradh 	void *switch_cb_arg;
81a87987a6Sriastradh 	struct callout switch_callout;
82a87987a6Sriastradh 	uint32_t switch_pending;
83a87987a6Sriastradh 	LIST_HEAD(, vcons_screen) screens;
84a87987a6Sriastradh 	struct vcons_screen *wanted;
85a87987a6Sriastradh 	const struct wsscreen_descr *currenttype;
86a87987a6Sriastradh 	struct wsscreen_descr *defaulttype;
87a87987a6Sriastradh 	int switch_poll_count;
88a87987a6Sriastradh 
89a87987a6Sriastradh #ifdef VCONS_DRAW_INTR
90a87987a6Sriastradh 	int cells;
91a87987a6Sriastradh 	long *attrs;
92a87987a6Sriastradh 	uint32_t *chars;
93a87987a6Sriastradh 	int cursor_offset;
94a87987a6Sriastradh 	callout_t intr;
95a87987a6Sriastradh 	int intr_valid;
96a87987a6Sriastradh 	void *intr_softint;
97a87987a6Sriastradh 	int use_intr;		/* use intr drawing when non-zero */
98a87987a6Sriastradh #endif
99a87987a6Sriastradh };
100a87987a6Sriastradh 
10156953335Smacallan static void vcons_dummy_init_screen(void *, struct vcons_screen *, int,
10256953335Smacallan 	    long *);
10356953335Smacallan 
10453524e44Schristos static int  vcons_ioctl(void *, void *, u_long, void *, int, struct lwp *);
10556953335Smacallan static int  vcons_alloc_screen(void *, const struct wsscreen_descr *, void **,
10656953335Smacallan 	    int *, int *, long *);
10756953335Smacallan static void vcons_free_screen(void *, void *);
10856953335Smacallan static int  vcons_show_screen(void *, void *, int, void (*)(void *, int, int),
10956953335Smacallan 	    void *);
110c5fb1a74Smacallan static int  vcons_load_font(void *, void *, struct wsdisplay_font *);
11156953335Smacallan 
11275a9d6c8Smacallan #ifdef WSDISPLAY_SCROLLSUPPORT
11375a9d6c8Smacallan static void vcons_scroll(void *, void *, int);
11475a9d6c8Smacallan static void vcons_do_scroll(struct vcons_screen *);
11575a9d6c8Smacallan #endif
11675a9d6c8Smacallan 
11754575b3cSjoerg static void vcons_do_switch(void *);
11856953335Smacallan 
11956953335Smacallan /* methods that work only on text buffers */
12056953335Smacallan static void vcons_copycols_buffer(void *, int, int, int, int);
12156953335Smacallan static void vcons_erasecols_buffer(void *, int, int, int, long);
12256953335Smacallan static void vcons_copyrows_buffer(void *, int, int, int);
12356953335Smacallan static void vcons_eraserows_buffer(void *, int, int, long);
1247b475855Smacallan static int vcons_putchar_buffer(void *, int, int, u_int, long);
12556953335Smacallan 
12656953335Smacallan /*
12756953335Smacallan  * actual wrapper methods which call both the _buffer ones above and the
12856953335Smacallan  * driver supplied ones to do the drawing
12956953335Smacallan  */
13056953335Smacallan static void vcons_copycols(void *, int, int, int, int);
13156953335Smacallan static void vcons_erasecols(void *, int, int, int, long);
13256953335Smacallan static void vcons_copyrows(void *, int, int, int);
13356953335Smacallan static void vcons_eraserows(void *, int, int, long);
13456953335Smacallan static void vcons_putchar(void *, int, int, u_int, long);
1356eb32961Smacallan #ifdef VCONS_DRAW_INTR
1364066bef8Smlelstv static void vcons_erasecols_cached(void *, int, int, int, long);
1374066bef8Smlelstv static void vcons_eraserows_cached(void *, int, int, long);
1386eb32961Smacallan static void vcons_putchar_cached(void *, int, int, u_int, long);
1396eb32961Smacallan #endif
14056953335Smacallan static void vcons_cursor(void *, int, int, int);
141d701d9f4Smacallan static void vcons_cursor_noread(void *, int, int, int);
14256953335Smacallan 
1439c10440fSmacallan /*
1449c10440fSmacallan  * methods that avoid framebuffer reads
1459c10440fSmacallan  */
1469c10440fSmacallan static void vcons_copycols_noread(void *, int, int, int, int);
1479c10440fSmacallan static void vcons_copyrows_noread(void *, int, int, int);
1489c10440fSmacallan 
1499c10440fSmacallan 
15075a9d6c8Smacallan /* support for reading/writing text buffers. For wsmoused */
151aec18036Sjmmv static int  vcons_putwschar(struct vcons_screen *, struct wsdisplay_char *);
152aec18036Sjmmv static int  vcons_getwschar(struct vcons_screen *, struct wsdisplay_char *);
15356953335Smacallan 
15456953335Smacallan static void vcons_lock(struct vcons_screen *);
15556953335Smacallan static void vcons_unlock(struct vcons_screen *);
15656953335Smacallan 
1578485f287Sjmcneill #ifdef VCONS_DRAW_INTR
1588485f287Sjmcneill static void vcons_intr(void *);
1593f11f2aaSjmcneill static void vcons_softintr(void *);
1601b26a1b9Sjmcneill static void vcons_init_thread(void *);
161a87987a6Sriastradh static void vcons_invalidate_cache(struct vcons_data *);
1628485f287Sjmcneill #endif
16356953335Smacallan 
164d7b10139Sriastradh static inline bool
165d7b10139Sriastradh vcons_use_intr(const struct vcons_screen *scr)
166d7b10139Sriastradh {
167d7b10139Sriastradh #ifdef VCONS_DRAW_INTR
168a87987a6Sriastradh 	return scr->scr_vd->private->use_intr;
169d7b10139Sriastradh #else
170d7b10139Sriastradh 	return false;
171d7b10139Sriastradh #endif
172d7b10139Sriastradh }
173d7b10139Sriastradh 
174f50ac8c2Sriastradh static inline void
175f50ac8c2Sriastradh vcons_dirty(struct vcons_screen *scr)
176f50ac8c2Sriastradh {
177f50ac8c2Sriastradh #ifdef VCONS_DRAW_INTR
178830aae3fSriastradh 	membar_release();
179f50ac8c2Sriastradh 	atomic_inc_uint(&scr->scr_dirty);
180f50ac8c2Sriastradh #endif
181f50ac8c2Sriastradh }
182f50ac8c2Sriastradh 
1831b26a1b9Sjmcneill static int
1841b26a1b9Sjmcneill vcons_init_common(struct vcons_data *vd, void *cookie,
1851b26a1b9Sjmcneill     struct wsscreen_descr *def, struct wsdisplay_accessops *ao,
1861b26a1b9Sjmcneill     int enable_intr)
18756953335Smacallan {
188a87987a6Sriastradh 	struct vcons_data_private *vdp;
189e594a414Smacallan 
190e594a414Smacallan 	/* zero out everything so we can rely on untouched fields being 0 */
191b16c42a9Smacallan 	memset(vd, 0, sizeof(struct vcons_data));
192e594a414Smacallan 
193a87987a6Sriastradh 	vd->private = vdp = kmem_zalloc(sizeof(*vdp), KM_SLEEP);
19456953335Smacallan 	vd->cookie = cookie;
19556953335Smacallan 
19656953335Smacallan 	vd->init_screen = vcons_dummy_init_screen;
19756953335Smacallan 	vd->show_screen_cb = NULL;
19856953335Smacallan 
199aec18036Sjmmv 	/* keep a copy of the accessops that we replace below with our
200aec18036Sjmmv 	 * own wrappers */
201a87987a6Sriastradh 	vdp->ioctl = ao->ioctl;
202aec18036Sjmmv 
203aec18036Sjmmv 	/* configure the accessops */
204aec18036Sjmmv 	ao->ioctl = vcons_ioctl;
20556953335Smacallan 	ao->alloc_screen = vcons_alloc_screen;
20656953335Smacallan 	ao->free_screen = vcons_free_screen;
20756953335Smacallan 	ao->show_screen = vcons_show_screen;
208c5fb1a74Smacallan 	ao->load_font = vcons_load_font;
20975a9d6c8Smacallan #ifdef WSDISPLAY_SCROLLSUPPORT
21075a9d6c8Smacallan 	ao->scroll = vcons_scroll;
21175a9d6c8Smacallan #endif
21256953335Smacallan 
213a87987a6Sriastradh 	LIST_INIT(&vdp->screens);
21456953335Smacallan 	vd->active = NULL;
215a87987a6Sriastradh 	vdp->wanted = NULL;
216a87987a6Sriastradh 	vdp->currenttype = def;
217a87987a6Sriastradh 	vdp->defaulttype = def;
218a87987a6Sriastradh 	callout_init(&vdp->switch_callout, 0);
219a87987a6Sriastradh 	callout_setfunc(&vdp->switch_callout, vcons_do_switch, vd);
2206eb32961Smacallan #ifdef VCONS_DRAW_INTR
221a87987a6Sriastradh 	vdp->cells = 0;
222a87987a6Sriastradh 	vdp->attrs = NULL;
223a87987a6Sriastradh 	vdp->chars = NULL;
224a87987a6Sriastradh 	vdp->cursor_offset = -1;
2256eb32961Smacallan #endif
22656953335Smacallan 
22756953335Smacallan 	/*
22856953335Smacallan 	 * a lock to serialize access to the framebuffer.
22956953335Smacallan 	 * when switching screens we need to make sure there's no rasops
23056953335Smacallan 	 * operation in progress
23156953335Smacallan 	 */
23256953335Smacallan #ifdef DIAGNOSTIC
233a87987a6Sriastradh 	vdp->switch_poll_count = 0;
23456953335Smacallan #endif
2358485f287Sjmcneill #ifdef VCONS_DRAW_INTR
2361b26a1b9Sjmcneill 	if (enable_intr) {
237a87987a6Sriastradh 		vdp->intr_softint = softint_establish(SOFTINT_SERIAL,
2383f11f2aaSjmcneill 		    vcons_softintr, vd);
239a87987a6Sriastradh 		callout_init(&vdp->intr, CALLOUT_MPSAFE);
240a87987a6Sriastradh 		callout_setfunc(&vdp->intr, vcons_intr, vd);
241a87987a6Sriastradh 		vdp->intr_valid = 1;
242232459adSjmcneill 
2431b26a1b9Sjmcneill 		if (kthread_create(PRI_NONE, 0, NULL, vcons_init_thread, vd,
2441b26a1b9Sjmcneill 		    NULL, "vcons_init") != 0) {
2451b26a1b9Sjmcneill 			printf("%s: unable to create thread.\n", __func__);
2461b26a1b9Sjmcneill 			return -1;
2471b26a1b9Sjmcneill 		}
2481b26a1b9Sjmcneill 	}
2498485f287Sjmcneill #endif
25056953335Smacallan 	return 0;
25156953335Smacallan }
25256953335Smacallan 
2531b26a1b9Sjmcneill int
2541b26a1b9Sjmcneill vcons_init(struct vcons_data *vd, void *cookie,
2551b26a1b9Sjmcneill     struct wsscreen_descr *def, struct wsdisplay_accessops *ao)
2561b26a1b9Sjmcneill {
2571b26a1b9Sjmcneill 	return vcons_init_common(vd, cookie, def, ao, 1);
2581b26a1b9Sjmcneill }
2591b26a1b9Sjmcneill 
2601b26a1b9Sjmcneill int
2611b26a1b9Sjmcneill vcons_earlyinit(struct vcons_data *vd, void *cookie,
2621b26a1b9Sjmcneill     struct wsscreen_descr *def, struct wsdisplay_accessops *ao)
2631b26a1b9Sjmcneill {
2641b26a1b9Sjmcneill 	return vcons_init_common(vd, cookie, def, ao, 0);
2651b26a1b9Sjmcneill }
2661b26a1b9Sjmcneill 
26756953335Smacallan static void
26856953335Smacallan vcons_lock(struct vcons_screen *scr)
26956953335Smacallan {
27056953335Smacallan #ifdef VCONS_PARANOIA
27156953335Smacallan 	int s;
27256953335Smacallan 
27356953335Smacallan 	s = splhigh();
27456953335Smacallan #endif
27556953335Smacallan 	SCREEN_BUSY(scr);
27656953335Smacallan #ifdef VCONS_PARANOIA
27756953335Smacallan 	splx(s);
27856953335Smacallan #endif
27956953335Smacallan }
28056953335Smacallan 
28156953335Smacallan static void
28256953335Smacallan vcons_unlock(struct vcons_screen *scr)
28356953335Smacallan {
28456953335Smacallan #ifdef VCONS_PARANOIA
28556953335Smacallan 	int s;
28656953335Smacallan 
28756953335Smacallan 	s = splhigh();
28856953335Smacallan #endif
28956953335Smacallan 	SCREEN_IDLE(scr);
29056953335Smacallan #ifdef VCONS_PARANOIA
29156953335Smacallan 	splx(s);
29256953335Smacallan #endif
29356953335Smacallan }
29456953335Smacallan 
29556953335Smacallan static void
296168cd830Schristos vcons_dummy_init_screen(void *cookie,
297168cd830Schristos     struct vcons_screen *scr, int exists,
298168cd830Schristos     long *defattr)
29956953335Smacallan {
30056953335Smacallan 
30156953335Smacallan 	/*
30256953335Smacallan 	 * default init_screen() method.
30356953335Smacallan 	 * Needs to be overwritten so we bitch and whine in case anyone ends
30456953335Smacallan 	 * up in here.
30556953335Smacallan 	 */
30656953335Smacallan 	printf("vcons_init_screen: dummy function called. Your driver is "
30756953335Smacallan 	       "supposed to supply a replacement for proper operation\n");
30856953335Smacallan }
30956953335Smacallan 
310c5fb1a74Smacallan static int
311c5fb1a74Smacallan vcons_alloc_buffers(struct vcons_data *vd, struct vcons_screen *scr)
31256953335Smacallan {
31356953335Smacallan 	struct rasops_info *ri = &scr->scr_ri;
31456953335Smacallan 	int cnt, i;
3156eb32961Smacallan #ifdef VCONS_DRAW_INTR
316a87987a6Sriastradh 	struct vcons_data_private *vdp = vd->private;
3176eb32961Smacallan 	int size;
3186eb32961Smacallan #endif
31956953335Smacallan 
320c5fb1a74Smacallan 	/*
321c5fb1a74Smacallan 	 * we allocate both chars and attributes in one chunk, attributes first
322c5fb1a74Smacallan 	 * because they have the (potentially) bigger alignment
323c5fb1a74Smacallan 	 */
324c5fb1a74Smacallan #ifdef WSDISPLAY_SCROLLSUPPORT
325c5fb1a74Smacallan 	cnt = (ri->ri_rows + WSDISPLAY_SCROLLBACK_LINES) * ri->ri_cols;
326c5fb1a74Smacallan 	scr->scr_lines_in_buffer = WSDISPLAY_SCROLLBACK_LINES;
327c5fb1a74Smacallan 	scr->scr_current_line = 0;
328c5fb1a74Smacallan 	scr->scr_line_wanted = 0;
329c5fb1a74Smacallan 	scr->scr_offset_to_zero = ri->ri_cols * WSDISPLAY_SCROLLBACK_LINES;
330c5fb1a74Smacallan 	scr->scr_current_offset = scr->scr_offset_to_zero;
331c5fb1a74Smacallan #else
332c5fb1a74Smacallan 	cnt = ri->ri_rows * ri->ri_cols;
333c5fb1a74Smacallan #endif
334c5fb1a74Smacallan 	scr->scr_attrs = malloc(cnt * (sizeof(long) +
335c5fb1a74Smacallan 	    sizeof(uint32_t)), M_DEVBUF, M_WAITOK);
336c5fb1a74Smacallan 	if (scr->scr_attrs == NULL)
337c5fb1a74Smacallan 		return ENOMEM;
338c5fb1a74Smacallan 
339c5fb1a74Smacallan 	scr->scr_chars = (uint32_t *)&scr->scr_attrs[cnt];
340c5fb1a74Smacallan 
341c5fb1a74Smacallan 	/*
342c5fb1a74Smacallan 	 * fill the attribute buffer with *defattr, chars with 0x20
343c5fb1a74Smacallan 	 * since we don't know if the driver tries to mimic firmware output or
344c5fb1a74Smacallan 	 * reset everything we do nothing to VRAM here, any driver that feels
345c5fb1a74Smacallan 	 * the need to clear screen or something will have to do it on its own
346c5fb1a74Smacallan 	 * Additional screens will start out in the background anyway so
347c5fb1a74Smacallan 	 * cleaning or not only really affects the initial console screen
348c5fb1a74Smacallan 	 */
349c5fb1a74Smacallan 	for (i = 0; i < cnt; i++) {
350c5fb1a74Smacallan 		scr->scr_attrs[i] = scr->scr_defattr;
351c5fb1a74Smacallan 		scr->scr_chars[i] = 0x20;
352c5fb1a74Smacallan 	}
353c5fb1a74Smacallan 
354c5fb1a74Smacallan #ifdef VCONS_DRAW_INTR
355c5fb1a74Smacallan 	size = ri->ri_cols * ri->ri_rows;
356a87987a6Sriastradh 	if (size > vdp->cells) {
35707fb6665Sriastradh 		if (vdp->chars != NULL)
35807fb6665Sriastradh 			free(vdp->chars, M_DEVBUF);
35907fb6665Sriastradh 		if (vdp->attrs != NULL)
36007fb6665Sriastradh 			free(vdp->attrs, M_DEVBUF);
361a87987a6Sriastradh 		vdp->cells = size;
362a87987a6Sriastradh 		vdp->chars = malloc(size * sizeof(uint32_t), M_DEVBUF,
363c5fb1a74Smacallan 		    M_WAITOK|M_ZERO);
364a87987a6Sriastradh 		vdp->attrs = malloc(size * sizeof(long), M_DEVBUF,
365c5fb1a74Smacallan 		    M_WAITOK|M_ZERO);
366c5fb1a74Smacallan 		vcons_invalidate_cache(vd);
367c5fb1a74Smacallan 	} else if (SCREEN_IS_VISIBLE(scr))
368c5fb1a74Smacallan 		vcons_invalidate_cache(vd);
369c5fb1a74Smacallan #endif
370c5fb1a74Smacallan 	return 0;
371c5fb1a74Smacallan }
372c5fb1a74Smacallan 
373c5fb1a74Smacallan int
374c5fb1a74Smacallan vcons_init_screen(struct vcons_data *vd, struct vcons_screen *scr,
375c5fb1a74Smacallan     int existing, long *defattr)
376c5fb1a74Smacallan {
377a87987a6Sriastradh 	struct vcons_data_private *vdp = vd->private;
378c5fb1a74Smacallan 	struct rasops_info *ri = &scr->scr_ri;
379c5fb1a74Smacallan 	int i;
380c5fb1a74Smacallan 
38156953335Smacallan 	scr->scr_cookie = vd->cookie;
3824baf3443Sjmcneill 	scr->scr_vd = scr->scr_origvd = vd;
38375a9d6c8Smacallan 	scr->scr_busy = 0;
3841421352eSmacallan 
385c5fb1a74Smacallan 	if (scr->scr_type == NULL)
386a87987a6Sriastradh 		scr->scr_type = vdp->defaulttype;
38756953335Smacallan 
38856953335Smacallan 	/*
38956953335Smacallan 	 * call the driver-supplied init_screen function which is expected
39056953335Smacallan 	 * to set up rasops_info, override cursor() and probably others
39156953335Smacallan 	 */
39256953335Smacallan 	vd->init_screen(vd->cookie, scr, existing, defattr);
39356953335Smacallan 
39456953335Smacallan 	/*
39556953335Smacallan 	 * save the non virtual console aware rasops and replace them with
39656953335Smacallan 	 * our wrappers
39756953335Smacallan 	 */
398a87987a6Sriastradh 	vdp->eraserows = ri->ri_ops.eraserows;
399a87987a6Sriastradh 	vdp->erasecols = ri->ri_ops.erasecols;
400c5fb1a74Smacallan 	scr->putchar   = ri->ri_ops.putchar;
40156953335Smacallan 
402195f4ebfSmacallan 	if (scr->scr_flags & VCONS_NO_COPYCOLS) {
403a87987a6Sriastradh 		vdp->copycols  = vcons_copycols_noread;
404195f4ebfSmacallan 	} else {
405a87987a6Sriastradh 		vdp->copycols = ri->ri_ops.copycols;
406195f4ebfSmacallan 	}
407195f4ebfSmacallan 
408195f4ebfSmacallan 	if (scr->scr_flags & VCONS_NO_COPYROWS) {
409a87987a6Sriastradh 		vdp->copyrows  = vcons_copyrows_noread;
410195f4ebfSmacallan 	} else {
411a87987a6Sriastradh 		vdp->copyrows = ri->ri_ops.copyrows;
412195f4ebfSmacallan 	}
413195f4ebfSmacallan 
4141421352eSmacallan 	if (scr->scr_flags & VCONS_NO_CURSOR) {
415a87987a6Sriastradh 		vdp->cursor  = vcons_cursor_noread;
4161421352eSmacallan 	} else {
417a87987a6Sriastradh 		vdp->cursor = ri->ri_ops.cursor;
4181421352eSmacallan 	}
4191421352eSmacallan 
42056953335Smacallan 	ri->ri_ops.eraserows = vcons_eraserows;
42156953335Smacallan 	ri->ri_ops.erasecols = vcons_erasecols;
42256953335Smacallan 	ri->ri_ops.putchar   = vcons_putchar;
42356953335Smacallan 	ri->ri_ops.cursor    = vcons_cursor;
4249c10440fSmacallan 	ri->ri_ops.copycols  = vcons_copycols;
42542092a5fSmacallan 	ri->ri_ops.copyrows  = vcons_copyrows;
426195f4ebfSmacallan 
42742092a5fSmacallan 
42856953335Smacallan 	ri->ri_hw = scr;
42956953335Smacallan 
430c47f805aSchristos 	i = ri->ri_ops.allocattr(ri, WS_DEFAULT_FG, WS_DEFAULT_BG, 0, defattr);
431c47f805aSchristos 	if (i != 0) {
432c47f805aSchristos #ifdef DIAGNOSTIC
433c47f805aSchristos 		printf("vcons: error allocating attribute %d\n", i);
434c47f805aSchristos #endif
435c47f805aSchristos 		scr->scr_defattr = 0;
436c47f805aSchristos 	} else
43756953335Smacallan 		scr->scr_defattr = *defattr;
43856953335Smacallan 
439c5fb1a74Smacallan 	vcons_alloc_buffers(vd, scr);
4406eb32961Smacallan 
441e594a414Smacallan 	if (vd->active == NULL) {
442e594a414Smacallan 		vd->active = scr;
443e594a414Smacallan 		SCREEN_VISIBLE(scr);
44456953335Smacallan 	}
445e594a414Smacallan 
446e594a414Smacallan 	if (existing) {
447e594a414Smacallan 		SCREEN_VISIBLE(scr);
448e594a414Smacallan 		vd->active = scr;
449e594a414Smacallan 	} else {
450e594a414Smacallan 		SCREEN_INVISIBLE(scr);
451e594a414Smacallan 	}
45256953335Smacallan 
453a87987a6Sriastradh 	LIST_INSERT_HEAD(&vdp->screens, scr, next);
45456953335Smacallan 	return 0;
45556953335Smacallan }
45656953335Smacallan 
457c5fb1a74Smacallan static int
458c5fb1a74Smacallan vcons_load_font(void *v, void *cookie, struct wsdisplay_font *f)
459c5fb1a74Smacallan {
460c5fb1a74Smacallan 	struct vcons_data *vd = v;
461a87987a6Sriastradh 	struct vcons_data_private *vdp = vd->private;
462c5fb1a74Smacallan 	struct vcons_screen *scr = cookie;
463c5fb1a74Smacallan 	struct rasops_info *ri;
464c5fb1a74Smacallan 	struct wsdisplay_font *font;
465c5fb1a74Smacallan 	int flags = WSFONT_FIND_BITMAP, fcookie;
466c5fb1a74Smacallan 
467c5fb1a74Smacallan 	/* see if we're asked to add a font or use it */
468c5fb1a74Smacallan 	if (scr == NULL)
469c5fb1a74Smacallan 		return 0;
470c5fb1a74Smacallan 
471c5fb1a74Smacallan 	ri = &scr->scr_ri;
472c5fb1a74Smacallan 
473c5fb1a74Smacallan 	/* see if the driver knows how to handle multiple fonts */
474c5fb1a74Smacallan 	if ((scr->scr_flags & VCONS_LOADFONT) == 0) {
475c5fb1a74Smacallan 		return EOPNOTSUPP;
476c5fb1a74Smacallan 	}
477c5fb1a74Smacallan 
478c5fb1a74Smacallan 	/* now see what fonts we can use */
479c5fb1a74Smacallan 	if (ri->ri_flg & RI_ENABLE_ALPHA) {
480c5fb1a74Smacallan 		flags |= WSFONT_FIND_ALPHA;
481c5fb1a74Smacallan 	}
482c5fb1a74Smacallan 
4833ef682c1Smacallan 	fcookie = wsfont_find(f->name, 0, 0, 0,
4843ef682c1Smacallan 	    /* bitorder */
4853ef682c1Smacallan 	    scr->scr_flags & VCONS_FONT_BITS_R2L ?
4863ef682c1Smacallan 	      WSDISPLAY_FONTORDER_R2L : WSDISPLAY_FONTORDER_L2R,
4873ef682c1Smacallan 	    /* byteorder */
4883ef682c1Smacallan 	    scr->scr_flags & VCONS_FONT_BYTES_R2L ?
4893ef682c1Smacallan 	      WSDISPLAY_FONTORDER_R2L : WSDISPLAY_FONTORDER_L2R,
4903ef682c1Smacallan 	    flags);
491c5fb1a74Smacallan 	if (fcookie == -1)
492c5fb1a74Smacallan 		return EINVAL;
493c5fb1a74Smacallan 
494c5fb1a74Smacallan 	wsfont_lock(fcookie, &font);
495c5fb1a74Smacallan 	if (font == NULL)
496c5fb1a74Smacallan 		return EINVAL;
497c5fb1a74Smacallan 
498c5fb1a74Smacallan 	/* ok, we got a font. Now clear the screen with the old parameters */
499c5fb1a74Smacallan 	if (SCREEN_IS_VISIBLE(scr))
500a87987a6Sriastradh 		vdp->eraserows(ri, 0, ri->ri_rows, scr->scr_defattr);
501c5fb1a74Smacallan 
502c5fb1a74Smacallan 	vcons_lock(vd->active);
503c5fb1a74Smacallan #ifdef VCONS_DRAW_INTR
504a87987a6Sriastradh 	callout_halt(&vdp->intr, NULL);
505c5fb1a74Smacallan #endif
506c5fb1a74Smacallan 	/* set the new font and re-initialize things */
507c5fb1a74Smacallan 	ri->ri_font = font;
508c5fb1a74Smacallan 	wsfont_unlock(ri->ri_wsfcookie);
509c5fb1a74Smacallan 	ri->ri_wsfcookie = fcookie;
510c5fb1a74Smacallan 
511c5fb1a74Smacallan 	vd->init_screen(vd->cookie, scr, 1, &scr->scr_defattr);
512c5fb1a74Smacallan 	DPRINTF("caps %x %x\n", scr->scr_type->capabilities, ri->ri_caps);
513c5fb1a74Smacallan 	if (scr->scr_type->capabilities & WSSCREEN_RESIZE) {
514c5fb1a74Smacallan 		scr->scr_type->nrows = ri->ri_rows;
515c5fb1a74Smacallan 		scr->scr_type->ncols = ri->ri_cols;
516c5fb1a74Smacallan 		DPRINTF("new size %d %d\n", ri->ri_rows, ri->ri_cols);
517c5fb1a74Smacallan 	}
518c5fb1a74Smacallan 
519c5fb1a74Smacallan 
520c5fb1a74Smacallan 	/* now, throw the old buffers away */
521c5fb1a74Smacallan 	if (scr->scr_attrs)
522c5fb1a74Smacallan 		free(scr->scr_attrs, M_DEVBUF);
523c5fb1a74Smacallan 	/* allocate new buffers */
524c5fb1a74Smacallan 	vcons_alloc_buffers(vd, scr);
525c5fb1a74Smacallan 
52699ff214aSrin 	/* save the potentially changed ri_ops */
527a87987a6Sriastradh 	vdp->eraserows = ri->ri_ops.eraserows;
528a87987a6Sriastradh 	vdp->erasecols = ri->ri_ops.erasecols;
529c5fb1a74Smacallan 	scr->putchar   = ri->ri_ops.putchar;
530a87987a6Sriastradh 	vdp->cursor    = ri->ri_ops.cursor;
53199ff214aSrin 
53299ff214aSrin 	if (scr->scr_flags & VCONS_NO_COPYCOLS) {
533a87987a6Sriastradh 		vdp->copycols  = vcons_copycols_noread;
53499ff214aSrin 	} else {
535a87987a6Sriastradh 		vdp->copycols = ri->ri_ops.copycols;
53699ff214aSrin 	}
53799ff214aSrin 
53899ff214aSrin 	if (scr->scr_flags & VCONS_NO_COPYROWS) {
539a87987a6Sriastradh 		vdp->copyrows  = vcons_copyrows_noread;
54099ff214aSrin 	} else {
541a87987a6Sriastradh 		vdp->copyrows = ri->ri_ops.copyrows;
54299ff214aSrin 	}
543c5fb1a74Smacallan 
5441421352eSmacallan 	if (scr->scr_flags & VCONS_NO_CURSOR) {
545a87987a6Sriastradh 		vdp->cursor  = vcons_cursor_noread;
5461421352eSmacallan 	} else {
547a87987a6Sriastradh 		vdp->cursor = ri->ri_ops.cursor;
5481421352eSmacallan 	}
5491421352eSmacallan 
550c5fb1a74Smacallan 	/* and put our wrappers back */
551c5fb1a74Smacallan 	ri->ri_ops.eraserows = vcons_eraserows;
552c5fb1a74Smacallan 	ri->ri_ops.erasecols = vcons_erasecols;
553c5fb1a74Smacallan 	ri->ri_ops.putchar   = vcons_putchar;
554c5fb1a74Smacallan 	ri->ri_ops.cursor    = vcons_cursor;
555c5fb1a74Smacallan 	ri->ri_ops.copycols  = vcons_copycols;
556c5fb1a74Smacallan 	ri->ri_ops.copyrows  = vcons_copyrows;
557c5fb1a74Smacallan 	vcons_unlock(vd->active);
5589dac6880Smacallan 
5599dac6880Smacallan 	/* notify things that we're about to redraw */
5609dac6880Smacallan 	if (vd->show_screen_cb != NULL)
5619dac6880Smacallan 		vd->show_screen_cb(scr, vd->show_screen_cookie);
5629dac6880Smacallan 
563c5fb1a74Smacallan #ifdef VCONS_DRAW_INTR
564c5fb1a74Smacallan 	/*
565c5fb1a74Smacallan 	 * XXX
566c5fb1a74Smacallan 	 * Something(tm) craps all over VRAM somewhere up there if we're
567c5fb1a74Smacallan 	 * using VCONS_DRAW_INTR. Until I figure out what causes it, just
568c5fb1a74Smacallan 	 * redraw the screen for now.
569c5fb1a74Smacallan 	 */
570c5fb1a74Smacallan 	vcons_redraw_screen(vd->active);
571a87987a6Sriastradh 	callout_schedule(&vdp->intr, mstohz(33));
572c5fb1a74Smacallan #endif
573c5fb1a74Smacallan 	/* no need to draw anything, wsdisplay should reset the terminal */
574c5fb1a74Smacallan 
575c5fb1a74Smacallan 	return 0;
576c5fb1a74Smacallan }
577c5fb1a74Smacallan 
57856953335Smacallan static void
57954575b3cSjoerg vcons_do_switch(void *arg)
58056953335Smacallan {
58154575b3cSjoerg 	struct vcons_data *vd = arg;
582a87987a6Sriastradh 	struct vcons_data_private *vdp = vd->private;
58356953335Smacallan 	struct vcons_screen *scr, *oldscr;
58456953335Smacallan 
585a87987a6Sriastradh 	scr = vdp->wanted;
58656953335Smacallan 	if (!scr) {
58756953335Smacallan 		printf("vcons_switch_screen: disappeared\n");
588a87987a6Sriastradh 		vdp->switch_cb(vdp->switch_cb_arg, EIO, 0);
58956953335Smacallan 		return;
59056953335Smacallan 	}
59156953335Smacallan 	oldscr = vd->active; /* can be NULL! */
59256953335Smacallan 
59356953335Smacallan 	/*
59456953335Smacallan 	 * if there's an old, visible screen we mark it invisible and wait
59556953335Smacallan 	 * until it's not busy so we can safely switch
59656953335Smacallan 	 */
59756953335Smacallan 	if (oldscr != NULL) {
59856953335Smacallan 		SCREEN_INVISIBLE(oldscr);
59956953335Smacallan 		if (SCREEN_IS_BUSY(oldscr)) {
600a87987a6Sriastradh 			callout_schedule(&vdp->switch_callout, 1);
60156953335Smacallan #ifdef DIAGNOSTIC
60256953335Smacallan 			/* bitch if we wait too long */
603a87987a6Sriastradh 			vdp->switch_poll_count++;
604a87987a6Sriastradh 			if (vdp->switch_poll_count > 100) {
60556953335Smacallan 				panic("vcons: screen still busy");
60656953335Smacallan 			}
60756953335Smacallan #endif
60856953335Smacallan 			return;
60956953335Smacallan 		}
61056953335Smacallan 		/* invisible screen -> no visible cursor image */
61156953335Smacallan 		oldscr->scr_ri.ri_flg &= ~RI_CURSOR;
61256953335Smacallan #ifdef DIAGNOSTIC
613a87987a6Sriastradh 		vdp->switch_poll_count = 0;
61456953335Smacallan #endif
61556953335Smacallan 	}
61656953335Smacallan 
61756953335Smacallan 	if (scr == oldscr)
61856953335Smacallan 		return;
61956953335Smacallan 
62056953335Smacallan #ifdef DIAGNOSTIC
62156953335Smacallan 	if (SCREEN_IS_VISIBLE(scr))
62275a9d6c8Smacallan 		printf("vcons_switch_screen: already active");
62356953335Smacallan #endif
62456953335Smacallan 
62556953335Smacallan #ifdef notyet
626a87987a6Sriastradh 	if (vdp->currenttype != type) {
62756953335Smacallan 		vcons_set_screentype(vd, type);
628a87987a6Sriastradh 		vdp->currenttype = type;
62956953335Smacallan 	}
63056953335Smacallan #endif
63156953335Smacallan 
63256953335Smacallan 	SCREEN_VISIBLE(scr);
63356953335Smacallan 	vd->active = scr;
634a87987a6Sriastradh 	vdp->wanted = NULL;
63556953335Smacallan 
636c5fb1a74Smacallan #ifdef VCONS_DRAW_INTR
637c5fb1a74Smacallan 	vcons_invalidate_cache(vd);
638c5fb1a74Smacallan #endif
639c5fb1a74Smacallan 
64056953335Smacallan 	if (vd->show_screen_cb != NULL)
6419dac6880Smacallan 		vd->show_screen_cb(scr, vd->show_screen_cookie);
64256953335Smacallan 
64356953335Smacallan 	if ((scr->scr_flags & VCONS_NO_REDRAW) == 0)
64456953335Smacallan 		vcons_redraw_screen(scr);
64556953335Smacallan 
646a87987a6Sriastradh 	if (vdp->switch_cb)
647a87987a6Sriastradh 		vdp->switch_cb(vdp->switch_cb_arg, 0, 0);
64856953335Smacallan }
64956953335Smacallan 
65056953335Smacallan void
65156953335Smacallan vcons_redraw_screen(struct vcons_screen *scr)
65256953335Smacallan {
653e8a38776Smacallan 	uint32_t *charptr = scr->scr_chars, c;
654e8a38776Smacallan 	long *attrptr = scr->scr_attrs, a, last_a = 0, mask, cmp, acmp;
65556953335Smacallan 	struct rasops_info *ri = &scr->scr_ri;
6566eb32961Smacallan 	struct vcons_data *vd = scr->scr_vd;
657a87987a6Sriastradh 	struct vcons_data_private *vdp = vd->private;
658e8a38776Smacallan 	int i, j, offset, boffset = 0, start = -1;
65956953335Smacallan 
660e8a38776Smacallan 	mask = 0x00ff00ff;	/* background and flags */
6615d271612Smacallan 	cmp = 0xffffffff;	/* never match anything */
66256953335Smacallan 	vcons_lock(scr);
66323d47317Smacallan 	if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) {
66456953335Smacallan 
66556953335Smacallan 		/*
66656953335Smacallan 		 * only clear the screen when RI_FULLCLEAR is set since we're
66756953335Smacallan 		 * going to overwrite every single character cell anyway
66856953335Smacallan 		 */
66956953335Smacallan 		if (ri->ri_flg & RI_FULLCLEAR) {
670a87987a6Sriastradh 			vdp->eraserows(ri, 0, ri->ri_rows,
67156953335Smacallan 			    scr->scr_defattr);
672e8a38776Smacallan 			cmp = scr->scr_defattr & mask;
67356953335Smacallan 		}
67456953335Smacallan 
67556953335Smacallan 		/* redraw the screen */
67675a9d6c8Smacallan #ifdef WSDISPLAY_SCROLLSUPPORT
67775a9d6c8Smacallan 		offset = scr->scr_current_offset;
67875a9d6c8Smacallan #else
67956953335Smacallan 		offset = 0;
68075a9d6c8Smacallan #endif
68156953335Smacallan 		for (i = 0; i < ri->ri_rows; i++) {
682e8a38776Smacallan 			start = -1;
68356953335Smacallan 			for (j = 0; j < ri->ri_cols; j++) {
68456953335Smacallan 				/*
68556953335Smacallan 				 * no need to use the wrapper function - we
68656953335Smacallan 				 * don't change any characters or attributes
68756953335Smacallan 				 * and we already made sure the screen we're
68856953335Smacallan 				 * working on is visible
68956953335Smacallan 				 */
690e8a38776Smacallan 				c = charptr[offset];
691e8a38776Smacallan 				a = attrptr[offset];
692e8a38776Smacallan 				acmp = a & mask;
693e8a38776Smacallan 				if (c == ' ') {
694e8a38776Smacallan 					/*
695e8a38776Smacallan 					 * if we already erased the background
696d701d9f4Smacallan 					 * and if this blank uses the same
697d701d9f4Smacallan 					 * colour and flags we don't need to do
698e8a38776Smacallan 					 * anything here
699e8a38776Smacallan 					 */
7007003c5c6Smacallan 					if (acmp == cmp && start == -1)
701e8a38776Smacallan 						goto next;
702e8a38776Smacallan 					/*
703e8a38776Smacallan 					 * see if we can optimize things a
704e8a38776Smacallan 					 * little bit by drawing stretches of
705e8a38776Smacallan 					 * blanks using erasecols
706e8a38776Smacallan 					 */
707e8a38776Smacallan 
708e8a38776Smacallan 					if (start == -1) {
709e8a38776Smacallan 						start = j;
710e8a38776Smacallan 						last_a = acmp;
711e8a38776Smacallan 					} else if (acmp != last_a) {
712e8a38776Smacallan 						/*
713e8a38776Smacallan 						 * different attr, need to
7145d271612Smacallan 						 * flush & restart
715e8a38776Smacallan 						 */
716a87987a6Sriastradh 						vdp->erasecols(ri, i, start,
717e8a38776Smacallan 						    j - start, last_a);
7185d271612Smacallan 						start = j;
7195d271612Smacallan 						last_a = acmp;
720e8a38776Smacallan 					}
721e8a38776Smacallan 				} else {
722e8a38776Smacallan 					if (start != -1) {
723a87987a6Sriastradh 						vdp->erasecols(ri, i, start,
724e8a38776Smacallan 						    j - start, last_a);
725e8a38776Smacallan 						start = -1;
726e8a38776Smacallan 					}
727e8a38776Smacallan 
728c5fb1a74Smacallan 					scr->putchar(ri, i, j, c, a);
729e8a38776Smacallan 				}
730e8a38776Smacallan next:
7316eb32961Smacallan #ifdef VCONS_DRAW_INTR
732a87987a6Sriastradh 				vdp->chars[boffset] = charptr[offset];
733a87987a6Sriastradh 				vdp->attrs[boffset] = attrptr[offset];
7346eb32961Smacallan #endif
73556953335Smacallan 				offset++;
7366eb32961Smacallan 				boffset++;
73756953335Smacallan 			}
738100a3398Sandvar 			/* end of the line - draw all deferred blanks, if any */
739e8a38776Smacallan 			if (start != -1) {
740a87987a6Sriastradh 				vdp->erasecols(ri, i, start, j - start, last_a);
741e8a38776Smacallan 			}
74256953335Smacallan 		}
74356953335Smacallan 		ri->ri_flg &= ~RI_CURSOR;
744a87987a6Sriastradh 		scr->scr_vd->private->cursor(ri, 1, ri->ri_crow, ri->ri_ccol);
7456eb32961Smacallan #ifdef VCONS_DRAW_INTR
746a87987a6Sriastradh 		vdp->cursor_offset = ri->ri_crow * ri->ri_cols + ri->ri_ccol;
7476eb32961Smacallan #endif
74856953335Smacallan 	}
74956953335Smacallan 	vcons_unlock(scr);
75056953335Smacallan }
75156953335Smacallan 
7526eb32961Smacallan void
7536eb32961Smacallan vcons_update_screen(struct vcons_screen *scr)
7546eb32961Smacallan {
755a87987a6Sriastradh #ifdef VCONS_DRAW_INTR
756452ccd35Smacallan 	uint32_t *charptr = scr->scr_chars;
7576eb32961Smacallan 	long *attrptr = scr->scr_attrs;
7586eb32961Smacallan 	struct rasops_info *ri = &scr->scr_ri;
7596eb32961Smacallan 	struct vcons_data *vd = scr->scr_vd;
760a87987a6Sriastradh 	struct vcons_data_private *vdp = vd->private;
7616eb32961Smacallan 	int i, j, offset, boffset = 0;
7626eb32961Smacallan 
7636eb32961Smacallan 	vcons_lock(scr);
7646eb32961Smacallan 	if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) {
7656eb32961Smacallan 
7666eb32961Smacallan 		/* redraw the screen */
7676eb32961Smacallan #ifdef WSDISPLAY_SCROLLSUPPORT
7686eb32961Smacallan 		offset = scr->scr_current_offset;
7696eb32961Smacallan #else
7706eb32961Smacallan 		offset = 0;
7716eb32961Smacallan #endif
7726eb32961Smacallan 		/*
7736eb32961Smacallan 		 * we mark the character cell occupied by the cursor as dirty
7746eb32961Smacallan 		 * so we don't have to deal with it
7756eb32961Smacallan 		 * notice that this isn't necessarily the position where rasops
7766eb32961Smacallan 		 * thinks it is, just where we drew it the last time
7776eb32961Smacallan 		 */
778a87987a6Sriastradh 		if (vdp->cursor_offset >= 0)
779a87987a6Sriastradh 			vdp->attrs[vdp->cursor_offset] = 0xffffffff;
7806eb32961Smacallan 
7816eb32961Smacallan 		for (i = 0; i < ri->ri_rows; i++) {
7826eb32961Smacallan 			for (j = 0; j < ri->ri_cols; j++) {
7836eb32961Smacallan 				/*
7846eb32961Smacallan 				 * no need to use the wrapper function - we
7856eb32961Smacallan 				 * don't change any characters or attributes
7866eb32961Smacallan 				 * and we already made sure the screen we're
7876eb32961Smacallan 				 * working on is visible
7886eb32961Smacallan 				 */
789a87987a6Sriastradh 				if ((vdp->chars[boffset] != charptr[offset]) ||
790a87987a6Sriastradh 				    (vdp->attrs[boffset] != attrptr[offset])) {
791c5fb1a74Smacallan 					scr->putchar(ri, i, j,
7926eb32961Smacallan 				 	   charptr[offset], attrptr[offset]);
793a87987a6Sriastradh 					vdp->chars[boffset] = charptr[offset];
794a87987a6Sriastradh 					vdp->attrs[boffset] = attrptr[offset];
7956eb32961Smacallan 				}
7966eb32961Smacallan 				offset++;
7976eb32961Smacallan 				boffset++;
7986eb32961Smacallan 			}
7996eb32961Smacallan 		}
8006eb32961Smacallan 		ri->ri_flg &= ~RI_CURSOR;
801a87987a6Sriastradh 		scr->scr_vd->private->cursor(ri, 1, ri->ri_crow, ri->ri_ccol);
802a87987a6Sriastradh 		vdp->cursor_offset = ri->ri_crow * ri->ri_cols + ri->ri_ccol;
8036eb32961Smacallan 	}
8046eb32961Smacallan 	vcons_unlock(scr);
805a87987a6Sriastradh #else  /* !VCONS_DRAW_INTR */
806a87987a6Sriastradh 	vcons_redraw_screen(scr);
8076eb32961Smacallan #endif
808a87987a6Sriastradh }
8096eb32961Smacallan 
81056953335Smacallan static int
81153524e44Schristos vcons_ioctl(void *v, void *vs, u_long cmd, void *data, int flag,
812aec18036Sjmmv 	struct lwp *l)
813aec18036Sjmmv {
814aec18036Sjmmv 	struct vcons_data *vd = v;
815a87987a6Sriastradh 	struct vcons_data_private *vdp = vd->private;
816452ccd35Smacallan 	int error = 0;
817452ccd35Smacallan 
818aec18036Sjmmv 
819aec18036Sjmmv 	switch (cmd) {
820aec18036Sjmmv 	case WSDISPLAYIO_GETWSCHAR:
821aec18036Sjmmv 		error = vcons_getwschar((struct vcons_screen *)vs,
822aec18036Sjmmv 			(struct wsdisplay_char *)data);
823aec18036Sjmmv 		break;
824aec18036Sjmmv 
825aec18036Sjmmv 	case WSDISPLAYIO_PUTWSCHAR:
826aec18036Sjmmv 		error = vcons_putwschar((struct vcons_screen *)vs,
827aec18036Sjmmv 			(struct wsdisplay_char *)data);
828aec18036Sjmmv 		break;
829aec18036Sjmmv 
830452ccd35Smacallan 	case WSDISPLAYIO_SET_POLLING: {
831452ccd35Smacallan 		int poll = *(int *)data;
832452ccd35Smacallan 
833452ccd35Smacallan 		/* first call the driver's ioctl handler */
834a87987a6Sriastradh 		if (vdp->ioctl != NULL)
835a87987a6Sriastradh 			error = (*vdp->ioctl)(v, vs, cmd, data, flag, l);
836452ccd35Smacallan 		if (poll) {
837452ccd35Smacallan 			vcons_enable_polling(vd);
838a87987a6Sriastradh 			vcons_hard_switch(LIST_FIRST(&vdp->screens));
839452ccd35Smacallan 		} else
840452ccd35Smacallan 			vcons_disable_polling(vd);
841452ccd35Smacallan 		}
842452ccd35Smacallan 		break;
843452ccd35Smacallan 
844*fd6a8bdeSmlelstv 	case WSDISPLAYIO_GFONT: {
845*fd6a8bdeSmlelstv 		struct wsdisplay_getfont *gf = data;
846*fd6a8bdeSmlelstv 		size_t actual;
847*fd6a8bdeSmlelstv 		struct wsdisplay_font *font;
848*fd6a8bdeSmlelstv 		const char *fontname;
849*fd6a8bdeSmlelstv 
850*fd6a8bdeSmlelstv 		font = ((struct vcons_screen *)vs)->scr_ri.ri_font;
851*fd6a8bdeSmlelstv 		fontname = font && font->name ? font->name : "";
852*fd6a8bdeSmlelstv 		error = copyoutstr(fontname, gf->gf_name, gf->gf_size, &actual);
853*fd6a8bdeSmlelstv 		if (!error)
854*fd6a8bdeSmlelstv 			gf->gf_actual = actual;
855*fd6a8bdeSmlelstv 		}
856*fd6a8bdeSmlelstv 		break;
857*fd6a8bdeSmlelstv 
858aec18036Sjmmv 	default:
859a87987a6Sriastradh 		if (vdp->ioctl != NULL)
860a87987a6Sriastradh 			error = (*vdp->ioctl)(v, vs, cmd, data, flag, l);
861aec18036Sjmmv 		else
862aec18036Sjmmv 			error = EPASSTHROUGH;
863aec18036Sjmmv 	}
864aec18036Sjmmv 
865aec18036Sjmmv 	return error;
866aec18036Sjmmv }
867aec18036Sjmmv 
868aec18036Sjmmv static int
86956953335Smacallan vcons_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
87056953335Smacallan     int *curxp, int *curyp, long *defattrp)
87156953335Smacallan {
87256953335Smacallan 	struct vcons_data *vd = v;
873a87987a6Sriastradh 	struct vcons_data_private *vdp = vd->private;
87456953335Smacallan 	struct vcons_screen *scr;
875c5fb1a74Smacallan 	struct wsscreen_descr *t = __UNCONST(type);
87656953335Smacallan 	int ret;
87756953335Smacallan 
87856953335Smacallan 	scr = malloc(sizeof(struct vcons_screen), M_DEVBUF, M_WAITOK | M_ZERO);
87956953335Smacallan 	if (scr == NULL)
88056953335Smacallan 		return ENOMEM;
88156953335Smacallan 
88256953335Smacallan 	scr->scr_flags = 0;
883e594a414Smacallan 	scr->scr_status = 0;
884e594a414Smacallan 	scr->scr_busy = 0;
885c5fb1a74Smacallan 	scr->scr_type = __UNCONST(type);
88656953335Smacallan 
88756953335Smacallan 	ret = vcons_init_screen(vd, scr, 0, defattrp);
88856953335Smacallan 	if (ret != 0) {
88956953335Smacallan 		free(scr, M_DEVBUF);
89056953335Smacallan 		return ret;
89156953335Smacallan 	}
892c5fb1a74Smacallan 	if (t->capabilities & WSSCREEN_RESIZE) {
893c5fb1a74Smacallan 		t->nrows = scr->scr_ri.ri_rows;
894c5fb1a74Smacallan 		t->ncols = scr->scr_ri.ri_cols;
895c5fb1a74Smacallan 	}
89656953335Smacallan 
89756953335Smacallan 	if (vd->active == NULL) {
89856953335Smacallan 		SCREEN_VISIBLE(scr);
89956953335Smacallan 		vd->active = scr;
900a87987a6Sriastradh 		vdp->currenttype = type;
90156953335Smacallan 	}
90256953335Smacallan 
90356953335Smacallan 	*cookiep = scr;
90456953335Smacallan 	*curxp = scr->scr_ri.ri_ccol;
90556953335Smacallan 	*curyp = scr->scr_ri.ri_crow;
90656953335Smacallan 	return 0;
90756953335Smacallan }
90856953335Smacallan 
90956953335Smacallan static void
91056953335Smacallan vcons_free_screen(void *v, void *cookie)
91156953335Smacallan {
91256953335Smacallan 	struct vcons_data *vd = v;
91356953335Smacallan 	struct vcons_screen *scr = cookie;
91456953335Smacallan 
91556953335Smacallan 	vcons_lock(scr);
91656953335Smacallan 	/* there should be no rasops activity here */
91756953335Smacallan 
91856953335Smacallan 	LIST_REMOVE(scr, next);
91956953335Smacallan 
92056953335Smacallan 	if ((scr->scr_flags & VCONS_SCREEN_IS_STATIC) == 0) {
92156953335Smacallan 		free(scr->scr_attrs, M_DEVBUF);
92256953335Smacallan 		free(scr, M_DEVBUF);
92356953335Smacallan 	} else {
92456953335Smacallan 		/*
92556953335Smacallan 		 * maybe we should just restore the old rasops_info methods
92656953335Smacallan 		 * and free the character/attribute buffer here?
92756953335Smacallan 		 */
92856953335Smacallan #ifdef VCONS_DEBUG
92956953335Smacallan 		panic("vcons_free_screen: console");
93056953335Smacallan #else
93156953335Smacallan 		printf("vcons_free_screen: console\n");
93256953335Smacallan #endif
93356953335Smacallan 	}
93456953335Smacallan 
93556953335Smacallan 	if (vd->active == scr)
93656953335Smacallan 		vd->active = NULL;
93756953335Smacallan }
93856953335Smacallan 
93956953335Smacallan static int
940168cd830Schristos vcons_show_screen(void *v, void *cookie, int waitok,
94156953335Smacallan     void (*cb)(void *, int, int), void *cb_arg)
94256953335Smacallan {
94356953335Smacallan 	struct vcons_data *vd = v;
944a87987a6Sriastradh 	struct vcons_data_private *vdp = vd->private;
94556953335Smacallan 	struct vcons_screen *scr;
94656953335Smacallan 
94756953335Smacallan 	scr = cookie;
94856953335Smacallan 	if (scr == vd->active)
94956953335Smacallan 		return 0;
95056953335Smacallan 
951a87987a6Sriastradh 	vdp->wanted = scr;
952a87987a6Sriastradh 	vdp->switch_cb = cb;
953a87987a6Sriastradh 	vdp->switch_cb_arg = cb_arg;
95456953335Smacallan 	if (cb) {
955a87987a6Sriastradh 		callout_schedule(&vdp->switch_callout, 0);
95656953335Smacallan 		return EAGAIN;
95756953335Smacallan 	}
95856953335Smacallan 
95956953335Smacallan 	vcons_do_switch(vd);
96056953335Smacallan 	return 0;
96156953335Smacallan }
96256953335Smacallan 
96356953335Smacallan /* wrappers for rasops_info methods */
96456953335Smacallan 
96556953335Smacallan static void
96656953335Smacallan vcons_copycols_buffer(void *cookie, int row, int srccol, int dstcol, int ncols)
96756953335Smacallan {
96856953335Smacallan 	struct rasops_info *ri = cookie;
96956953335Smacallan 	struct vcons_screen *scr = ri->ri_hw;
97056953335Smacallan 	int from = srccol + row * ri->ri_cols;
97156953335Smacallan 	int to = dstcol + row * ri->ri_cols;
972bca7350bSriastradh 	int offset = vcons_offset_to_zero(scr);
97375a9d6c8Smacallan 
97475a9d6c8Smacallan 	memmove(&scr->scr_attrs[offset + to], &scr->scr_attrs[offset + from],
97575a9d6c8Smacallan 	    ncols * sizeof(long));
97675a9d6c8Smacallan 	memmove(&scr->scr_chars[offset + to], &scr->scr_chars[offset + from],
977452ccd35Smacallan 	    ncols * sizeof(uint32_t));
9788485f287Sjmcneill 
979f50ac8c2Sriastradh 	vcons_dirty(scr);
98056953335Smacallan }
98156953335Smacallan 
98256953335Smacallan static void
98356953335Smacallan vcons_copycols(void *cookie, int row, int srccol, int dstcol, int ncols)
98456953335Smacallan {
98556953335Smacallan 	struct rasops_info *ri = cookie;
98656953335Smacallan 	struct vcons_screen *scr = ri->ri_hw;
98756953335Smacallan 
98856953335Smacallan 	vcons_copycols_buffer(cookie, row, srccol, dstcol, ncols);
98956953335Smacallan 
990d7b10139Sriastradh 	if (vcons_use_intr(scr))
991232459adSjmcneill 		return;
992232459adSjmcneill 
99356953335Smacallan 	vcons_lock(scr);
99423d47317Smacallan 	if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) {
9954066bef8Smlelstv #if defined(VCONS_DRAW_INTR)
99680529807Smlelstv 		vcons_update_screen(scr);
99780529807Smlelstv #else
998a87987a6Sriastradh 		scr->scr_vd->private->copycols(cookie, row, srccol, dstcol,
999a87987a6Sriastradh 		    ncols);
10004066bef8Smlelstv #endif
100156953335Smacallan 	}
100256953335Smacallan 	vcons_unlock(scr);
100356953335Smacallan }
100456953335Smacallan 
100556953335Smacallan static void
10069c10440fSmacallan vcons_copycols_noread(void *cookie, int row, int srccol, int dstcol, int ncols)
10079c10440fSmacallan {
10089c10440fSmacallan 	struct rasops_info *ri = cookie;
10099c10440fSmacallan 	struct vcons_screen *scr = ri->ri_hw;
1010c5fb1a74Smacallan #ifdef VCONS_DRAW_INTR
10116eb32961Smacallan 	struct vcons_data *vd = scr->scr_vd;
1012a87987a6Sriastradh 	struct vcons_data_private *vdp = vd->private;
1013c5fb1a74Smacallan #endif
10149c10440fSmacallan 
10154066bef8Smlelstv 	vcons_lock(scr);
10169c10440fSmacallan 	if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) {
10176eb32961Smacallan 		int pos, c, offset, ppos;
10189c10440fSmacallan 
10199c10440fSmacallan #ifdef WSDISPLAY_SCROLLSUPPORT
10209c10440fSmacallan 		offset = scr->scr_current_offset;
10219c10440fSmacallan #else
10229c10440fSmacallan 		offset = 0;
10239c10440fSmacallan #endif
10246eb32961Smacallan 		ppos = ri->ri_cols * row + dstcol;
10256eb32961Smacallan 		pos = ppos + offset;
10269c10440fSmacallan 		for (c = dstcol; c < (dstcol + ncols); c++) {
10276eb32961Smacallan #ifdef VCONS_DRAW_INTR
1028a87987a6Sriastradh 			if ((scr->scr_chars[pos] != vdp->chars[ppos]) ||
1029a87987a6Sriastradh 			    (scr->scr_attrs[pos] != vdp->attrs[ppos])) {
1030c5fb1a74Smacallan 				scr->putchar(cookie, row, c,
10319c10440fSmacallan 				   scr->scr_chars[pos], scr->scr_attrs[pos]);
1032a87987a6Sriastradh 				vdp->chars[ppos] = scr->scr_chars[pos];
1033a87987a6Sriastradh 				vdp->attrs[ppos] = scr->scr_attrs[pos];
10346eb32961Smacallan 			}
10356eb32961Smacallan #else
1036c5fb1a74Smacallan 			scr->putchar(cookie, row, c, scr->scr_chars[pos],
10376eb32961Smacallan 			    scr->scr_attrs[pos]);
10386eb32961Smacallan #endif
10399c10440fSmacallan 			pos++;
10406eb32961Smacallan 			ppos++;
10419c10440fSmacallan 		}
10421421352eSmacallan 		if (ri->ri_crow == row &&
10431421352eSmacallan 		   (ri->ri_ccol >= dstcol && ri->ri_ccol < (dstcol + ncols )))
10441421352eSmacallan 			ri->ri_flg &= ~RI_CURSOR;
10459c10440fSmacallan 	}
10464066bef8Smlelstv 	vcons_unlock(scr);
10479c10440fSmacallan }
10489c10440fSmacallan 
10499c10440fSmacallan static void
105056953335Smacallan vcons_erasecols_buffer(void *cookie, int row, int startcol, int ncols, long fillattr)
105156953335Smacallan {
105256953335Smacallan 	struct rasops_info *ri = cookie;
105356953335Smacallan 	struct vcons_screen *scr = ri->ri_hw;
105456953335Smacallan 	int start = startcol + row * ri->ri_cols;
105556953335Smacallan 	int end = start + ncols, i;
1056bca7350bSriastradh 	int offset = vcons_offset_to_zero(scr);
105775a9d6c8Smacallan 
105875a9d6c8Smacallan 	for (i = start; i < end; i++) {
105975a9d6c8Smacallan 		scr->scr_attrs[offset + i] = fillattr;
106075a9d6c8Smacallan 		scr->scr_chars[offset + i] = 0x20;
106175a9d6c8Smacallan 	}
10628485f287Sjmcneill 
1063f50ac8c2Sriastradh 	vcons_dirty(scr);
106456953335Smacallan }
106556953335Smacallan 
10666eb32961Smacallan #ifdef VCONS_DRAW_INTR
10676eb32961Smacallan static void
10686eb32961Smacallan vcons_erasecols_cached(void *cookie, int row, int startcol, int ncols, long fillattr)
10696eb32961Smacallan {
10706eb32961Smacallan 	struct rasops_info *ri = cookie;
10716eb32961Smacallan 	struct vcons_screen *scr = ri->ri_hw;
10726eb32961Smacallan 	struct vcons_data *vd = scr->scr_vd;
1073a87987a6Sriastradh 	struct vcons_data_private *vdp = vd->private;
10746eb32961Smacallan 	int i, pos = row * ri->ri_cols + startcol;
10756eb32961Smacallan 
1076a87987a6Sriastradh 	vdp->erasecols(cookie, row, startcol, ncols, fillattr);
107718538507Smlelstv 	for (i = pos; i < ncols; i++) {
1078a87987a6Sriastradh 		vdp->chars[i] = scr->scr_chars[i];
1079a87987a6Sriastradh 		vdp->attrs[i] = scr->scr_attrs[i];
108018538507Smlelstv 	}
10816eb32961Smacallan }
10826eb32961Smacallan #endif
10836eb32961Smacallan 
108456953335Smacallan static void
108556953335Smacallan vcons_erasecols(void *cookie, int row, int startcol, int ncols, long fillattr)
108656953335Smacallan {
108756953335Smacallan 	struct rasops_info *ri = cookie;
108856953335Smacallan 	struct vcons_screen *scr = ri->ri_hw;
108956953335Smacallan 
109056953335Smacallan 	vcons_erasecols_buffer(cookie, row, startcol, ncols, fillattr);
109156953335Smacallan 
1092d7b10139Sriastradh 	if (vcons_use_intr(scr))
1093232459adSjmcneill 		return;
1094232459adSjmcneill 
109556953335Smacallan 	vcons_lock(scr);
109623d47317Smacallan 	if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) {
10976eb32961Smacallan #ifdef VCONS_DRAW_INTR
10986eb32961Smacallan 		vcons_erasecols_cached(cookie, row, startcol, ncols,
109956953335Smacallan 		    fillattr);
11006eb32961Smacallan #else
1101a87987a6Sriastradh 		scr->scr_vd->private->erasecols(cookie, row, startcol, ncols,
1102a87987a6Sriastradh 		    fillattr);
11036eb32961Smacallan #endif
110456953335Smacallan 	}
110556953335Smacallan 	vcons_unlock(scr);
110656953335Smacallan }
110756953335Smacallan 
110856953335Smacallan static void
110956953335Smacallan vcons_copyrows_buffer(void *cookie, int srcrow, int dstrow, int nrows)
111056953335Smacallan {
111156953335Smacallan 	struct rasops_info *ri = cookie;
111256953335Smacallan 	struct vcons_screen *scr = ri->ri_hw;
111356953335Smacallan 	int from, to, len;
1114bca7350bSriastradh 	int offset = vcons_offset_to_zero(scr);
111575a9d6c8Smacallan 
111675a9d6c8Smacallan 	/* do we need to scroll the back buffer? */
1117bca7350bSriastradh 	if (dstrow == 0 && offset != 0) {
111875a9d6c8Smacallan 		from = ri->ri_cols * srcrow;
111975a9d6c8Smacallan 		to = ri->ri_cols * dstrow;
112075a9d6c8Smacallan 
112175a9d6c8Smacallan 		memmove(&scr->scr_attrs[to], &scr->scr_attrs[from],
1122bca7350bSriastradh 		    offset * sizeof(long));
112375a9d6c8Smacallan 		memmove(&scr->scr_chars[to], &scr->scr_chars[from],
1124bca7350bSriastradh 		    offset * sizeof(uint32_t));
112575a9d6c8Smacallan 	}
112675a9d6c8Smacallan 	from = ri->ri_cols * srcrow + offset;
112775a9d6c8Smacallan 	to = ri->ri_cols * dstrow + offset;
112875a9d6c8Smacallan 	len = ri->ri_cols * nrows;
112975a9d6c8Smacallan 
113056953335Smacallan 	memmove(&scr->scr_attrs[to], &scr->scr_attrs[from],
113156953335Smacallan 	    len * sizeof(long));
113256953335Smacallan 	memmove(&scr->scr_chars[to], &scr->scr_chars[from],
1133452ccd35Smacallan 	    len * sizeof(uint32_t));
11348485f287Sjmcneill 
1135f50ac8c2Sriastradh 	vcons_dirty(scr);
113656953335Smacallan }
113756953335Smacallan 
113856953335Smacallan static void
113956953335Smacallan vcons_copyrows(void *cookie, int srcrow, int dstrow, int nrows)
114056953335Smacallan {
114156953335Smacallan 	struct rasops_info *ri = cookie;
114256953335Smacallan 	struct vcons_screen *scr = ri->ri_hw;
114356953335Smacallan 
114456953335Smacallan 	vcons_copyrows_buffer(cookie, srcrow, dstrow, nrows);
114556953335Smacallan 
1146d7b10139Sriastradh 	if (vcons_use_intr(scr))
1147232459adSjmcneill 		return;
1148232459adSjmcneill 
114956953335Smacallan 	vcons_lock(scr);
115023d47317Smacallan 	if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) {
11514066bef8Smlelstv #if defined(VCONS_DRAW_INTR)
115280529807Smlelstv 		vcons_update_screen(scr);
115380529807Smlelstv #else
1154a87987a6Sriastradh 		scr->scr_vd->private->copyrows(cookie, srcrow, dstrow, nrows);
11554066bef8Smlelstv #endif
115656953335Smacallan 	}
115756953335Smacallan 	vcons_unlock(scr);
115856953335Smacallan }
115956953335Smacallan 
116056953335Smacallan static void
11619c10440fSmacallan vcons_copyrows_noread(void *cookie, int srcrow, int dstrow, int nrows)
11629c10440fSmacallan {
11639c10440fSmacallan 	struct rasops_info *ri = cookie;
11649c10440fSmacallan 	struct vcons_screen *scr = ri->ri_hw;
1165c5fb1a74Smacallan #ifdef VCONS_DRAW_INTR
11666eb32961Smacallan 	struct vcons_data *vd = scr->scr_vd;
1167a87987a6Sriastradh 	struct vcons_data_private *vdp = vd->private;
1168c5fb1a74Smacallan #endif
11694066bef8Smlelstv 	vcons_lock(scr);
11709c10440fSmacallan 	if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) {
11716eb32961Smacallan 		int pos, l, c, offset, ppos;
11729c10440fSmacallan 
11739c10440fSmacallan #ifdef WSDISPLAY_SCROLLSUPPORT
11749c10440fSmacallan 		offset = scr->scr_current_offset;
11759c10440fSmacallan #else
11769c10440fSmacallan 		offset = 0;
11779c10440fSmacallan #endif
11786eb32961Smacallan 		ppos = ri->ri_cols * dstrow;
11796eb32961Smacallan 		pos = ppos + offset;
11809c10440fSmacallan 		for (l = dstrow; l < (dstrow + nrows); l++) {
11819c10440fSmacallan 			for (c = 0; c < ri->ri_cols; c++) {
11826eb32961Smacallan #ifdef VCONS_DRAW_INTR
1183a87987a6Sriastradh 				if ((scr->scr_chars[pos] != vdp->chars[ppos]) ||
1184a87987a6Sriastradh 				    (scr->scr_attrs[pos] != vdp->attrs[ppos])) {
1185c5fb1a74Smacallan 					scr->putchar(cookie, l, c,
11869c10440fSmacallan 					   scr->scr_chars[pos], scr->scr_attrs[pos]);
1187a87987a6Sriastradh 					vdp->chars[ppos] = scr->scr_chars[pos];
1188a87987a6Sriastradh 					vdp->attrs[ppos] = scr->scr_attrs[pos];
11896eb32961Smacallan 				}
11906eb32961Smacallan #else
1191c5fb1a74Smacallan 				scr->putchar(cookie, l, c, scr->scr_chars[pos],
11926eb32961Smacallan 				    scr->scr_attrs[pos]);
11936eb32961Smacallan #endif
11949c10440fSmacallan 				pos++;
11956eb32961Smacallan 				ppos++;
11969c10440fSmacallan 			}
11979c10440fSmacallan 		}
11981421352eSmacallan 		if (ri->ri_crow >= dstrow && ri->ri_crow < (dstrow + nrows))
11991421352eSmacallan 			ri->ri_flg &= ~RI_CURSOR;
12009c10440fSmacallan 	}
12014066bef8Smlelstv 	vcons_unlock(scr);
12029c10440fSmacallan }
12039c10440fSmacallan 
12049c10440fSmacallan static void
120556953335Smacallan vcons_eraserows_buffer(void *cookie, int row, int nrows, long fillattr)
120656953335Smacallan {
120756953335Smacallan 	struct rasops_info *ri = cookie;
120856953335Smacallan 	struct vcons_screen *scr = ri->ri_hw;
1209bca7350bSriastradh 	int offset = vcons_offset_to_zero(scr);
121056953335Smacallan 	int start, end, i;
121156953335Smacallan 
121275a9d6c8Smacallan 	start = ri->ri_cols * row + offset;
121375a9d6c8Smacallan 	end = ri->ri_cols * (row + nrows) + offset;
121456953335Smacallan 
121556953335Smacallan 	for (i = start; i < end; i++) {
121656953335Smacallan 		scr->scr_attrs[i] = fillattr;
121756953335Smacallan 		scr->scr_chars[i] = 0x20;
121856953335Smacallan 	}
12198485f287Sjmcneill 
1220f50ac8c2Sriastradh 	vcons_dirty(scr);
122156953335Smacallan }
122256953335Smacallan 
12234066bef8Smlelstv #ifdef VCONS_DRAW_INTR
12244066bef8Smlelstv static void
12254066bef8Smlelstv vcons_eraserows_cached(void *cookie, int row, int nrows, long fillattr)
12264066bef8Smlelstv {
12274066bef8Smlelstv 	struct rasops_info *ri = cookie;
12284066bef8Smlelstv 	struct vcons_screen *scr = ri->ri_hw;
12294066bef8Smlelstv 	struct vcons_data *vd = scr->scr_vd;
1230a87987a6Sriastradh 	struct vcons_data_private *vdp = vd->private;
12314066bef8Smlelstv 	int i, pos = row * ri->ri_cols, end = (row+nrows) * ri->ri_cols;
12324066bef8Smlelstv 
12334066bef8Smlelstv 	for (i = pos; i < end; i++) {
1234a87987a6Sriastradh 		vdp->chars[i] = 0x20;
1235a87987a6Sriastradh 		vdp->attrs[i] = fillattr;
12364066bef8Smlelstv 	}
1237a87987a6Sriastradh 	vdp->eraserows(cookie, row, nrows, fillattr);
12384066bef8Smlelstv }
12394066bef8Smlelstv #endif
12404066bef8Smlelstv 
124156953335Smacallan static void
124256953335Smacallan vcons_eraserows(void *cookie, int row, int nrows, long fillattr)
124356953335Smacallan {
124456953335Smacallan 	struct rasops_info *ri = cookie;
124556953335Smacallan 	struct vcons_screen *scr = ri->ri_hw;
124656953335Smacallan 
124756953335Smacallan 	vcons_eraserows_buffer(cookie, row, nrows, fillattr);
124856953335Smacallan 
1249d7b10139Sriastradh 	if (vcons_use_intr(scr))
1250232459adSjmcneill 		return;
1251232459adSjmcneill 
125256953335Smacallan 	vcons_lock(scr);
125323d47317Smacallan 	if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) {
12544066bef8Smlelstv #ifdef VCONS_DRAW_INTR
12554066bef8Smlelstv 		vcons_eraserows_cached(cookie, row, nrows, fillattr);
12564066bef8Smlelstv #else
1257a87987a6Sriastradh 		scr->scr_vd->private->eraserows(cookie, row, nrows, fillattr);
12584066bef8Smlelstv #endif
125956953335Smacallan 	}
126056953335Smacallan 	vcons_unlock(scr);
126156953335Smacallan }
126256953335Smacallan 
12637b475855Smacallan static int
126456953335Smacallan vcons_putchar_buffer(void *cookie, int row, int col, u_int c, long attr)
126556953335Smacallan {
126656953335Smacallan 	struct rasops_info *ri = cookie;
126756953335Smacallan 	struct vcons_screen *scr = ri->ri_hw;
1268bca7350bSriastradh 	int offset = vcons_offset_to_zero(scr);
12697b475855Smacallan 	int pos, ret = 0;
127056953335Smacallan 
127175a9d6c8Smacallan 	if ((row >= 0) && (row < ri->ri_rows) && (col >= 0) &&
127275a9d6c8Smacallan 	    (col < ri->ri_cols)) {
127375a9d6c8Smacallan 		pos = col + row * ri->ri_cols;
12747b475855Smacallan 		ret = (scr->scr_attrs[pos + offset] != attr) ||
12757b475855Smacallan 		      (scr->scr_chars[pos + offset] != c);
127675a9d6c8Smacallan 		scr->scr_attrs[pos + offset] = attr;
127775a9d6c8Smacallan 		scr->scr_chars[pos + offset] = c;
127875a9d6c8Smacallan 	}
12798485f287Sjmcneill 
128007fb6665Sriastradh 	if (ret)
128107fb6665Sriastradh 		vcons_dirty(scr);
12827b475855Smacallan 	return ret;
128356953335Smacallan }
128456953335Smacallan 
12856eb32961Smacallan #ifdef VCONS_DRAW_INTR
12866eb32961Smacallan static void
12876eb32961Smacallan vcons_putchar_cached(void *cookie, int row, int col, u_int c, long attr)
12886eb32961Smacallan {
12896eb32961Smacallan 	struct rasops_info *ri = cookie;
12906eb32961Smacallan 	struct vcons_screen *scr = ri->ri_hw;
12916eb32961Smacallan 	struct vcons_data *vd = scr->scr_vd;
1292a87987a6Sriastradh 	struct vcons_data_private *vdp = vd->private;
12936eb32961Smacallan 	int pos = row * ri->ri_cols + col;
12946eb32961Smacallan 
1295a87987a6Sriastradh 	if ((vdp->chars == NULL) || (vdp->attrs == NULL)) {
1296c5fb1a74Smacallan 		scr->putchar(cookie, row, col, c, attr);
12976eb32961Smacallan 		return;
12986eb32961Smacallan 	}
1299a87987a6Sriastradh 	if ((vdp->chars[pos] != c) || (vdp->attrs[pos] != attr)) {
1300a87987a6Sriastradh 		vdp->attrs[pos] = attr;
1301a87987a6Sriastradh 		vdp->chars[pos] = c;
1302c5fb1a74Smacallan 		scr->putchar(cookie, row, col, c, attr);
13036eb32961Smacallan 	}
13046eb32961Smacallan }
13056eb32961Smacallan #endif
13066eb32961Smacallan 
130756953335Smacallan static void
130856953335Smacallan vcons_putchar(void *cookie, int row, int col, u_int c, long attr)
130956953335Smacallan {
131056953335Smacallan 	struct rasops_info *ri = cookie;
131156953335Smacallan 	struct vcons_screen *scr = ri->ri_hw;
13127b475855Smacallan 	int need_draw;
131356953335Smacallan 
13147b475855Smacallan 	need_draw = vcons_putchar_buffer(cookie, row, col, c, attr);
131556953335Smacallan 
1316d7b10139Sriastradh 	if (vcons_use_intr(scr))
1317232459adSjmcneill 		return;
1318232459adSjmcneill 
131956953335Smacallan 	vcons_lock(scr);
132023d47317Smacallan 	if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) {
13216eb32961Smacallan #ifdef VCONS_DRAW_INTR
132207fb6665Sriastradh 		if (need_draw)
132307fb6665Sriastradh 			vcons_putchar_cached(cookie, row, col, c, attr);
13246eb32961Smacallan #else
13254f1cc448Smacallan 		if (row == ri->ri_crow && col == ri->ri_ccol) {
13264f1cc448Smacallan 			ri->ri_flg &= ~RI_CURSOR;
13277b475855Smacallan 			scr->putchar(cookie, row, col, c, attr);
13287b475855Smacallan 		} else if (need_draw)
1329c5fb1a74Smacallan 			scr->putchar(cookie, row, col, c, attr);
13306eb32961Smacallan #endif
133156953335Smacallan 	}
133256953335Smacallan 	vcons_unlock(scr);
133356953335Smacallan }
133456953335Smacallan 
133556953335Smacallan static void
133656953335Smacallan vcons_cursor(void *cookie, int on, int row, int col)
133756953335Smacallan {
133856953335Smacallan 	struct rasops_info *ri = cookie;
133956953335Smacallan 	struct vcons_screen *scr = ri->ri_hw;
134056953335Smacallan 
1341d7b10139Sriastradh 	if (vcons_use_intr(scr)) {
1342232459adSjmcneill 		vcons_lock(scr);
13438485f287Sjmcneill 		if (scr->scr_ri.ri_crow != row || scr->scr_ri.ri_ccol != col) {
13448485f287Sjmcneill 			scr->scr_ri.ri_crow = row;
13458485f287Sjmcneill 			scr->scr_ri.ri_ccol = col;
1346f50ac8c2Sriastradh 			vcons_dirty(scr);
13478485f287Sjmcneill 		}
1348232459adSjmcneill 		vcons_unlock(scr);
1349232459adSjmcneill 		return;
1350232459adSjmcneill 	}
1351232459adSjmcneill 
1352232459adSjmcneill 	vcons_lock(scr);
1353232459adSjmcneill 
135423d47317Smacallan 	if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) {
1355a87987a6Sriastradh 		scr->scr_vd->private->cursor(cookie, on, row, col);
135656953335Smacallan 	} else {
135756953335Smacallan 		scr->scr_ri.ri_crow = row;
135856953335Smacallan 		scr->scr_ri.ri_ccol = col;
135956953335Smacallan 	}
136056953335Smacallan 	vcons_unlock(scr);
136156953335Smacallan }
136256953335Smacallan 
1363d701d9f4Smacallan static void
1364d701d9f4Smacallan vcons_cursor_noread(void *cookie, int on, int row, int col)
1365d701d9f4Smacallan {
1366d701d9f4Smacallan 	struct rasops_info *ri = cookie;
1367d701d9f4Smacallan 	struct vcons_screen *scr = ri->ri_hw;
13681421352eSmacallan 	int offset = 0, ofs;
1369d701d9f4Smacallan 
1370d701d9f4Smacallan #ifdef WSDISPLAY_SCROLLSUPPORT
1371d701d9f4Smacallan 	offset = scr->scr_current_offset;
1372d701d9f4Smacallan #endif
13731421352eSmacallan 	ofs = offset + ri->ri_crow * ri->ri_cols + ri->ri_ccol;
13741421352eSmacallan 	if ((ri->ri_flg & RI_CURSOR) &&
1375ddbd9be9Smacallan 	   (((scr->scr_flags & VCONS_DONT_READ) != VCONS_DONT_READ) || on)) {
1376d701d9f4Smacallan 		scr->putchar(cookie, ri->ri_crow, ri->ri_ccol,
1377d701d9f4Smacallan 		    scr->scr_chars[ofs], scr->scr_attrs[ofs]);
1378d701d9f4Smacallan 		ri->ri_flg &= ~RI_CURSOR;
1379d701d9f4Smacallan 	}
1380d701d9f4Smacallan 	ri->ri_crow = row;
1381d701d9f4Smacallan 	ri->ri_ccol = col;
1382d701d9f4Smacallan 	ofs = offset + ri->ri_crow * ri->ri_cols + ri->ri_ccol;
1383d701d9f4Smacallan 	if (on) {
1384d701d9f4Smacallan 		scr->putchar(cookie, row, col, scr->scr_chars[ofs],
1385d701d9f4Smacallan #ifdef VCONS_DEBUG_CURSOR_NOREAD
1386d701d9f4Smacallan 		/* draw a red cursor so we can tell which cursor()
1387d701d9f4Smacallan 		 * implementation is being used */
1388d701d9f4Smacallan 		    ((scr->scr_attrs[ofs] & 0xff00ffff) ^ 0x0f000000) |
1389d701d9f4Smacallan 		      0x00010000);
1390d701d9f4Smacallan #else
1391d701d9f4Smacallan 		    scr->scr_attrs[ofs] ^ 0x0f0f0000);
1392d701d9f4Smacallan #endif
1393d701d9f4Smacallan 		ri->ri_flg |= RI_CURSOR;
1394d701d9f4Smacallan 	}
1395d701d9f4Smacallan }
1396d701d9f4Smacallan 
139756953335Smacallan /* methods to read/write characters via ioctl() */
139856953335Smacallan 
139956953335Smacallan static int
1400aec18036Sjmmv vcons_putwschar(struct vcons_screen *scr, struct wsdisplay_char *wsc)
140156953335Smacallan {
140256953335Smacallan 	long attr;
1403aec18036Sjmmv 	struct rasops_info *ri;
1404c47f805aSchristos 	int error;
1405aec18036Sjmmv 
14063bf10644Sriastradh 	KASSERT(scr != NULL);
14073bf10644Sriastradh 	KASSERT(wsc != NULL);
1408aec18036Sjmmv 
140964dd0415Srumble 	ri = &scr->scr_ri;
141064dd0415Srumble 
1411f10f192fSmacallan 	/* allow col as linear index if row == 0 */
1412f10f192fSmacallan 	if (wsc->row == 0) {
1413f10f192fSmacallan 		if (wsc->col < 0 || wsc->col > (ri->ri_cols * ri->ri_rows))
1414f10f192fSmacallan 			return EINVAL;
1415f10f192fSmacallan 	    	int rem;
1416f10f192fSmacallan 	    	rem = wsc->col % ri->ri_cols;
1417f10f192fSmacallan 	    	wsc->row = wsc->col / ri->ri_cols;
1418f10f192fSmacallan 	    	DPRINTF("off %d -> %d, %d\n", wsc->col, rem, wsc->row);
1419f10f192fSmacallan 	    	wsc->col = rem;
1420f10f192fSmacallan 	} else {
1421f10f192fSmacallan 		if (__predict_false(wsc->col < 0 || wsc->col >= ri->ri_cols))
1422e62a3f2fSriastradh 			return EINVAL;
142305619021Smjf 
1424f10f192fSmacallan 		if (__predict_false(wsc->row < 0 || wsc->row >= ri->ri_rows))
1425e62a3f2fSriastradh 			return EINVAL;
1426f10f192fSmacallan 	}
142775a9d6c8Smacallan 
1428c47f805aSchristos 	error = ri->ri_ops.allocattr(ri, wsc->foreground,
1429c47f805aSchristos 	    wsc->background, wsc->flags, &attr);
1430c47f805aSchristos 	if (error)
1431c47f805aSchristos 		return error;
143256953335Smacallan 	vcons_putchar(ri, wsc->row, wsc->col, wsc->letter, attr);
1433755399abSriastradh 	DPRINTF("vcons_putwschar(%d, %d, %x, %lx\n", wsc->row, wsc->col,
143475a9d6c8Smacallan 	    wsc->letter, attr);
143556953335Smacallan 	return 0;
143656953335Smacallan }
143756953335Smacallan 
143856953335Smacallan static int
1439aec18036Sjmmv vcons_getwschar(struct vcons_screen *scr, struct wsdisplay_char *wsc)
144056953335Smacallan {
1441aec18036Sjmmv 	int offset;
144256953335Smacallan 	long attr;
1443aec18036Sjmmv 	struct rasops_info *ri;
144427f97b36Smlelstv 	int fg, bg, ul;
144556953335Smacallan 
14463bf10644Sriastradh 	KASSERT(scr != NULL);
14473bf10644Sriastradh 	KASSERT(wsc != NULL);
1448aec18036Sjmmv 
1449aec18036Sjmmv 	ri = &scr->scr_ri;
145075a9d6c8Smacallan 
1451f10f192fSmacallan 	/* allow col as linear index if row == 0 */
1452f10f192fSmacallan 	if (wsc->row == 0) {
1453f10f192fSmacallan 		if (wsc->col < 0 || wsc->col > (ri->ri_cols * ri->ri_rows))
1454f10f192fSmacallan 			return EINVAL;
1455f10f192fSmacallan 	    	int rem;
1456f10f192fSmacallan 	    	rem = wsc->col % ri->ri_cols;
1457f10f192fSmacallan 	    	wsc->row = wsc->col / ri->ri_cols;
1458f10f192fSmacallan 	    	DPRINTF("off %d -> %d, %d\n", wsc->col, rem, wsc->row);
1459f10f192fSmacallan 	    	wsc->col = rem;
1460f10f192fSmacallan 	} else {
1461f10f192fSmacallan 		if (__predict_false(wsc->col < 0 || wsc->col >= ri->ri_cols))
1462e62a3f2fSriastradh 			return EINVAL;
1463f10f192fSmacallan 
1464f10f192fSmacallan 		if (__predict_false(wsc->row < 0 || wsc->row >= ri->ri_rows))
1465e62a3f2fSriastradh 			return EINVAL;
1466f10f192fSmacallan 	}
146775a9d6c8Smacallan 
1468aec18036Sjmmv 	offset = ri->ri_cols * wsc->row + wsc->col;
1469bca7350bSriastradh 	offset += vcons_offset_to_zero(scr);
147056953335Smacallan 	wsc->letter = scr->scr_chars[offset];
147156953335Smacallan 	attr = scr->scr_attrs[offset];
147256953335Smacallan 
1473755399abSriastradh 	DPRINTF("vcons_getwschar: %d, %d, %x, %lx\n", wsc->row,
147427f97b36Smlelstv 	    wsc->col, wsc->letter, attr);
147527f97b36Smlelstv 
147656953335Smacallan 	/*
147756953335Smacallan 	 * this is ugly. We need to break up an attribute into colours and
147856953335Smacallan 	 * flags but there's no rasops method to do that so we must rely on
147956953335Smacallan 	 * the 'canonical' encoding.
148056953335Smacallan 	 */
148127f97b36Smlelstv 
148227f97b36Smlelstv 	/* only fetches underline attribute */
148327f97b36Smlelstv 	/* rasops_unpack_attr(attr, &fg, &bg, &ul); */
148427f97b36Smlelstv 	fg = (attr >> 24) & 0xf;
148527f97b36Smlelstv 	bg = (attr >> 16) & 0xf;
148627f97b36Smlelstv 	ul = (attr & 1);
148727f97b36Smlelstv 
148827f97b36Smlelstv 	wsc->foreground = fg;
148927f97b36Smlelstv 	wsc->background = bg;
149027f97b36Smlelstv 
149127f97b36Smlelstv 	/* clear trashed bits and restore underline flag */
149227f97b36Smlelstv 	attr &= ~(WSATTR_HILIT | WSATTR_BLINK | WSATTR_UNDERLINE);
149327f97b36Smlelstv 	if (ul)
149427f97b36Smlelstv 		attr |= WSATTR_UNDERLINE;
149527f97b36Smlelstv 
149627f97b36Smlelstv 	/* restore highlight boost */
149727f97b36Smlelstv 	if (attr & WSATTR_HILIT)
149827f97b36Smlelstv 		if (wsc->foreground >= 8)
149927f97b36Smlelstv 			wsc->foreground -= 8;
150027f97b36Smlelstv 
150127f97b36Smlelstv 	/* we always use colors, even when not stored */
150227f97b36Smlelstv 	attr |= WSATTR_WSCOLORS;
150356953335Smacallan 	return 0;
150456953335Smacallan }
150575a9d6c8Smacallan 
1506a87987a6Sriastradh int
1507a87987a6Sriastradh vcons_offset_to_zero(const struct vcons_screen *scr)
1508a87987a6Sriastradh {
1509a87987a6Sriastradh #ifdef WSDISPLAY_SCROLLSUPPORT
1510a87987a6Sriastradh 	return scr->scr_offset_to_zero;
1511a87987a6Sriastradh #else
1512a87987a6Sriastradh 	return 0;
1513a87987a6Sriastradh #endif
1514a87987a6Sriastradh }
1515a87987a6Sriastradh 
151675a9d6c8Smacallan #ifdef WSDISPLAY_SCROLLSUPPORT
151775a9d6c8Smacallan 
151875a9d6c8Smacallan static void
151975a9d6c8Smacallan vcons_scroll(void *cookie, void *vs, int where)
152075a9d6c8Smacallan {
152175a9d6c8Smacallan 	struct vcons_screen *scr = vs;
152275a9d6c8Smacallan 
152375a9d6c8Smacallan 	if (where == 0) {
152475a9d6c8Smacallan 		scr->scr_line_wanted = 0;
152575a9d6c8Smacallan 	} else {
152675a9d6c8Smacallan 		scr->scr_line_wanted = scr->scr_line_wanted - where;
152775a9d6c8Smacallan 		if (scr->scr_line_wanted < 0)
152875a9d6c8Smacallan 			scr->scr_line_wanted = 0;
152975a9d6c8Smacallan 		if (scr->scr_line_wanted > scr->scr_lines_in_buffer)
153075a9d6c8Smacallan 			scr->scr_line_wanted = scr->scr_lines_in_buffer;
153175a9d6c8Smacallan 	}
153275a9d6c8Smacallan 
153375a9d6c8Smacallan 	if (scr->scr_line_wanted != scr->scr_current_line) {
153475a9d6c8Smacallan 
153575a9d6c8Smacallan 		vcons_do_scroll(scr);
153675a9d6c8Smacallan 	}
153775a9d6c8Smacallan }
153875a9d6c8Smacallan 
153975a9d6c8Smacallan static void
154075a9d6c8Smacallan vcons_do_scroll(struct vcons_screen *scr)
154175a9d6c8Smacallan {
154275a9d6c8Smacallan 	int dist, from, to, num;
154375a9d6c8Smacallan 	int r_offset, r_start;
154475a9d6c8Smacallan 	int i, j;
154575a9d6c8Smacallan 
154675a9d6c8Smacallan 	if (scr->scr_line_wanted == scr->scr_current_line)
154775a9d6c8Smacallan 		return;
154875a9d6c8Smacallan 	dist = scr->scr_line_wanted - scr->scr_current_line;
154975a9d6c8Smacallan 	scr->scr_current_line = scr->scr_line_wanted;
155075a9d6c8Smacallan 	scr->scr_current_offset = scr->scr_ri.ri_cols *
155175a9d6c8Smacallan 	    (scr->scr_lines_in_buffer - scr->scr_current_line);
155275a9d6c8Smacallan 	if (abs(dist) >= scr->scr_ri.ri_rows) {
155375a9d6c8Smacallan 		vcons_redraw_screen(scr);
155475a9d6c8Smacallan 		return;
155575a9d6c8Smacallan 	}
155675a9d6c8Smacallan 	/* scroll and redraw only what we really have to */
155775a9d6c8Smacallan 	if (dist > 0) {
155875a9d6c8Smacallan 		/* we scroll down */
155975a9d6c8Smacallan 		from = 0;
156075a9d6c8Smacallan 		to = dist;
156175a9d6c8Smacallan 		num = scr->scr_ri.ri_rows - dist;
156275a9d6c8Smacallan 		/* now the redraw parameters */
156375a9d6c8Smacallan 		r_offset = scr->scr_current_offset;
156475a9d6c8Smacallan 		r_start = 0;
156575a9d6c8Smacallan 	} else {
156675a9d6c8Smacallan 		/* scrolling up */
156775a9d6c8Smacallan 		to = 0;
156875a9d6c8Smacallan 		from = -dist;
156975a9d6c8Smacallan 		num = scr->scr_ri.ri_rows + dist;
157075a9d6c8Smacallan 		r_offset = scr->scr_current_offset + num * scr->scr_ri.ri_cols;
157175a9d6c8Smacallan 		r_start = num;
157275a9d6c8Smacallan 	}
1573a87987a6Sriastradh 	scr->scr_vd->private->copyrows(scr, from, to, num);
157475a9d6c8Smacallan 	for (i = 0; i < abs(dist); i++) {
157575a9d6c8Smacallan 		for (j = 0; j < scr->scr_ri.ri_cols; j++) {
15766eb32961Smacallan #ifdef VCONS_DRAW_INTR
15776eb32961Smacallan 			vcons_putchar_cached(scr, i + r_start, j,
15786eb32961Smacallan 			    scr->scr_chars[r_offset],
15796eb32961Smacallan 			    scr->scr_attrs[r_offset]);
15806eb32961Smacallan #else
1581c5fb1a74Smacallan 			scr->putchar(scr, i + r_start, j,
158275a9d6c8Smacallan 			    scr->scr_chars[r_offset],
158375a9d6c8Smacallan 			    scr->scr_attrs[r_offset]);
15846eb32961Smacallan #endif
158575a9d6c8Smacallan 			r_offset++;
158675a9d6c8Smacallan 		}
158775a9d6c8Smacallan 	}
158875a9d6c8Smacallan 
158975a9d6c8Smacallan 	if (scr->scr_line_wanted == 0) {
159075a9d6c8Smacallan 		/* this was a reset - need to draw the cursor */
159175a9d6c8Smacallan 		scr->scr_ri.ri_flg &= ~RI_CURSOR;
1592a87987a6Sriastradh 		scr->scr_vd->private->cursor(scr, 1, scr->scr_ri.ri_crow,
159375a9d6c8Smacallan 		    scr->scr_ri.ri_ccol);
159475a9d6c8Smacallan 	}
159575a9d6c8Smacallan }
159675a9d6c8Smacallan 
159775a9d6c8Smacallan #endif /* WSDISPLAY_SCROLLSUPPORT */
159875a9d6c8Smacallan 
15998485f287Sjmcneill #ifdef VCONS_DRAW_INTR
16008485f287Sjmcneill static void
16018485f287Sjmcneill vcons_intr(void *cookie)
16028485f287Sjmcneill {
16038485f287Sjmcneill 	struct vcons_data *vd = cookie;
1604a87987a6Sriastradh 	struct vcons_data_private *vdp = vd->private;
16058485f287Sjmcneill 
1606a87987a6Sriastradh 	softint_schedule(vdp->intr_softint);
16078485f287Sjmcneill }
16088485f287Sjmcneill 
16098485f287Sjmcneill static void
16103f11f2aaSjmcneill vcons_softintr(void *cookie)
16118485f287Sjmcneill {
16128485f287Sjmcneill 	struct vcons_data *vd = cookie;
1613a87987a6Sriastradh 	struct vcons_data_private *vdp = vd->private;
16148485f287Sjmcneill 	struct vcons_screen *scr = vd->active;
16153f11f2aaSjmcneill 	unsigned int dirty;
16168485f287Sjmcneill 
1617a87987a6Sriastradh 	if (scr && vdp->use_intr) {
16183f11f2aaSjmcneill 		if (!SCREEN_IS_BUSY(scr)) {
16193f11f2aaSjmcneill 			dirty = atomic_swap_uint(&scr->scr_dirty, 0);
1620830aae3fSriastradh 			membar_acquire();
1621a87987a6Sriastradh 			if (vdp->use_intr == 2) {
16224066bef8Smlelstv 				if ((scr->scr_flags & VCONS_NO_REDRAW) == 0) {
1623a87987a6Sriastradh 					vdp->use_intr = 1;
16244066bef8Smlelstv 					vcons_redraw_screen(scr);
16254066bef8Smlelstv 				}
16264066bef8Smlelstv 			} else if (dirty > 0) {
16278485f287Sjmcneill 				if ((scr->scr_flags & VCONS_NO_REDRAW) == 0)
16286eb32961Smacallan 					vcons_update_screen(scr);
16293f11f2aaSjmcneill 			}
16308485f287Sjmcneill 		}
16318485f287Sjmcneill 	}
16328485f287Sjmcneill 
1633a87987a6Sriastradh 	callout_schedule(&vdp->intr, mstohz(33));
16348485f287Sjmcneill }
1635232459adSjmcneill 
16361b26a1b9Sjmcneill static void
16371b26a1b9Sjmcneill vcons_init_thread(void *cookie)
1638232459adSjmcneill {
16391b26a1b9Sjmcneill 	struct vcons_data *vd = (struct vcons_data *)cookie;
1640a87987a6Sriastradh 	struct vcons_data_private *vdp = vd->private;
16419820da10Smsaitoh 
1642a87987a6Sriastradh 	vdp->use_intr = 2;
1643a87987a6Sriastradh 	callout_schedule(&vdp->intr, mstohz(33));
16441b26a1b9Sjmcneill 	kthread_exit(0);
1645232459adSjmcneill }
16468485f287Sjmcneill #endif /* VCONS_DRAW_INTR */
1647f24dfbb1Sjmcneill 
1648f24dfbb1Sjmcneill void
1649f24dfbb1Sjmcneill vcons_enable_polling(struct vcons_data *vd)
1650f24dfbb1Sjmcneill {
1651f24dfbb1Sjmcneill 	struct vcons_screen *scr = vd->active;
1652f24dfbb1Sjmcneill 
1653f24dfbb1Sjmcneill #ifdef VCONS_DRAW_INTR
1654c8e5dc73Smartin 	struct vcons_data_private *vdp = vd->private;
1655c8e5dc73Smartin 
1656a87987a6Sriastradh 	vdp->use_intr = 0;
1657f24dfbb1Sjmcneill #endif
1658f24dfbb1Sjmcneill 
1659f24dfbb1Sjmcneill 	if (scr && !SCREEN_IS_BUSY(scr)) {
1660f24dfbb1Sjmcneill 		if ((scr->scr_flags & VCONS_NO_REDRAW) == 0)
1661f24dfbb1Sjmcneill 			vcons_redraw_screen(scr);
1662f24dfbb1Sjmcneill 	}
1663f24dfbb1Sjmcneill }
1664f24dfbb1Sjmcneill 
1665f24dfbb1Sjmcneill void
1666f24dfbb1Sjmcneill vcons_disable_polling(struct vcons_data *vd)
1667f24dfbb1Sjmcneill {
1668f24dfbb1Sjmcneill #ifdef VCONS_DRAW_INTR
1669a87987a6Sriastradh 	struct vcons_data_private *vdp = vd->private;
1670f24dfbb1Sjmcneill 	struct vcons_screen *scr = vd->active;
1671f24dfbb1Sjmcneill 
1672a87987a6Sriastradh 	if (!vdp->intr_valid)
1673f24dfbb1Sjmcneill 		return;
1674f24dfbb1Sjmcneill 
1675a87987a6Sriastradh 	vdp->use_intr = 2;
1676f24dfbb1Sjmcneill 	if (scr)
1677f50ac8c2Sriastradh 		vcons_dirty(scr);
1678f24dfbb1Sjmcneill #endif
1679f24dfbb1Sjmcneill }
1680a1001814Sjmcneill 
1681a1001814Sjmcneill void
1682a1001814Sjmcneill vcons_hard_switch(struct vcons_screen *scr)
1683a1001814Sjmcneill {
1684a1001814Sjmcneill 	struct vcons_data *vd = scr->scr_vd;
1685a87987a6Sriastradh 	struct vcons_data_private *vdp = vd->private;
1686a1001814Sjmcneill 	struct vcons_screen *oldscr = vd->active;
1687a1001814Sjmcneill 
1688a1001814Sjmcneill 	if (oldscr) {
1689a1001814Sjmcneill 		SCREEN_INVISIBLE(oldscr);
1690a1001814Sjmcneill 		oldscr->scr_ri.ri_flg &= ~RI_CURSOR;
1691a1001814Sjmcneill 	}
1692a1001814Sjmcneill 	SCREEN_VISIBLE(scr);
1693a1001814Sjmcneill 	vd->active = scr;
1694a87987a6Sriastradh 	vdp->wanted = NULL;
1695a1001814Sjmcneill 
1696a1001814Sjmcneill 	if (vd->show_screen_cb != NULL)
16979dac6880Smacallan 		vd->show_screen_cb(scr, vd->show_screen_cookie);
1698a1001814Sjmcneill }
16996eb32961Smacallan 
17006eb32961Smacallan #ifdef VCONS_DRAW_INTR
1701a87987a6Sriastradh static void
17026eb32961Smacallan vcons_invalidate_cache(struct vcons_data *vd)
17036eb32961Smacallan {
1704a87987a6Sriastradh 	struct vcons_data_private *vdp = vd->private;
17056eb32961Smacallan 	int i;
17066eb32961Smacallan 
1707a87987a6Sriastradh 	for (i = 0; i < vdp->cells; i++) {
1708a87987a6Sriastradh 		vdp->chars[i] = -1;
1709a87987a6Sriastradh 		vdp->attrs[i] = -1;
17106eb32961Smacallan 	}
17116eb32961Smacallan }
17126eb32961Smacallan #endif
1713