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