xref: /netbsd-src/sys/dev/wscons/wsdisplay_vcons.c (revision 6d322f2f4598f0d8a138f10ea648ec4fabe41f8b)
1 /*	$NetBSD: wsdisplay_vcons.c,v 1.29 2013/09/15 16:12:00 martin Exp $ */
2 
3 /*-
4  * Copyright (c) 2005, 2006 Michael Lorenz
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: wsdisplay_vcons.c,v 1.29 2013/09/15 16:12:00 martin Exp $");
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/kernel.h>
35 #include <sys/buf.h>
36 #include <sys/device.h>
37 #include <sys/ioctl.h>
38 #include <sys/malloc.h>
39 #include <sys/mman.h>
40 #include <sys/tty.h>
41 #include <sys/conf.h>
42 #include <sys/proc.h>
43 #include <sys/kthread.h>
44 #include <sys/tprintf.h>
45 #include <sys/atomic.h>
46 
47 #include <dev/wscons/wsdisplayvar.h>
48 #include <dev/wscons/wsconsio.h>
49 #include <dev/wsfont/wsfont.h>
50 #include <dev/rasops/rasops.h>
51 
52 #include <dev/wscons/wsdisplay_vconsvar.h>
53 
54 #include "opt_wsemul.h"
55 #include "opt_wsdisplay_compat.h"
56 #include "opt_vcons.h"
57 
58 static void vcons_dummy_init_screen(void *, struct vcons_screen *, int,
59 	    long *);
60 
61 static int  vcons_ioctl(void *, void *, u_long, void *, int, struct lwp *);
62 static int  vcons_alloc_screen(void *, const struct wsscreen_descr *, void **,
63 	    int *, int *, long *);
64 static void vcons_free_screen(void *, void *);
65 static int  vcons_show_screen(void *, void *, int, void (*)(void *, int, int),
66 	    void *);
67 
68 #ifdef WSDISPLAY_SCROLLSUPPORT
69 static void vcons_scroll(void *, void *, int);
70 static void vcons_do_scroll(struct vcons_screen *);
71 #endif
72 
73 static void vcons_do_switch(void *);
74 
75 /* methods that work only on text buffers */
76 static void vcons_copycols_buffer(void *, int, int, int, int);
77 static void vcons_erasecols_buffer(void *, int, int, int, long);
78 static void vcons_copyrows_buffer(void *, int, int, int);
79 static void vcons_eraserows_buffer(void *, int, int, long);
80 static void vcons_putchar_buffer(void *, int, int, u_int, long);
81 
82 /*
83  * actual wrapper methods which call both the _buffer ones above and the
84  * driver supplied ones to do the drawing
85  */
86 static void vcons_copycols(void *, int, int, int, int);
87 static void vcons_erasecols(void *, int, int, int, long);
88 static void vcons_copyrows(void *, int, int, int);
89 static void vcons_eraserows(void *, int, int, long);
90 static void vcons_putchar(void *, int, int, u_int, long);
91 #ifdef VCONS_DRAW_INTR
92 static void vcons_putchar_cached(void *, int, int, u_int, long);
93 #endif
94 static void vcons_cursor(void *, int, int, int);
95 
96 /*
97  * methods that avoid framebuffer reads
98  */
99 static void vcons_copycols_noread(void *, int, int, int, int);
100 static void vcons_copyrows_noread(void *, int, int, int);
101 
102 
103 /* support for reading/writing text buffers. For wsmoused */
104 static int  vcons_putwschar(struct vcons_screen *, struct wsdisplay_char *);
105 static int  vcons_getwschar(struct vcons_screen *, struct wsdisplay_char *);
106 
107 static void vcons_lock(struct vcons_screen *);
108 static void vcons_unlock(struct vcons_screen *);
109 
110 #ifdef VCONS_DRAW_INTR
111 static void vcons_intr(void *);
112 static void vcons_softintr(void *);
113 static void vcons_intr_enable(device_t);
114 #endif
115 
116 int
117 vcons_init(struct vcons_data *vd, void *cookie, struct wsscreen_descr *def,
118     struct wsdisplay_accessops *ao)
119 {
120 
121 	/* zero out everything so we can rely on untouched fields being 0 */
122 	memset(vd, 0, sizeof(struct vcons_data));
123 
124 	vd->cookie = cookie;
125 
126 	vd->init_screen = vcons_dummy_init_screen;
127 	vd->show_screen_cb = NULL;
128 
129 	/* keep a copy of the accessops that we replace below with our
130 	 * own wrappers */
131 	vd->ioctl = ao->ioctl;
132 
133 	/* configure the accessops */
134 	ao->ioctl = vcons_ioctl;
135 	ao->alloc_screen = vcons_alloc_screen;
136 	ao->free_screen = vcons_free_screen;
137 	ao->show_screen = vcons_show_screen;
138 #ifdef WSDISPLAY_SCROLLSUPPORT
139 	ao->scroll = vcons_scroll;
140 #endif
141 
142 	LIST_INIT(&vd->screens);
143 	vd->active = NULL;
144 	vd->wanted = NULL;
145 	vd->currenttype = def;
146 	callout_init(&vd->switch_callout, 0);
147 	callout_setfunc(&vd->switch_callout, vcons_do_switch, vd);
148 #ifdef VCONS_DRAW_INTR
149 	vd->cells = 0;
150 	vd->attrs = NULL;
151 	vd->chars = NULL;
152 	vd->cursor_offset = -1;
153 #endif
154 
155 	/*
156 	 * a lock to serialize access to the framebuffer.
157 	 * when switching screens we need to make sure there's no rasops
158 	 * operation in progress
159 	 */
160 #ifdef DIAGNOSTIC
161 	vd->switch_poll_count = 0;
162 #endif
163 #ifdef VCONS_DRAW_INTR
164 	vd->intr_softint = softint_establish(SOFTINT_SERIAL,
165 	    vcons_softintr, vd);
166 	callout_init(&vd->intr, 0);
167 	callout_setfunc(&vd->intr, vcons_intr, vd);
168 	vd->intr_valid = 1;
169 
170 	/* XXX assume that the 'dev' arg is never dereferenced */
171 	config_interrupts((device_t)vd, vcons_intr_enable);
172 #endif
173 	return 0;
174 }
175 
176 static void
177 vcons_lock(struct vcons_screen *scr)
178 {
179 #ifdef VCONS_PARANOIA
180 	int s;
181 
182 	s = splhigh();
183 #endif
184 	SCREEN_BUSY(scr);
185 #ifdef VCONS_PARANOIA
186 	splx(s);
187 #endif
188 }
189 
190 static void
191 vcons_unlock(struct vcons_screen *scr)
192 {
193 #ifdef VCONS_PARANOIA
194 	int s;
195 
196 	s = splhigh();
197 #endif
198 	SCREEN_IDLE(scr);
199 #ifdef VCONS_PARANOIA
200 	splx(s);
201 #endif
202 }
203 
204 static void
205 vcons_dummy_init_screen(void *cookie,
206     struct vcons_screen *scr, int exists,
207     long *defattr)
208 {
209 
210 	/*
211 	 * default init_screen() method.
212 	 * Needs to be overwritten so we bitch and whine in case anyone ends
213 	 * up in here.
214 	 */
215 	printf("vcons_init_screen: dummy function called. Your driver is "
216 	       "supposed to supply a replacement for proper operation\n");
217 }
218 
219 int
220 vcons_init_screen(struct vcons_data *vd, struct vcons_screen *scr,
221     int existing, long *defattr)
222 {
223 	struct rasops_info *ri = &scr->scr_ri;
224 	int cnt, i;
225 #ifdef VCONS_DRAW_INTR
226 	int size;
227 #endif
228 
229 	scr->scr_cookie = vd->cookie;
230 	scr->scr_vd = scr->scr_origvd = vd;
231 	scr->scr_busy = 0;
232 
233 	/*
234 	 * call the driver-supplied init_screen function which is expected
235 	 * to set up rasops_info, override cursor() and probably others
236 	 */
237 	vd->init_screen(vd->cookie, scr, existing, defattr);
238 
239 	/*
240 	 * save the non virtual console aware rasops and replace them with
241 	 * our wrappers
242 	 */
243 	vd->eraserows = ri->ri_ops.eraserows;
244 	vd->erasecols = ri->ri_ops.erasecols;
245 	vd->putchar   = ri->ri_ops.putchar;
246 	vd->cursor    = ri->ri_ops.cursor;
247 
248 	if (scr->scr_flags & VCONS_NO_COPYCOLS) {
249 		vd->copycols  = vcons_copycols_noread;
250 	} else {
251 		vd->copycols = ri->ri_ops.copycols;
252 	}
253 
254 	if (scr->scr_flags & VCONS_NO_COPYROWS) {
255 		vd->copyrows  = vcons_copyrows_noread;
256 	} else {
257 		vd->copyrows = ri->ri_ops.copyrows;
258 	}
259 
260 	ri->ri_ops.eraserows = vcons_eraserows;
261 	ri->ri_ops.erasecols = vcons_erasecols;
262 	ri->ri_ops.putchar   = vcons_putchar;
263 	ri->ri_ops.cursor    = vcons_cursor;
264 	ri->ri_ops.copycols  = vcons_copycols;
265 	ri->ri_ops.copyrows  = vcons_copyrows;
266 
267 
268 	ri->ri_hw = scr;
269 
270 	/*
271 	 * we allocate both chars and attributes in one chunk, attributes first
272 	 * because they have the (potentially) bigger alignment
273 	 */
274 #ifdef WSDISPLAY_SCROLLSUPPORT
275 	cnt = (ri->ri_rows + WSDISPLAY_SCROLLBACK_LINES) * ri->ri_cols;
276 	scr->scr_lines_in_buffer = WSDISPLAY_SCROLLBACK_LINES;
277 	scr->scr_current_line = 0;
278 	scr->scr_line_wanted = 0;
279 	scr->scr_offset_to_zero = ri->ri_cols * WSDISPLAY_SCROLLBACK_LINES;
280 	scr->scr_current_offset = scr->scr_offset_to_zero;
281 #else
282 	cnt = ri->ri_rows * ri->ri_cols;
283 #endif
284 	scr->scr_attrs = (long *)malloc(cnt * (sizeof(long) +
285 	    sizeof(uint32_t)), M_DEVBUF, M_WAITOK);
286 	if (scr->scr_attrs == NULL)
287 		return ENOMEM;
288 
289 	scr->scr_chars = (uint32_t *)&scr->scr_attrs[cnt];
290 
291 	ri->ri_ops.allocattr(ri, WS_DEFAULT_FG, WS_DEFAULT_BG, 0, defattr);
292 	scr->scr_defattr = *defattr;
293 
294 	/*
295 	 * fill the attribute buffer with *defattr, chars with 0x20
296 	 * since we don't know if the driver tries to mimic firmware output or
297 	 * reset everything we do nothing to VRAM here, any driver that feels
298 	 * the need to clear screen or something will have to do it on its own
299 	 * Additional screens will start out in the background anyway so
300 	 * cleaning or not only really affects the initial console screen
301 	 */
302 	for (i = 0; i < cnt; i++) {
303 		scr->scr_attrs[i] = *defattr;
304 		scr->scr_chars[i] = 0x20;
305 	}
306 
307 #ifdef VCONS_DRAW_INTR
308 	size = ri->ri_cols * ri->ri_rows;
309 	if (size > vd->cells) {
310 		if (vd->chars != NULL) free(vd->chars, M_DEVBUF);
311 		if (vd->attrs != NULL) free(vd->attrs, M_DEVBUF);
312 		vd->cells = size;
313 		vd->chars = malloc(size * sizeof(uint32_t), M_DEVBUF, M_WAITOK);
314 		vd->attrs = malloc(size * sizeof(long), M_DEVBUF, M_WAITOK);
315 		vcons_invalidate_cache(vd);
316 	}
317 #endif
318 
319 	if(vd->active == NULL) {
320 		vd->active = scr;
321 		SCREEN_VISIBLE(scr);
322 	}
323 
324 	if (existing) {
325 		SCREEN_VISIBLE(scr);
326 		vd->active = scr;
327 	} else {
328 		SCREEN_INVISIBLE(scr);
329 	}
330 
331 	LIST_INSERT_HEAD(&vd->screens, scr, next);
332 	return 0;
333 }
334 
335 static void
336 vcons_do_switch(void *arg)
337 {
338 	struct vcons_data *vd = arg;
339 	struct vcons_screen *scr, *oldscr;
340 
341 	scr = vd->wanted;
342 	if (!scr) {
343 		printf("vcons_switch_screen: disappeared\n");
344 		vd->switch_cb(vd->switch_cb_arg, EIO, 0);
345 		return;
346 	}
347 	oldscr = vd->active; /* can be NULL! */
348 
349 	/*
350 	 * if there's an old, visible screen we mark it invisible and wait
351 	 * until it's not busy so we can safely switch
352 	 */
353 	if (oldscr != NULL) {
354 		SCREEN_INVISIBLE(oldscr);
355 		if (SCREEN_IS_BUSY(oldscr)) {
356 			callout_schedule(&vd->switch_callout, 1);
357 #ifdef DIAGNOSTIC
358 			/* bitch if we wait too long */
359 			vd->switch_poll_count++;
360 			if (vd->switch_poll_count > 100) {
361 				panic("vcons: screen still busy");
362 			}
363 #endif
364 			return;
365 		}
366 		/* invisible screen -> no visible cursor image */
367 		oldscr->scr_ri.ri_flg &= ~RI_CURSOR;
368 #ifdef DIAGNOSTIC
369 		vd->switch_poll_count = 0;
370 #endif
371 	}
372 
373 	if (scr == oldscr)
374 		return;
375 
376 #ifdef DIAGNOSTIC
377 	if (SCREEN_IS_VISIBLE(scr))
378 		printf("vcons_switch_screen: already active");
379 #endif
380 
381 #ifdef notyet
382 	if (vd->currenttype != type) {
383 		vcons_set_screentype(vd, type);
384 		vd->currenttype = type;
385 	}
386 #endif
387 
388 	SCREEN_VISIBLE(scr);
389 	vd->active = scr;
390 	vd->wanted = NULL;
391 
392 	if (vd->show_screen_cb != NULL)
393 		vd->show_screen_cb(scr);
394 
395 	if ((scr->scr_flags & VCONS_NO_REDRAW) == 0)
396 		vcons_redraw_screen(scr);
397 
398 	if (vd->switch_cb)
399 		vd->switch_cb(vd->switch_cb_arg, 0, 0);
400 }
401 
402 void
403 vcons_redraw_screen(struct vcons_screen *scr)
404 {
405 	uint32_t *charptr = scr->scr_chars, c;
406 	long *attrptr = scr->scr_attrs, a, last_a = 0, mask, cmp, acmp;
407 	struct rasops_info *ri = &scr->scr_ri;
408 	struct vcons_data *vd = scr->scr_vd;
409 	int i, j, offset, boffset = 0, start = -1;
410 
411 	mask = 0x00ff00ff;	/* background and flags */
412 	cmp = -1;		/* never match anything */
413 	vcons_lock(scr);
414 	if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) {
415 
416 		/*
417 		 * only clear the screen when RI_FULLCLEAR is set since we're
418 		 * going to overwrite every single character cell anyway
419 		 */
420 		if (ri->ri_flg & RI_FULLCLEAR) {
421 			vd->eraserows(ri, 0, ri->ri_rows,
422 			    scr->scr_defattr);
423 			cmp = scr->scr_defattr & mask;
424 		}
425 
426 		/* redraw the screen */
427 #ifdef WSDISPLAY_SCROLLSUPPORT
428 		offset = scr->scr_current_offset;
429 #else
430 		offset = 0;
431 #endif
432 		for (i = 0; i < ri->ri_rows; i++) {
433 			start = -1;
434 			for (j = 0; j < ri->ri_cols; j++) {
435 				/*
436 				 * no need to use the wrapper function - we
437 				 * don't change any characters or attributes
438 				 * and we already made sure the screen we're
439 				 * working on is visible
440 				 */
441 				c = charptr[offset];
442 				a = attrptr[offset];
443 				acmp = a & mask;
444 				if (c == ' ') {
445 					/*
446 					 * if we already erased the background
447 					 * and this blank uses the same colour
448 					 * and flags we don't need to do
449 					 * anything here
450 					 */
451 					if (acmp == cmp)
452 						goto next;
453 					/*
454 					 * see if we can optimize things a
455 					 * little bit by drawing stretches of
456 					 * blanks using erasecols
457 					 */
458 
459 					if (start == -1) {
460 						start = j;
461 						last_a = acmp;
462 					} else if (acmp != last_a) {
463 						/*
464 						 * different attr, need to
465 						 * flush
466 						 */
467 						vd->erasecols(ri, i, start,
468 						    j - start, last_a);
469 						start = -1;
470 					}
471 				} else {
472 					if (start != -1) {
473 						vd->erasecols(ri, i, start,
474 						    j - start, last_a);
475 						start = -1;
476 					}
477 
478 					vd->putchar(ri, i, j, c, a);
479 				}
480 next:
481 #ifdef VCONS_DRAW_INTR
482 				vd->chars[boffset] = charptr[offset];
483 				vd->attrs[boffset] = attrptr[offset];
484 #endif
485 				offset++;
486 				boffset++;
487 			}
488 			/* end of the line - draw all defered blanks, if any */
489 			if (start != -1) {
490 				vd->erasecols(ri, i, start, j - start, last_a);
491 			}
492 		}
493 		ri->ri_flg &= ~RI_CURSOR;
494 		scr->scr_vd->cursor(ri, 1, ri->ri_crow, ri->ri_ccol);
495 #ifdef VCONS_DRAW_INTR
496 		vd->cursor_offset = ri->ri_crow * ri->ri_cols + ri->ri_ccol;
497 #endif
498 	}
499 	vcons_unlock(scr);
500 }
501 
502 #ifdef VCONS_DRAW_INTR
503 void
504 vcons_update_screen(struct vcons_screen *scr)
505 {
506 	uint32_t *charptr = scr->scr_chars;
507 	long *attrptr = scr->scr_attrs;
508 	struct rasops_info *ri = &scr->scr_ri;
509 	struct vcons_data *vd = scr->scr_vd;
510 	int i, j, offset, boffset = 0;
511 
512 	vcons_lock(scr);
513 	if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) {
514 
515 		/* redraw the screen */
516 #ifdef WSDISPLAY_SCROLLSUPPORT
517 		offset = scr->scr_current_offset;
518 #else
519 		offset = 0;
520 #endif
521 		/*
522 		 * we mark the character cell occupied by the cursor as dirty
523 		 * so we don't have to deal with it
524 		 * notice that this isn't necessarily the position where rasops
525 		 * thinks it is, just where we drew it the last time
526 		 */
527 		if (vd->cursor_offset >= 0)
528 			vd->attrs[vd->cursor_offset] = 0xffffffff;
529 
530 		for (i = 0; i < ri->ri_rows; i++) {
531 			for (j = 0; j < ri->ri_cols; j++) {
532 				/*
533 				 * no need to use the wrapper function - we
534 				 * don't change any characters or attributes
535 				 * and we already made sure the screen we're
536 				 * working on is visible
537 				 */
538 				if ((vd->chars[boffset] != charptr[offset]) ||
539 				    (vd->attrs[boffset] != attrptr[offset])) {
540 					vd->putchar(ri, i, j,
541 				 	   charptr[offset], attrptr[offset]);
542 					vd->chars[boffset] = charptr[offset];
543 					vd->attrs[boffset] = attrptr[offset];
544 				}
545 				offset++;
546 				boffset++;
547 			}
548 		}
549 		ri->ri_flg &= ~RI_CURSOR;
550 		scr->scr_vd->cursor(ri, 1, ri->ri_crow, ri->ri_ccol);
551 		vd->cursor_offset = ri->ri_crow * ri->ri_cols + ri->ri_ccol;
552 	}
553 	vcons_unlock(scr);
554 }
555 #endif
556 
557 static int
558 vcons_ioctl(void *v, void *vs, u_long cmd, void *data, int flag,
559 	struct lwp *l)
560 {
561 	struct vcons_data *vd = v;
562 	int error = 0;
563 
564 
565 	switch (cmd) {
566 	case WSDISPLAYIO_GETWSCHAR:
567 		error = vcons_getwschar((struct vcons_screen *)vs,
568 			(struct wsdisplay_char *)data);
569 		break;
570 
571 	case WSDISPLAYIO_PUTWSCHAR:
572 		error = vcons_putwschar((struct vcons_screen *)vs,
573 			(struct wsdisplay_char *)data);
574 		break;
575 
576 	case WSDISPLAYIO_SET_POLLING: {
577 		int poll = *(int *)data;
578 
579 		/* first call the driver's ioctl handler */
580 		if (vd->ioctl != NULL)
581 			error = (*vd->ioctl)(v, vs, cmd, data, flag, l);
582 		if (poll) {
583 			vcons_enable_polling(vd);
584 			vcons_hard_switch(LIST_FIRST(&vd->screens));
585 		} else
586 			vcons_disable_polling(vd);
587 		}
588 		break;
589 
590 	default:
591 		if (vd->ioctl != NULL)
592 			error = (*vd->ioctl)(v, vs, cmd, data, flag, l);
593 		else
594 			error = EPASSTHROUGH;
595 	}
596 
597 	return error;
598 }
599 
600 static int
601 vcons_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
602     int *curxp, int *curyp, long *defattrp)
603 {
604 	struct vcons_data *vd = v;
605 	struct vcons_screen *scr;
606 	int ret;
607 
608 	scr = malloc(sizeof(struct vcons_screen), M_DEVBUF, M_WAITOK | M_ZERO);
609 	if (scr == NULL)
610 		return ENOMEM;
611 
612 	scr->scr_flags = 0;
613 	scr->scr_status = 0;
614 	scr->scr_busy = 0;
615 	scr->scr_type = type;
616 
617 	ret = vcons_init_screen(vd, scr, 0, defattrp);
618 	if (ret != 0) {
619 		free(scr, M_DEVBUF);
620 		return ret;
621 	}
622 
623 	if (vd->active == NULL) {
624 		SCREEN_VISIBLE(scr);
625 		vd->active = scr;
626 		vd->currenttype = type;
627 	}
628 
629 	*cookiep = scr;
630 	*curxp = scr->scr_ri.ri_ccol;
631 	*curyp = scr->scr_ri.ri_crow;
632 	return 0;
633 }
634 
635 static void
636 vcons_free_screen(void *v, void *cookie)
637 {
638 	struct vcons_data *vd = v;
639 	struct vcons_screen *scr = cookie;
640 
641 	vcons_lock(scr);
642 	/* there should be no rasops activity here */
643 
644 	LIST_REMOVE(scr, next);
645 
646 	if ((scr->scr_flags & VCONS_SCREEN_IS_STATIC) == 0) {
647 		free(scr->scr_attrs, M_DEVBUF);
648 		free(scr, M_DEVBUF);
649 	} else {
650 		/*
651 		 * maybe we should just restore the old rasops_info methods
652 		 * and free the character/attribute buffer here?
653 		 */
654 #ifdef VCONS_DEBUG
655 		panic("vcons_free_screen: console");
656 #else
657 		printf("vcons_free_screen: console\n");
658 #endif
659 	}
660 
661 	if (vd->active == scr)
662 		vd->active = NULL;
663 }
664 
665 static int
666 vcons_show_screen(void *v, void *cookie, int waitok,
667     void (*cb)(void *, int, int), void *cb_arg)
668 {
669 	struct vcons_data *vd = v;
670 	struct vcons_screen *scr;
671 
672 	scr = cookie;
673 	if (scr == vd->active)
674 		return 0;
675 
676 	vd->wanted = scr;
677 	vd->switch_cb = cb;
678 	vd->switch_cb_arg = cb_arg;
679 	if (cb) {
680 		callout_schedule(&vd->switch_callout, 0);
681 		return EAGAIN;
682 	}
683 
684 	vcons_do_switch(vd);
685 	return 0;
686 }
687 
688 /* wrappers for rasops_info methods */
689 
690 static void
691 vcons_copycols_buffer(void *cookie, int row, int srccol, int dstcol, int ncols)
692 {
693 	struct rasops_info *ri = cookie;
694 	struct vcons_screen *scr = ri->ri_hw;
695 	int from = srccol + row * ri->ri_cols;
696 	int to = dstcol + row * ri->ri_cols;
697 
698 #ifdef WSDISPLAY_SCROLLSUPPORT
699 	int offset;
700 	offset = scr->scr_offset_to_zero;
701 
702 	memmove(&scr->scr_attrs[offset + to], &scr->scr_attrs[offset + from],
703 	    ncols * sizeof(long));
704 	memmove(&scr->scr_chars[offset + to], &scr->scr_chars[offset + from],
705 	    ncols * sizeof(uint32_t));
706 #else
707 	memmove(&scr->scr_attrs[to], &scr->scr_attrs[from],
708 	    ncols * sizeof(long));
709 	memmove(&scr->scr_chars[to], &scr->scr_chars[from],
710 	    ncols * sizeof(uint32_t));
711 #endif
712 
713 #ifdef VCONS_DRAW_INTR
714 	atomic_inc_uint(&scr->scr_dirty);
715 #endif
716 }
717 
718 static void
719 vcons_copycols(void *cookie, int row, int srccol, int dstcol, int ncols)
720 {
721 	struct rasops_info *ri = cookie;
722 	struct vcons_screen *scr = ri->ri_hw;
723 
724 	vcons_copycols_buffer(cookie, row, srccol, dstcol, ncols);
725 
726 #if defined(VCONS_DRAW_INTR)
727 	if (scr->scr_vd->use_intr)
728 		return;
729 #endif
730 
731 	vcons_lock(scr);
732 	if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) {
733 		scr->scr_vd->copycols(cookie, row, srccol, dstcol, ncols);
734 	}
735 	vcons_unlock(scr);
736 }
737 
738 static void
739 vcons_copycols_noread(void *cookie, int row, int srccol, int dstcol, int ncols)
740 {
741 	struct rasops_info *ri = cookie;
742 	struct vcons_screen *scr = ri->ri_hw;
743 	struct vcons_data *vd = scr->scr_vd;
744 
745 	if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) {
746 		int pos, c, offset, ppos;
747 
748 #ifdef WSDISPLAY_SCROLLSUPPORT
749 		offset = scr->scr_current_offset;
750 #else
751 		offset = 0;
752 #endif
753 		ppos = ri->ri_cols * row + dstcol;
754 		pos = ppos + offset;
755 		for (c = dstcol; c < (dstcol + ncols); c++) {
756 #ifdef VCONS_DRAW_INTR
757 			if ((scr->scr_chars[pos] != vd->chars[ppos]) ||
758 			    (scr->scr_attrs[pos] != vd->attrs[ppos])) {
759 				vd->putchar(cookie, row, c,
760 				   scr->scr_chars[pos], scr->scr_attrs[pos]);
761 				vd->chars[ppos] = scr->scr_chars[pos];
762 				vd->attrs[ppos] = scr->scr_attrs[pos];
763 			}
764 #else
765 			vd->putchar(cookie, row, c, scr->scr_chars[pos],
766 			    scr->scr_attrs[pos]);
767 #endif
768 			pos++;
769 			ppos++;
770 		}
771 	}
772 }
773 
774 static void
775 vcons_erasecols_buffer(void *cookie, int row, int startcol, int ncols, long fillattr)
776 {
777 	struct rasops_info *ri = cookie;
778 	struct vcons_screen *scr = ri->ri_hw;
779 	int start = startcol + row * ri->ri_cols;
780 	int end = start + ncols, i;
781 
782 #ifdef WSDISPLAY_SCROLLSUPPORT
783 	int offset;
784 	offset = scr->scr_offset_to_zero;
785 
786 	for (i = start; i < end; i++) {
787 		scr->scr_attrs[offset + i] = fillattr;
788 		scr->scr_chars[offset + i] = 0x20;
789 	}
790 #else
791 	for (i = start; i < end; i++) {
792 		scr->scr_attrs[i] = fillattr;
793 		scr->scr_chars[i] = 0x20;
794 	}
795 #endif
796 
797 #ifdef VCONS_DRAW_INTR
798 	atomic_inc_uint(&scr->scr_dirty);
799 #endif
800 }
801 
802 #ifdef VCONS_DRAW_INTR
803 static void
804 vcons_erasecols_cached(void *cookie, int row, int startcol, int ncols, long fillattr)
805 {
806 	struct rasops_info *ri = cookie;
807 	struct vcons_screen *scr = ri->ri_hw;
808 	struct vcons_data *vd = scr->scr_vd;
809 	int i, pos = row * ri->ri_cols + startcol;
810 
811 	for (i = pos; i < ncols; i++) {
812 		vd->chars[i] = 0x20;
813 		vd->attrs[i] = fillattr;
814 	}
815 	vd->erasecols(cookie, row, startcol, ncols, fillattr);
816 }
817 #endif
818 
819 static void
820 vcons_erasecols(void *cookie, int row, int startcol, int ncols, long fillattr)
821 {
822 	struct rasops_info *ri = cookie;
823 	struct vcons_screen *scr = ri->ri_hw;
824 
825 	vcons_erasecols_buffer(cookie, row, startcol, ncols, fillattr);
826 
827 #if defined(VCONS_DRAW_INTR)
828 	if (scr->scr_vd->use_intr)
829 		return;
830 #endif
831 
832 	vcons_lock(scr);
833 	if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) {
834 #ifdef VCONS_DRAW_INTR
835 			vcons_erasecols_cached(cookie, row, startcol, ncols,
836 			    fillattr);
837 #else
838 		scr->scr_vd->erasecols(cookie, row, startcol, ncols, fillattr);
839 #endif
840 	}
841 	vcons_unlock(scr);
842 }
843 
844 static void
845 vcons_copyrows_buffer(void *cookie, int srcrow, int dstrow, int nrows)
846 {
847 	struct rasops_info *ri = cookie;
848 	struct vcons_screen *scr = ri->ri_hw;
849 	int from, to, len;
850 
851 #ifdef WSDISPLAY_SCROLLSUPPORT
852 	int offset;
853 	offset = scr->scr_offset_to_zero;
854 
855 	/* do we need to scroll the back buffer? */
856 	if (dstrow == 0) {
857 		from = ri->ri_cols * srcrow;
858 		to = ri->ri_cols * dstrow;
859 
860 		memmove(&scr->scr_attrs[to], &scr->scr_attrs[from],
861 		    scr->scr_offset_to_zero * sizeof(long));
862 		memmove(&scr->scr_chars[to], &scr->scr_chars[from],
863 		    scr->scr_offset_to_zero * sizeof(uint32_t));
864 	}
865 	from = ri->ri_cols * srcrow + offset;
866 	to = ri->ri_cols * dstrow + offset;
867 	len = ri->ri_cols * nrows;
868 
869 #else
870 	from = ri->ri_cols * srcrow;
871 	to = ri->ri_cols * dstrow;
872 	len = ri->ri_cols * nrows;
873 #endif
874 	memmove(&scr->scr_attrs[to], &scr->scr_attrs[from],
875 	    len * sizeof(long));
876 	memmove(&scr->scr_chars[to], &scr->scr_chars[from],
877 	    len * sizeof(uint32_t));
878 
879 #ifdef VCONS_DRAW_INTR
880 	atomic_inc_uint(&scr->scr_dirty);
881 #endif
882 }
883 
884 static void
885 vcons_copyrows(void *cookie, int srcrow, int dstrow, int nrows)
886 {
887 	struct rasops_info *ri = cookie;
888 	struct vcons_screen *scr = ri->ri_hw;
889 
890 	vcons_copyrows_buffer(cookie, srcrow, dstrow, nrows);
891 
892 #if defined(VCONS_DRAW_INTR)
893 	if (scr->scr_vd->use_intr)
894 		return;
895 #endif
896 
897 	vcons_lock(scr);
898 	if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) {
899 		scr->scr_vd->copyrows(cookie, srcrow, dstrow, nrows);
900 	}
901 	vcons_unlock(scr);
902 }
903 
904 static void
905 vcons_copyrows_noread(void *cookie, int srcrow, int dstrow, int nrows)
906 {
907 	struct rasops_info *ri = cookie;
908 	struct vcons_screen *scr = ri->ri_hw;
909 	struct vcons_data *vd = scr->scr_vd;
910 
911 	if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) {
912 		int pos, l, c, offset, ppos;
913 
914 #ifdef WSDISPLAY_SCROLLSUPPORT
915 		offset = scr->scr_current_offset;
916 #else
917 		offset = 0;
918 #endif
919 		ppos = ri->ri_cols * dstrow;
920 		pos = ppos + offset;
921 		for (l = dstrow; l < (dstrow + nrows); l++) {
922 			for (c = 0; c < ri->ri_cols; c++) {
923 #ifdef VCONS_DRAW_INTR
924 				if ((scr->scr_chars[pos] != vd->chars[ppos]) ||
925 				    (scr->scr_attrs[pos] != vd->attrs[ppos])) {
926 					vd->putchar(cookie, l, c,
927 					   scr->scr_chars[pos], scr->scr_attrs[pos]);
928 					vd->chars[ppos] = scr->scr_chars[pos];
929 					vd->attrs[ppos] = scr->scr_attrs[pos];
930 				}
931 #else
932 				vd->putchar(cookie, l, c, scr->scr_chars[pos],
933 				    scr->scr_attrs[pos]);
934 #endif
935 				pos++;
936 				ppos++;
937 			}
938 		}
939 	}
940 }
941 
942 static void
943 vcons_eraserows_buffer(void *cookie, int row, int nrows, long fillattr)
944 {
945 	struct rasops_info *ri = cookie;
946 	struct vcons_screen *scr = ri->ri_hw;
947 	int start, end, i;
948 
949 #ifdef WSDISPLAY_SCROLLSUPPORT
950 	int offset;
951 	offset = scr->scr_offset_to_zero;
952 
953 	start = ri->ri_cols * row + offset;
954 	end = ri->ri_cols * (row + nrows) + offset;
955 #else
956 	start = ri->ri_cols * row;
957 	end = ri->ri_cols * (row + nrows);
958 #endif
959 
960 	for (i = start; i < end; i++) {
961 		scr->scr_attrs[i] = fillattr;
962 		scr->scr_chars[i] = 0x20;
963 	}
964 
965 #ifdef VCONS_DRAW_INTR
966 	atomic_inc_uint(&scr->scr_dirty);
967 #endif
968 }
969 
970 static void
971 vcons_eraserows(void *cookie, int row, int nrows, long fillattr)
972 {
973 	struct rasops_info *ri = cookie;
974 	struct vcons_screen *scr = ri->ri_hw;
975 
976 	vcons_eraserows_buffer(cookie, row, nrows, fillattr);
977 
978 #if defined(VCONS_DRAW_INTR)
979 	if (scr->scr_vd->use_intr)
980 		return;
981 #endif
982 
983 	vcons_lock(scr);
984 	if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) {
985 		scr->scr_vd->eraserows(cookie, row, nrows, fillattr);
986 	}
987 	vcons_unlock(scr);
988 }
989 
990 static void
991 vcons_putchar_buffer(void *cookie, int row, int col, u_int c, long attr)
992 {
993 	struct rasops_info *ri = cookie;
994 	struct vcons_screen *scr = ri->ri_hw;
995 	int pos;
996 
997 #ifdef WSDISPLAY_SCROLLSUPPORT
998 	int offset;
999 	offset = scr->scr_offset_to_zero;
1000 
1001 	if ((row >= 0) && (row < ri->ri_rows) && (col >= 0) &&
1002 	     (col < ri->ri_cols)) {
1003 		pos = col + row * ri->ri_cols;
1004 		scr->scr_attrs[pos + offset] = attr;
1005 		scr->scr_chars[pos + offset] = c;
1006 	}
1007 #else
1008 	if ((row >= 0) && (row < ri->ri_rows) && (col >= 0) &&
1009 	     (col < ri->ri_cols)) {
1010 		pos = col + row * ri->ri_cols;
1011 		scr->scr_attrs[pos] = attr;
1012 		scr->scr_chars[pos] = c;
1013 	}
1014 #endif
1015 
1016 #ifdef VCONS_DRAW_INTR
1017 	atomic_inc_uint(&scr->scr_dirty);
1018 #endif
1019 }
1020 
1021 #ifdef VCONS_DRAW_INTR
1022 static void
1023 vcons_putchar_cached(void *cookie, int row, int col, u_int c, long attr)
1024 {
1025 	struct rasops_info *ri = cookie;
1026 	struct vcons_screen *scr = ri->ri_hw;
1027 	struct vcons_data *vd = scr->scr_vd;
1028 	int pos = row * ri->ri_cols + col;
1029 
1030 	if ((vd->chars == NULL) || (vd->attrs == NULL)) {
1031 		vd->putchar(cookie, row, col, c, attr);
1032 		return;
1033 	}
1034 	if ((vd->chars[pos] != c) || (vd->attrs[pos] != attr)) {
1035 		vd->attrs[pos] = attr;
1036 		vd->chars[pos] = c;
1037 		vd->putchar(cookie, row, col, c, attr);
1038 	}
1039 }
1040 #endif
1041 
1042 static void
1043 vcons_putchar(void *cookie, int row, int col, u_int c, long attr)
1044 {
1045 	struct rasops_info *ri = cookie;
1046 	struct vcons_screen *scr = ri->ri_hw;
1047 
1048 	vcons_putchar_buffer(cookie, row, col, c, attr);
1049 
1050 #if defined(VCONS_DRAW_INTR)
1051 	if (scr->scr_vd->use_intr)
1052 		return;
1053 #endif
1054 
1055 	vcons_lock(scr);
1056 	if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) {
1057 #ifdef VCONS_DRAW_INTR
1058 		vcons_putchar_cached(cookie, row, col, c, attr);
1059 #else
1060 		scr->scr_vd->putchar(cookie, row, col, c, attr);
1061 #endif
1062 	}
1063 	vcons_unlock(scr);
1064 }
1065 
1066 static void
1067 vcons_cursor(void *cookie, int on, int row, int col)
1068 {
1069 	struct rasops_info *ri = cookie;
1070 	struct vcons_screen *scr = ri->ri_hw;
1071 
1072 
1073 #if defined(VCONS_DRAW_INTR)
1074 	if (scr->scr_vd->use_intr) {
1075 		vcons_lock(scr);
1076 		if (scr->scr_ri.ri_crow != row || scr->scr_ri.ri_ccol != col) {
1077 			scr->scr_ri.ri_crow = row;
1078 			scr->scr_ri.ri_ccol = col;
1079 			atomic_inc_uint(&scr->scr_dirty);
1080 		}
1081 		vcons_unlock(scr);
1082 		return;
1083 	}
1084 #endif
1085 
1086 	vcons_lock(scr);
1087 
1088 	if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) {
1089 		scr->scr_vd->cursor(cookie, on, row, col);
1090 	} else {
1091 		scr->scr_ri.ri_crow = row;
1092 		scr->scr_ri.ri_ccol = col;
1093 	}
1094 	vcons_unlock(scr);
1095 }
1096 
1097 /* methods to read/write characters via ioctl() */
1098 
1099 static int
1100 vcons_putwschar(struct vcons_screen *scr, struct wsdisplay_char *wsc)
1101 {
1102 	long attr;
1103 	struct rasops_info *ri;
1104 
1105 	KASSERT(scr != NULL && wsc != NULL);
1106 
1107 	ri = &scr->scr_ri;
1108 
1109 	if (__predict_false((unsigned int)wsc->col > ri->ri_cols ||
1110 	    (unsigned int)wsc->row > ri->ri_rows))
1111 			return (EINVAL);
1112 
1113 	if ((wsc->row >= 0) && (wsc->row < ri->ri_rows) && (wsc->col >= 0) &&
1114 	     (wsc->col < ri->ri_cols)) {
1115 
1116 		ri->ri_ops.allocattr(ri, wsc->foreground, wsc->background,
1117 		    wsc->flags, &attr);
1118 		vcons_putchar(ri, wsc->row, wsc->col, wsc->letter, attr);
1119 #ifdef VCONS_DEBUG
1120 		printf("vcons_putwschar(%d, %d, %x, %lx\n", wsc->row, wsc->col,
1121 		    wsc->letter, attr);
1122 #endif
1123 		return 0;
1124 	} else
1125 		return EINVAL;
1126 }
1127 
1128 static int
1129 vcons_getwschar(struct vcons_screen *scr, struct wsdisplay_char *wsc)
1130 {
1131 	int offset;
1132 	long attr;
1133 	struct rasops_info *ri;
1134 
1135 	KASSERT(scr != NULL && wsc != NULL);
1136 
1137 	ri = &scr->scr_ri;
1138 
1139 	if ((wsc->row >= 0) && (wsc->row < ri->ri_rows) && (wsc->col >= 0) &&
1140 	     (wsc->col < ri->ri_cols)) {
1141 
1142 		offset = ri->ri_cols * wsc->row + wsc->col;
1143 #ifdef WSDISPLAY_SCROLLSUPPORT
1144 		offset += scr->scr_offset_to_zero;
1145 #endif
1146 		wsc->letter = scr->scr_chars[offset];
1147 		attr = scr->scr_attrs[offset];
1148 
1149 		/*
1150 		 * this is ugly. We need to break up an attribute into colours and
1151 		 * flags but there's no rasops method to do that so we must rely on
1152 		 * the 'canonical' encoding.
1153 		 */
1154 #ifdef VCONS_DEBUG
1155 		printf("vcons_getwschar: %d, %d, %x, %lx\n", wsc->row,
1156 		    wsc->col, wsc->letter, attr);
1157 #endif
1158 		wsc->foreground = (attr >> 24) & 0xff;
1159 		wsc->background = (attr >> 16) & 0xff;
1160 		wsc->flags      = attr & 0xff;
1161 		return 0;
1162 	} else
1163 		return EINVAL;
1164 }
1165 
1166 #ifdef WSDISPLAY_SCROLLSUPPORT
1167 
1168 static void
1169 vcons_scroll(void *cookie, void *vs, int where)
1170 {
1171 	struct vcons_screen *scr = vs;
1172 
1173 	if (where == 0) {
1174 		scr->scr_line_wanted = 0;
1175 	} else {
1176 		scr->scr_line_wanted = scr->scr_line_wanted - where;
1177 		if (scr->scr_line_wanted < 0)
1178 			scr->scr_line_wanted = 0;
1179 		if (scr->scr_line_wanted > scr->scr_lines_in_buffer)
1180 			scr->scr_line_wanted = scr->scr_lines_in_buffer;
1181 	}
1182 
1183 	if (scr->scr_line_wanted != scr->scr_current_line) {
1184 
1185 		vcons_do_scroll(scr);
1186 	}
1187 }
1188 
1189 static void
1190 vcons_do_scroll(struct vcons_screen *scr)
1191 {
1192 	int dist, from, to, num;
1193 	int r_offset, r_start;
1194 	int i, j;
1195 
1196 	if (scr->scr_line_wanted == scr->scr_current_line)
1197 		return;
1198 	dist = scr->scr_line_wanted - scr->scr_current_line;
1199 	scr->scr_current_line = scr->scr_line_wanted;
1200 	scr->scr_current_offset = scr->scr_ri.ri_cols *
1201 	    (scr->scr_lines_in_buffer - scr->scr_current_line);
1202 	if (abs(dist) >= scr->scr_ri.ri_rows) {
1203 		vcons_redraw_screen(scr);
1204 		return;
1205 	}
1206 	/* scroll and redraw only what we really have to */
1207 	if (dist > 0) {
1208 		/* we scroll down */
1209 		from = 0;
1210 		to = dist;
1211 		num = scr->scr_ri.ri_rows - dist;
1212 		/* now the redraw parameters */
1213 		r_offset = scr->scr_current_offset;
1214 		r_start = 0;
1215 	} else {
1216 		/* scrolling up */
1217 		to = 0;
1218 		from = -dist;
1219 		num = scr->scr_ri.ri_rows + dist;
1220 		r_offset = scr->scr_current_offset + num * scr->scr_ri.ri_cols;
1221 		r_start = num;
1222 	}
1223 	scr->scr_vd->copyrows(scr, from, to, num);
1224 	for (i = 0; i < abs(dist); i++) {
1225 		for (j = 0; j < scr->scr_ri.ri_cols; j++) {
1226 #ifdef VCONS_DRAW_INTR
1227 			vcons_putchar_cached(scr, i + r_start, j,
1228 			    scr->scr_chars[r_offset],
1229 			    scr->scr_attrs[r_offset]);
1230 #else
1231 			scr->scr_vd->putchar(scr, i + r_start, j,
1232 			    scr->scr_chars[r_offset],
1233 			    scr->scr_attrs[r_offset]);
1234 #endif
1235 			r_offset++;
1236 		}
1237 	}
1238 
1239 	if (scr->scr_line_wanted == 0) {
1240 		/* this was a reset - need to draw the cursor */
1241 		scr->scr_ri.ri_flg &= ~RI_CURSOR;
1242 		scr->scr_vd->cursor(scr, 1, scr->scr_ri.ri_crow,
1243 		    scr->scr_ri.ri_ccol);
1244 	}
1245 }
1246 
1247 #endif /* WSDISPLAY_SCROLLSUPPORT */
1248 
1249 #ifdef VCONS_DRAW_INTR
1250 static void
1251 vcons_intr(void *cookie)
1252 {
1253 	struct vcons_data *vd = cookie;
1254 
1255 	softint_schedule(vd->intr_softint);
1256 }
1257 
1258 static void
1259 vcons_softintr(void *cookie)
1260 {
1261 	struct vcons_data *vd = cookie;
1262 	struct vcons_screen *scr = vd->active;
1263 	unsigned int dirty;
1264 
1265 	if (scr && vd->use_intr == 1) {
1266 		if (!SCREEN_IS_BUSY(scr)) {
1267 			dirty = atomic_swap_uint(&scr->scr_dirty, 0);
1268 			if (dirty > 0) {
1269 				if ((scr->scr_flags & VCONS_NO_REDRAW) == 0)
1270 					vcons_update_screen(scr);
1271 			}
1272 		}
1273 	}
1274 
1275 	callout_schedule(&vd->intr, mstohz(33));
1276 }
1277 
1278 static void
1279 vcons_intr_enable(device_t dev)
1280 {
1281 	/* the 'dev' arg we pass to config_interrupts isn't a device_t */
1282 	struct vcons_data *vd = (struct vcons_data *)dev;
1283 	vd->use_intr = 1;
1284 	callout_schedule(&vd->intr, mstohz(33));
1285 }
1286 #endif /* VCONS_DRAW_INTR */
1287 
1288 void
1289 vcons_enable_polling(struct vcons_data *vd)
1290 {
1291 	struct vcons_screen *scr = vd->active;
1292 
1293 #ifdef VCONS_DRAW_INTR
1294 	vd->use_intr = 0;
1295 #endif
1296 
1297 	if (scr && !SCREEN_IS_BUSY(scr)) {
1298 		if ((scr->scr_flags & VCONS_NO_REDRAW) == 0)
1299 			vcons_redraw_screen(scr);
1300 	}
1301 }
1302 
1303 void
1304 vcons_disable_polling(struct vcons_data *vd)
1305 {
1306 #ifdef VCONS_DRAW_INTR
1307 	struct vcons_screen *scr = vd->active;
1308 
1309 	if (!vd->intr_valid)
1310 		return;
1311 
1312 	vd->use_intr = 1;
1313 	if (scr)
1314 		atomic_inc_uint(&scr->scr_dirty);
1315 #endif
1316 }
1317 
1318 void
1319 vcons_hard_switch(struct vcons_screen *scr)
1320 {
1321 	struct vcons_data *vd = scr->scr_vd;
1322 	struct vcons_screen *oldscr = vd->active;
1323 
1324 	if (oldscr) {
1325 		SCREEN_INVISIBLE(oldscr);
1326 		oldscr->scr_ri.ri_flg &= ~RI_CURSOR;
1327 	}
1328 	SCREEN_VISIBLE(scr);
1329 	vd->active = scr;
1330 	vd->wanted = NULL;
1331 
1332 	if (vd->show_screen_cb != NULL)
1333 		vd->show_screen_cb(scr);
1334 }
1335 
1336 #ifdef VCONS_DRAW_INTR
1337 void
1338 vcons_invalidate_cache(struct vcons_data *vd)
1339 {
1340 	int i;
1341 
1342 	if (vd->cells == 0)
1343 		return;
1344 
1345 	for (i = 0; i > vd->cells; i++) {
1346 		vd->chars[i] = -1;
1347 		vd->attrs[i] = -1;
1348 	}
1349 }
1350 #endif
1351