1 1.70 macallan /* $NetBSD: wsdisplay_vcons.c,v 1.70 2025/04/28 07:43:41 macallan Exp $ */ 2 1.1 macallan 3 1.1 macallan /*- 4 1.1 macallan * Copyright (c) 2005, 2006 Michael Lorenz 5 1.1 macallan * All rights reserved. 6 1.1 macallan * 7 1.1 macallan * Redistribution and use in source and binary forms, with or without 8 1.1 macallan * modification, are permitted provided that the following conditions 9 1.1 macallan * are met: 10 1.1 macallan * 1. Redistributions of source code must retain the above copyright 11 1.1 macallan * notice, this list of conditions and the following disclaimer. 12 1.1 macallan * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 macallan * notice, this list of conditions and the following disclaimer in the 14 1.1 macallan * documentation and/or other materials provided with the distribution. 15 1.1 macallan * 16 1.1 macallan * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 1.1 macallan * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 1.1 macallan * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 1.1 macallan * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 1.1 macallan * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 1.1 macallan * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 1.1 macallan * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 1.1 macallan * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 1.1 macallan * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 1.1 macallan * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 1.1 macallan * POSSIBILITY OF SUCH DAMAGE. 27 1.1 macallan */ 28 1.1 macallan 29 1.1 macallan #include <sys/cdefs.h> 30 1.70 macallan __KERNEL_RCSID(0, "$NetBSD: wsdisplay_vcons.c,v 1.70 2025/04/28 07:43:41 macallan Exp $"); 31 1.1 macallan 32 1.1 macallan #include <sys/param.h> 33 1.1 macallan #include <sys/systm.h> 34 1.1 macallan #include <sys/kernel.h> 35 1.1 macallan #include <sys/buf.h> 36 1.1 macallan #include <sys/device.h> 37 1.1 macallan #include <sys/ioctl.h> 38 1.1 macallan #include <sys/malloc.h> 39 1.1 macallan #include <sys/mman.h> 40 1.1 macallan #include <sys/tty.h> 41 1.1 macallan #include <sys/conf.h> 42 1.1 macallan #include <sys/proc.h> 43 1.1 macallan #include <sys/kthread.h> 44 1.1 macallan #include <sys/tprintf.h> 45 1.19 macallan #include <sys/atomic.h> 46 1.63 riastrad #include <sys/kmem.h> 47 1.1 macallan 48 1.1 macallan #include <dev/wscons/wsdisplayvar.h> 49 1.1 macallan #include <dev/wscons/wsconsio.h> 50 1.1 macallan #include <dev/wsfont/wsfont.h> 51 1.1 macallan #include <dev/rasops/rasops.h> 52 1.1 macallan 53 1.1 macallan #include <dev/wscons/wsdisplay_vconsvar.h> 54 1.1 macallan 55 1.32 riastrad #ifdef _KERNEL_OPT 56 1.14 macallan #include "opt_wsemul.h" 57 1.14 macallan #include "opt_wsdisplay_compat.h" 58 1.14 macallan #include "opt_vcons.h" 59 1.32 riastrad #endif 60 1.14 macallan 61 1.37 macallan #ifdef VCONS_DEBUG 62 1.37 macallan #define DPRINTF printf 63 1.37 macallan #else 64 1.37 macallan #define DPRINTF if (0) printf 65 1.37 macallan #endif 66 1.37 macallan 67 1.63 riastrad struct vcons_data_private { 68 1.63 riastrad /* accessops */ 69 1.63 riastrad int (*ioctl)(void *, void *, u_long, void *, int, struct lwp *); 70 1.63 riastrad 71 1.63 riastrad /* rasops */ 72 1.63 riastrad void (*copycols)(void *, int, int, int, int); 73 1.63 riastrad void (*erasecols)(void *, int, int, int, long); 74 1.63 riastrad void (*copyrows)(void *, int, int, int); 75 1.63 riastrad void (*eraserows)(void *, int, int, long); 76 1.63 riastrad void (*cursor)(void *, int, int, int); 77 1.63 riastrad 78 1.63 riastrad /* virtual screen management stuff */ 79 1.63 riastrad void (*switch_cb)(void *, int, int); 80 1.63 riastrad void *switch_cb_arg; 81 1.63 riastrad struct callout switch_callout; 82 1.63 riastrad uint32_t switch_pending; 83 1.63 riastrad LIST_HEAD(, vcons_screen) screens; 84 1.63 riastrad struct vcons_screen *wanted; 85 1.63 riastrad const struct wsscreen_descr *currenttype; 86 1.63 riastrad struct wsscreen_descr *defaulttype; 87 1.63 riastrad int switch_poll_count; 88 1.63 riastrad 89 1.63 riastrad #ifdef VCONS_DRAW_INTR 90 1.63 riastrad int cells; 91 1.63 riastrad long *attrs; 92 1.63 riastrad uint32_t *chars; 93 1.63 riastrad int cursor_offset; 94 1.63 riastrad callout_t intr; 95 1.63 riastrad int intr_valid; 96 1.63 riastrad void *intr_softint; 97 1.63 riastrad int use_intr; /* use intr drawing when non-zero */ 98 1.63 riastrad #endif 99 1.63 riastrad }; 100 1.63 riastrad 101 1.55 riastrad static void vcons_dummy_init_screen(void *, struct vcons_screen *, int, 102 1.1 macallan long *); 103 1.1 macallan 104 1.10 christos static int vcons_ioctl(void *, void *, u_long, void *, int, struct lwp *); 105 1.55 riastrad static int vcons_alloc_screen(void *, const struct wsscreen_descr *, void **, 106 1.1 macallan int *, int *, long *); 107 1.1 macallan static void vcons_free_screen(void *, void *); 108 1.1 macallan static int vcons_show_screen(void *, void *, int, void (*)(void *, int, int), 109 1.1 macallan void *); 110 1.37 macallan static int vcons_load_font(void *, void *, struct wsdisplay_font *); 111 1.1 macallan 112 1.14 macallan #ifdef WSDISPLAY_SCROLLSUPPORT 113 1.14 macallan static void vcons_scroll(void *, void *, int); 114 1.14 macallan static void vcons_do_scroll(struct vcons_screen *); 115 1.14 macallan #endif 116 1.14 macallan 117 1.15 joerg static void vcons_do_switch(void *); 118 1.1 macallan 119 1.1 macallan /* methods that work only on text buffers */ 120 1.1 macallan static void vcons_copycols_buffer(void *, int, int, int, int); 121 1.1 macallan static void vcons_erasecols_buffer(void *, int, int, int, long); 122 1.1 macallan static void vcons_copyrows_buffer(void *, int, int, int); 123 1.1 macallan static void vcons_eraserows_buffer(void *, int, int, long); 124 1.65 macallan static int vcons_putchar_buffer(void *, int, int, u_int, long); 125 1.1 macallan 126 1.1 macallan /* 127 1.1 macallan * actual wrapper methods which call both the _buffer ones above and the 128 1.1 macallan * driver supplied ones to do the drawing 129 1.1 macallan */ 130 1.1 macallan static void vcons_copycols(void *, int, int, int, int); 131 1.1 macallan static void vcons_erasecols(void *, int, int, int, long); 132 1.1 macallan static void vcons_copyrows(void *, int, int, int); 133 1.1 macallan static void vcons_eraserows(void *, int, int, long); 134 1.1 macallan static void vcons_putchar(void *, int, int, u_int, long); 135 1.25 macallan #ifdef VCONS_DRAW_INTR 136 1.30 mlelstv static void vcons_erasecols_cached(void *, int, int, int, long); 137 1.30 mlelstv static void vcons_eraserows_cached(void *, int, int, long); 138 1.25 macallan static void vcons_putchar_cached(void *, int, int, u_int, long); 139 1.25 macallan #endif 140 1.1 macallan static void vcons_cursor(void *, int, int, int); 141 1.48 macallan static void vcons_cursor_noread(void *, int, int, int); 142 1.1 macallan 143 1.17 macallan /* 144 1.17 macallan * methods that avoid framebuffer reads 145 1.17 macallan */ 146 1.17 macallan static void vcons_copycols_noread(void *, int, int, int, int); 147 1.17 macallan static void vcons_copyrows_noread(void *, int, int, int); 148 1.17 macallan 149 1.17 macallan 150 1.14 macallan /* support for reading/writing text buffers. For wsmoused */ 151 1.6 jmmv static int vcons_putwschar(struct vcons_screen *, struct wsdisplay_char *); 152 1.6 jmmv static int vcons_getwschar(struct vcons_screen *, struct wsdisplay_char *); 153 1.1 macallan 154 1.1 macallan static void vcons_lock(struct vcons_screen *); 155 1.1 macallan static void vcons_unlock(struct vcons_screen *); 156 1.1 macallan 157 1.20 jmcneill #ifdef VCONS_DRAW_INTR 158 1.20 jmcneill static void vcons_intr(void *); 159 1.22 jmcneill static void vcons_softintr(void *); 160 1.47 jmcneill static void vcons_init_thread(void *); 161 1.63 riastrad static void vcons_invalidate_cache(struct vcons_data *); 162 1.20 jmcneill #endif 163 1.1 macallan 164 1.57 riastrad static inline bool 165 1.57 riastrad vcons_use_intr(const struct vcons_screen *scr) 166 1.57 riastrad { 167 1.57 riastrad #ifdef VCONS_DRAW_INTR 168 1.63 riastrad return scr->scr_vd->private->use_intr; 169 1.57 riastrad #else 170 1.57 riastrad return false; 171 1.57 riastrad #endif 172 1.57 riastrad } 173 1.57 riastrad 174 1.58 riastrad static inline void 175 1.58 riastrad vcons_dirty(struct vcons_screen *scr) 176 1.58 riastrad { 177 1.58 riastrad #ifdef VCONS_DRAW_INTR 178 1.59 riastrad membar_release(); 179 1.58 riastrad atomic_inc_uint(&scr->scr_dirty); 180 1.58 riastrad #endif 181 1.58 riastrad } 182 1.58 riastrad 183 1.47 jmcneill static int 184 1.47 jmcneill vcons_init_common(struct vcons_data *vd, void *cookie, 185 1.47 jmcneill struct wsscreen_descr *def, struct wsdisplay_accessops *ao, 186 1.47 jmcneill int enable_intr) 187 1.1 macallan { 188 1.63 riastrad struct vcons_data_private *vdp; 189 1.2 macallan 190 1.2 macallan /* zero out everything so we can rely on untouched fields being 0 */ 191 1.3 macallan memset(vd, 0, sizeof(struct vcons_data)); 192 1.47 jmcneill 193 1.63 riastrad vd->private = vdp = kmem_zalloc(sizeof(*vdp), KM_SLEEP); 194 1.1 macallan vd->cookie = cookie; 195 1.1 macallan 196 1.1 macallan vd->init_screen = vcons_dummy_init_screen; 197 1.1 macallan vd->show_screen_cb = NULL; 198 1.1 macallan 199 1.6 jmmv /* keep a copy of the accessops that we replace below with our 200 1.6 jmmv * own wrappers */ 201 1.63 riastrad vdp->ioctl = ao->ioctl; 202 1.6 jmmv 203 1.6 jmmv /* configure the accessops */ 204 1.6 jmmv ao->ioctl = vcons_ioctl; 205 1.1 macallan ao->alloc_screen = vcons_alloc_screen; 206 1.1 macallan ao->free_screen = vcons_free_screen; 207 1.1 macallan ao->show_screen = vcons_show_screen; 208 1.37 macallan ao->load_font = vcons_load_font; 209 1.14 macallan #ifdef WSDISPLAY_SCROLLSUPPORT 210 1.14 macallan ao->scroll = vcons_scroll; 211 1.14 macallan #endif 212 1.1 macallan 213 1.63 riastrad LIST_INIT(&vdp->screens); 214 1.1 macallan vd->active = NULL; 215 1.63 riastrad vdp->wanted = NULL; 216 1.63 riastrad vdp->currenttype = def; 217 1.63 riastrad vdp->defaulttype = def; 218 1.63 riastrad callout_init(&vdp->switch_callout, 0); 219 1.63 riastrad callout_setfunc(&vdp->switch_callout, vcons_do_switch, vd); 220 1.63 riastrad #ifdef VCONS_DRAW_INTR 221 1.63 riastrad vdp->cells = 0; 222 1.63 riastrad vdp->attrs = NULL; 223 1.63 riastrad vdp->chars = NULL; 224 1.63 riastrad vdp->cursor_offset = -1; 225 1.25 macallan #endif 226 1.1 macallan 227 1.1 macallan /* 228 1.1 macallan * a lock to serialize access to the framebuffer. 229 1.1 macallan * when switching screens we need to make sure there's no rasops 230 1.1 macallan * operation in progress 231 1.1 macallan */ 232 1.1 macallan #ifdef DIAGNOSTIC 233 1.63 riastrad vdp->switch_poll_count = 0; 234 1.1 macallan #endif 235 1.20 jmcneill #ifdef VCONS_DRAW_INTR 236 1.47 jmcneill if (enable_intr) { 237 1.63 riastrad vdp->intr_softint = softint_establish(SOFTINT_SERIAL, 238 1.47 jmcneill vcons_softintr, vd); 239 1.63 riastrad callout_init(&vdp->intr, CALLOUT_MPSAFE); 240 1.63 riastrad callout_setfunc(&vdp->intr, vcons_intr, vd); 241 1.63 riastrad vdp->intr_valid = 1; 242 1.47 jmcneill 243 1.47 jmcneill if (kthread_create(PRI_NONE, 0, NULL, vcons_init_thread, vd, 244 1.47 jmcneill NULL, "vcons_init") != 0) { 245 1.47 jmcneill printf("%s: unable to create thread.\n", __func__); 246 1.47 jmcneill return -1; 247 1.47 jmcneill } 248 1.47 jmcneill } 249 1.20 jmcneill #endif 250 1.1 macallan return 0; 251 1.1 macallan } 252 1.1 macallan 253 1.47 jmcneill int 254 1.47 jmcneill vcons_init(struct vcons_data *vd, void *cookie, 255 1.47 jmcneill struct wsscreen_descr *def, struct wsdisplay_accessops *ao) 256 1.47 jmcneill { 257 1.47 jmcneill return vcons_init_common(vd, cookie, def, ao, 1); 258 1.47 jmcneill } 259 1.47 jmcneill 260 1.47 jmcneill int 261 1.47 jmcneill vcons_earlyinit(struct vcons_data *vd, void *cookie, 262 1.47 jmcneill struct wsscreen_descr *def, struct wsdisplay_accessops *ao) 263 1.47 jmcneill { 264 1.47 jmcneill return vcons_init_common(vd, cookie, def, ao, 0); 265 1.47 jmcneill } 266 1.47 jmcneill 267 1.1 macallan static void 268 1.1 macallan vcons_lock(struct vcons_screen *scr) 269 1.1 macallan { 270 1.1 macallan #ifdef VCONS_PARANOIA 271 1.1 macallan int s; 272 1.1 macallan 273 1.1 macallan s = splhigh(); 274 1.1 macallan #endif 275 1.1 macallan SCREEN_BUSY(scr); 276 1.1 macallan #ifdef VCONS_PARANOIA 277 1.1 macallan splx(s); 278 1.1 macallan #endif 279 1.1 macallan } 280 1.1 macallan 281 1.1 macallan static void 282 1.1 macallan vcons_unlock(struct vcons_screen *scr) 283 1.1 macallan { 284 1.1 macallan #ifdef VCONS_PARANOIA 285 1.1 macallan int s; 286 1.1 macallan 287 1.1 macallan s = splhigh(); 288 1.1 macallan #endif 289 1.1 macallan SCREEN_IDLE(scr); 290 1.1 macallan #ifdef VCONS_PARANOIA 291 1.1 macallan splx(s); 292 1.1 macallan #endif 293 1.1 macallan } 294 1.1 macallan 295 1.1 macallan static void 296 1.9 christos vcons_dummy_init_screen(void *cookie, 297 1.9 christos struct vcons_screen *scr, int exists, 298 1.9 christos long *defattr) 299 1.1 macallan { 300 1.1 macallan 301 1.1 macallan /* 302 1.1 macallan * default init_screen() method. 303 1.1 macallan * Needs to be overwritten so we bitch and whine in case anyone ends 304 1.1 macallan * up in here. 305 1.1 macallan */ 306 1.1 macallan printf("vcons_init_screen: dummy function called. Your driver is " 307 1.1 macallan "supposed to supply a replacement for proper operation\n"); 308 1.1 macallan } 309 1.1 macallan 310 1.37 macallan static int 311 1.37 macallan vcons_alloc_buffers(struct vcons_data *vd, struct vcons_screen *scr) 312 1.1 macallan { 313 1.1 macallan struct rasops_info *ri = &scr->scr_ri; 314 1.1 macallan int cnt, i; 315 1.25 macallan #ifdef VCONS_DRAW_INTR 316 1.63 riastrad struct vcons_data_private *vdp = vd->private; 317 1.25 macallan int size; 318 1.25 macallan #endif 319 1.1 macallan 320 1.55 riastrad /* 321 1.55 riastrad * we allocate both chars and attributes in one chunk, attributes first 322 1.55 riastrad * because they have the (potentially) bigger alignment 323 1.37 macallan */ 324 1.37 macallan #ifdef WSDISPLAY_SCROLLSUPPORT 325 1.37 macallan cnt = (ri->ri_rows + WSDISPLAY_SCROLLBACK_LINES) * ri->ri_cols; 326 1.37 macallan scr->scr_lines_in_buffer = WSDISPLAY_SCROLLBACK_LINES; 327 1.37 macallan scr->scr_current_line = 0; 328 1.37 macallan scr->scr_line_wanted = 0; 329 1.37 macallan scr->scr_offset_to_zero = ri->ri_cols * WSDISPLAY_SCROLLBACK_LINES; 330 1.37 macallan scr->scr_current_offset = scr->scr_offset_to_zero; 331 1.37 macallan #else 332 1.37 macallan cnt = ri->ri_rows * ri->ri_cols; 333 1.37 macallan #endif 334 1.55 riastrad scr->scr_attrs = malloc(cnt * (sizeof(long) + 335 1.37 macallan sizeof(uint32_t)), M_DEVBUF, M_WAITOK); 336 1.37 macallan if (scr->scr_attrs == NULL) 337 1.37 macallan return ENOMEM; 338 1.37 macallan 339 1.37 macallan scr->scr_chars = (uint32_t *)&scr->scr_attrs[cnt]; 340 1.37 macallan 341 1.55 riastrad /* 342 1.55 riastrad * fill the attribute buffer with *defattr, chars with 0x20 343 1.37 macallan * since we don't know if the driver tries to mimic firmware output or 344 1.37 macallan * reset everything we do nothing to VRAM here, any driver that feels 345 1.37 macallan * the need to clear screen or something will have to do it on its own 346 1.37 macallan * Additional screens will start out in the background anyway so 347 1.37 macallan * cleaning or not only really affects the initial console screen 348 1.37 macallan */ 349 1.37 macallan for (i = 0; i < cnt; i++) { 350 1.37 macallan scr->scr_attrs[i] = scr->scr_defattr; 351 1.37 macallan scr->scr_chars[i] = 0x20; 352 1.37 macallan } 353 1.37 macallan 354 1.37 macallan #ifdef VCONS_DRAW_INTR 355 1.37 macallan size = ri->ri_cols * ri->ri_rows; 356 1.63 riastrad if (size > vdp->cells) { 357 1.67 riastrad if (vdp->chars != NULL) 358 1.67 riastrad free(vdp->chars, M_DEVBUF); 359 1.67 riastrad if (vdp->attrs != NULL) 360 1.67 riastrad free(vdp->attrs, M_DEVBUF); 361 1.63 riastrad vdp->cells = size; 362 1.63 riastrad vdp->chars = malloc(size * sizeof(uint32_t), M_DEVBUF, 363 1.37 macallan M_WAITOK|M_ZERO); 364 1.63 riastrad vdp->attrs = malloc(size * sizeof(long), M_DEVBUF, 365 1.37 macallan M_WAITOK|M_ZERO); 366 1.37 macallan vcons_invalidate_cache(vd); 367 1.37 macallan } else if (SCREEN_IS_VISIBLE(scr)) 368 1.37 macallan vcons_invalidate_cache(vd); 369 1.37 macallan #endif 370 1.37 macallan return 0; 371 1.37 macallan } 372 1.37 macallan 373 1.37 macallan int 374 1.37 macallan vcons_init_screen(struct vcons_data *vd, struct vcons_screen *scr, 375 1.37 macallan int existing, long *defattr) 376 1.37 macallan { 377 1.63 riastrad struct vcons_data_private *vdp = vd->private; 378 1.37 macallan struct rasops_info *ri = &scr->scr_ri; 379 1.37 macallan int i; 380 1.37 macallan 381 1.1 macallan scr->scr_cookie = vd->cookie; 382 1.4 jmcneill scr->scr_vd = scr->scr_origvd = vd; 383 1.14 macallan scr->scr_busy = 0; 384 1.50 macallan 385 1.37 macallan if (scr->scr_type == NULL) 386 1.63 riastrad scr->scr_type = vdp->defaulttype; 387 1.55 riastrad 388 1.1 macallan /* 389 1.1 macallan * call the driver-supplied init_screen function which is expected 390 1.1 macallan * to set up rasops_info, override cursor() and probably others 391 1.1 macallan */ 392 1.1 macallan vd->init_screen(vd->cookie, scr, existing, defattr); 393 1.1 macallan 394 1.55 riastrad /* 395 1.55 riastrad * save the non virtual console aware rasops and replace them with 396 1.1 macallan * our wrappers 397 1.1 macallan */ 398 1.63 riastrad vdp->eraserows = ri->ri_ops.eraserows; 399 1.63 riastrad vdp->erasecols = ri->ri_ops.erasecols; 400 1.37 macallan scr->putchar = ri->ri_ops.putchar; 401 1.1 macallan 402 1.18 macallan if (scr->scr_flags & VCONS_NO_COPYCOLS) { 403 1.63 riastrad vdp->copycols = vcons_copycols_noread; 404 1.18 macallan } else { 405 1.63 riastrad vdp->copycols = ri->ri_ops.copycols; 406 1.18 macallan } 407 1.18 macallan 408 1.18 macallan if (scr->scr_flags & VCONS_NO_COPYROWS) { 409 1.63 riastrad vdp->copyrows = vcons_copyrows_noread; 410 1.17 macallan } else { 411 1.63 riastrad vdp->copyrows = ri->ri_ops.copyrows; 412 1.17 macallan } 413 1.17 macallan 414 1.48 macallan if (scr->scr_flags & VCONS_NO_CURSOR) { 415 1.63 riastrad vdp->cursor = vcons_cursor_noread; 416 1.48 macallan } else { 417 1.63 riastrad vdp->cursor = ri->ri_ops.cursor; 418 1.48 macallan } 419 1.48 macallan 420 1.55 riastrad ri->ri_ops.eraserows = vcons_eraserows; 421 1.55 riastrad ri->ri_ops.erasecols = vcons_erasecols; 422 1.50 macallan ri->ri_ops.putchar = vcons_putchar; 423 1.50 macallan ri->ri_ops.cursor = vcons_cursor; 424 1.19 macallan ri->ri_ops.copycols = vcons_copycols; 425 1.19 macallan ri->ri_ops.copyrows = vcons_copyrows; 426 1.19 macallan 427 1.19 macallan 428 1.1 macallan ri->ri_hw = scr; 429 1.1 macallan 430 1.35 christos i = ri->ri_ops.allocattr(ri, WS_DEFAULT_FG, WS_DEFAULT_BG, 0, defattr); 431 1.35 christos if (i != 0) { 432 1.35 christos #ifdef DIAGNOSTIC 433 1.35 christos printf("vcons: error allocating attribute %d\n", i); 434 1.35 christos #endif 435 1.35 christos scr->scr_defattr = 0; 436 1.35 christos } else 437 1.35 christos scr->scr_defattr = *defattr; 438 1.1 macallan 439 1.37 macallan vcons_alloc_buffers(vd, scr); 440 1.25 macallan 441 1.63 riastrad if (vd->active == NULL) { 442 1.2 macallan vd->active = scr; 443 1.2 macallan SCREEN_VISIBLE(scr); 444 1.2 macallan } 445 1.55 riastrad 446 1.1 macallan if (existing) { 447 1.2 macallan SCREEN_VISIBLE(scr); 448 1.2 macallan vd->active = scr; 449 1.1 macallan } else { 450 1.2 macallan SCREEN_INVISIBLE(scr); 451 1.1 macallan } 452 1.55 riastrad 453 1.63 riastrad LIST_INSERT_HEAD(&vdp->screens, scr, next); 454 1.1 macallan return 0; 455 1.1 macallan } 456 1.1 macallan 457 1.37 macallan static int 458 1.37 macallan vcons_load_font(void *v, void *cookie, struct wsdisplay_font *f) 459 1.37 macallan { 460 1.37 macallan struct vcons_data *vd = v; 461 1.63 riastrad struct vcons_data_private *vdp = vd->private; 462 1.37 macallan struct vcons_screen *scr = cookie; 463 1.37 macallan struct rasops_info *ri; 464 1.37 macallan struct wsdisplay_font *font; 465 1.70 macallan char buf[64], *at; 466 1.70 macallan int flags = WSFONT_FIND_BITMAP, fcookie, h = 0; 467 1.37 macallan 468 1.37 macallan /* see if we're asked to add a font or use it */ 469 1.37 macallan if (scr == NULL) 470 1.37 macallan return 0; 471 1.37 macallan 472 1.37 macallan ri = &scr->scr_ri; 473 1.37 macallan 474 1.37 macallan /* see if the driver knows how to handle multiple fonts */ 475 1.37 macallan if ((scr->scr_flags & VCONS_LOADFONT) == 0) { 476 1.37 macallan return EOPNOTSUPP; 477 1.37 macallan } 478 1.37 macallan 479 1.37 macallan /* now see what fonts we can use */ 480 1.37 macallan if (ri->ri_flg & RI_ENABLE_ALPHA) { 481 1.37 macallan flags |= WSFONT_FIND_ALPHA; 482 1.37 macallan } 483 1.37 macallan 484 1.70 macallan strncpy(buf, f->name, 63); 485 1.70 macallan buf[63] = 0; 486 1.70 macallan at = strchr(buf, '@'); 487 1.70 macallan if (at != NULL) { 488 1.70 macallan int stat; 489 1.70 macallan at[0] = 0; 490 1.70 macallan at++; 491 1.70 macallan DPRINTF("got '%s'\n", at); 492 1.70 macallan h = strtoi(at, NULL, 10, 1, 99, &stat); 493 1.70 macallan if (stat != 0) h = 0; 494 1.70 macallan DPRINTF("looking for %d\n", h); 495 1.70 macallan } 496 1.70 macallan fcookie = wsfont_find(buf, 0, h, 0, 497 1.66 macallan /* bitorder */ 498 1.66 macallan scr->scr_flags & VCONS_FONT_BITS_R2L ? 499 1.66 macallan WSDISPLAY_FONTORDER_R2L : WSDISPLAY_FONTORDER_L2R, 500 1.66 macallan /* byteorder */ 501 1.66 macallan scr->scr_flags & VCONS_FONT_BYTES_R2L ? 502 1.66 macallan WSDISPLAY_FONTORDER_R2L : WSDISPLAY_FONTORDER_L2R, 503 1.66 macallan flags); 504 1.37 macallan if (fcookie == -1) 505 1.70 macallan return ENOENT; 506 1.37 macallan 507 1.37 macallan wsfont_lock(fcookie, &font); 508 1.37 macallan if (font == NULL) 509 1.37 macallan return EINVAL; 510 1.37 macallan 511 1.37 macallan /* ok, we got a font. Now clear the screen with the old parameters */ 512 1.37 macallan if (SCREEN_IS_VISIBLE(scr)) 513 1.63 riastrad vdp->eraserows(ri, 0, ri->ri_rows, scr->scr_defattr); 514 1.37 macallan 515 1.37 macallan vcons_lock(vd->active); 516 1.37 macallan #ifdef VCONS_DRAW_INTR 517 1.63 riastrad callout_halt(&vdp->intr, NULL); 518 1.37 macallan #endif 519 1.37 macallan /* set the new font and re-initialize things */ 520 1.37 macallan ri->ri_font = font; 521 1.37 macallan wsfont_unlock(ri->ri_wsfcookie); 522 1.37 macallan ri->ri_wsfcookie = fcookie; 523 1.37 macallan 524 1.37 macallan vd->init_screen(vd->cookie, scr, 1, &scr->scr_defattr); 525 1.37 macallan DPRINTF("caps %x %x\n", scr->scr_type->capabilities, ri->ri_caps); 526 1.37 macallan if (scr->scr_type->capabilities & WSSCREEN_RESIZE) { 527 1.37 macallan scr->scr_type->nrows = ri->ri_rows; 528 1.37 macallan scr->scr_type->ncols = ri->ri_cols; 529 1.37 macallan DPRINTF("new size %d %d\n", ri->ri_rows, ri->ri_cols); 530 1.37 macallan } 531 1.37 macallan 532 1.37 macallan 533 1.37 macallan /* now, throw the old buffers away */ 534 1.37 macallan if (scr->scr_attrs) 535 1.37 macallan free(scr->scr_attrs, M_DEVBUF); 536 1.37 macallan /* allocate new buffers */ 537 1.37 macallan vcons_alloc_buffers(vd, scr); 538 1.55 riastrad 539 1.55 riastrad /* save the potentially changed ri_ops */ 540 1.63 riastrad vdp->eraserows = ri->ri_ops.eraserows; 541 1.63 riastrad vdp->erasecols = ri->ri_ops.erasecols; 542 1.37 macallan scr->putchar = ri->ri_ops.putchar; 543 1.63 riastrad vdp->cursor = ri->ri_ops.cursor; 544 1.40 rin 545 1.40 rin if (scr->scr_flags & VCONS_NO_COPYCOLS) { 546 1.63 riastrad vdp->copycols = vcons_copycols_noread; 547 1.40 rin } else { 548 1.63 riastrad vdp->copycols = ri->ri_ops.copycols; 549 1.40 rin } 550 1.40 rin 551 1.40 rin if (scr->scr_flags & VCONS_NO_COPYROWS) { 552 1.63 riastrad vdp->copyrows = vcons_copyrows_noread; 553 1.40 rin } else { 554 1.63 riastrad vdp->copyrows = ri->ri_ops.copyrows; 555 1.40 rin } 556 1.37 macallan 557 1.50 macallan if (scr->scr_flags & VCONS_NO_CURSOR) { 558 1.63 riastrad vdp->cursor = vcons_cursor_noread; 559 1.50 macallan } else { 560 1.63 riastrad vdp->cursor = ri->ri_ops.cursor; 561 1.50 macallan } 562 1.50 macallan 563 1.37 macallan /* and put our wrappers back */ 564 1.55 riastrad ri->ri_ops.eraserows = vcons_eraserows; 565 1.55 riastrad ri->ri_ops.erasecols = vcons_erasecols; 566 1.37 macallan ri->ri_ops.putchar = vcons_putchar; 567 1.50 macallan ri->ri_ops.cursor = vcons_cursor; 568 1.37 macallan ri->ri_ops.copycols = vcons_copycols; 569 1.37 macallan ri->ri_ops.copyrows = vcons_copyrows; 570 1.37 macallan vcons_unlock(vd->active); 571 1.38 macallan 572 1.38 macallan /* notify things that we're about to redraw */ 573 1.38 macallan if (vd->show_screen_cb != NULL) 574 1.38 macallan vd->show_screen_cb(scr, vd->show_screen_cookie); 575 1.55 riastrad 576 1.37 macallan #ifdef VCONS_DRAW_INTR 577 1.37 macallan /* 578 1.37 macallan * XXX 579 1.55 riastrad * Something(tm) craps all over VRAM somewhere up there if we're 580 1.37 macallan * using VCONS_DRAW_INTR. Until I figure out what causes it, just 581 1.37 macallan * redraw the screen for now. 582 1.37 macallan */ 583 1.37 macallan vcons_redraw_screen(vd->active); 584 1.63 riastrad callout_schedule(&vdp->intr, mstohz(33)); 585 1.37 macallan #endif 586 1.37 macallan /* no need to draw anything, wsdisplay should reset the terminal */ 587 1.37 macallan 588 1.37 macallan return 0; 589 1.55 riastrad } 590 1.37 macallan 591 1.1 macallan static void 592 1.15 joerg vcons_do_switch(void *arg) 593 1.1 macallan { 594 1.15 joerg struct vcons_data *vd = arg; 595 1.63 riastrad struct vcons_data_private *vdp = vd->private; 596 1.1 macallan struct vcons_screen *scr, *oldscr; 597 1.1 macallan 598 1.63 riastrad scr = vdp->wanted; 599 1.1 macallan if (!scr) { 600 1.1 macallan printf("vcons_switch_screen: disappeared\n"); 601 1.63 riastrad vdp->switch_cb(vdp->switch_cb_arg, EIO, 0); 602 1.1 macallan return; 603 1.1 macallan } 604 1.1 macallan oldscr = vd->active; /* can be NULL! */ 605 1.1 macallan 606 1.55 riastrad /* 607 1.1 macallan * if there's an old, visible screen we mark it invisible and wait 608 1.55 riastrad * until it's not busy so we can safely switch 609 1.1 macallan */ 610 1.1 macallan if (oldscr != NULL) { 611 1.1 macallan SCREEN_INVISIBLE(oldscr); 612 1.1 macallan if (SCREEN_IS_BUSY(oldscr)) { 613 1.63 riastrad callout_schedule(&vdp->switch_callout, 1); 614 1.1 macallan #ifdef DIAGNOSTIC 615 1.1 macallan /* bitch if we wait too long */ 616 1.63 riastrad vdp->switch_poll_count++; 617 1.63 riastrad if (vdp->switch_poll_count > 100) { 618 1.1 macallan panic("vcons: screen still busy"); 619 1.1 macallan } 620 1.1 macallan #endif 621 1.1 macallan return; 622 1.1 macallan } 623 1.1 macallan /* invisible screen -> no visible cursor image */ 624 1.1 macallan oldscr->scr_ri.ri_flg &= ~RI_CURSOR; 625 1.1 macallan #ifdef DIAGNOSTIC 626 1.63 riastrad vdp->switch_poll_count = 0; 627 1.1 macallan #endif 628 1.1 macallan } 629 1.1 macallan 630 1.1 macallan if (scr == oldscr) 631 1.1 macallan return; 632 1.1 macallan 633 1.1 macallan #ifdef DIAGNOSTIC 634 1.1 macallan if (SCREEN_IS_VISIBLE(scr)) 635 1.14 macallan printf("vcons_switch_screen: already active"); 636 1.1 macallan #endif 637 1.1 macallan 638 1.1 macallan #ifdef notyet 639 1.63 riastrad if (vdp->currenttype != type) { 640 1.1 macallan vcons_set_screentype(vd, type); 641 1.63 riastrad vdp->currenttype = type; 642 1.1 macallan } 643 1.1 macallan #endif 644 1.1 macallan 645 1.1 macallan SCREEN_VISIBLE(scr); 646 1.1 macallan vd->active = scr; 647 1.63 riastrad vdp->wanted = NULL; 648 1.1 macallan 649 1.37 macallan #ifdef VCONS_DRAW_INTR 650 1.37 macallan vcons_invalidate_cache(vd); 651 1.37 macallan #endif 652 1.37 macallan 653 1.1 macallan if (vd->show_screen_cb != NULL) 654 1.38 macallan vd->show_screen_cb(scr, vd->show_screen_cookie); 655 1.1 macallan 656 1.1 macallan if ((scr->scr_flags & VCONS_NO_REDRAW) == 0) 657 1.1 macallan vcons_redraw_screen(scr); 658 1.1 macallan 659 1.63 riastrad if (vdp->switch_cb) 660 1.63 riastrad vdp->switch_cb(vdp->switch_cb_arg, 0, 0); 661 1.1 macallan } 662 1.1 macallan 663 1.1 macallan void 664 1.1 macallan vcons_redraw_screen(struct vcons_screen *scr) 665 1.1 macallan { 666 1.28 macallan uint32_t *charptr = scr->scr_chars, c; 667 1.28 macallan long *attrptr = scr->scr_attrs, a, last_a = 0, mask, cmp, acmp; 668 1.1 macallan struct rasops_info *ri = &scr->scr_ri; 669 1.25 macallan struct vcons_data *vd = scr->scr_vd; 670 1.63 riastrad struct vcons_data_private *vdp = vd->private; 671 1.28 macallan int i, j, offset, boffset = 0, start = -1; 672 1.1 macallan 673 1.28 macallan mask = 0x00ff00ff; /* background and flags */ 674 1.36 macallan cmp = 0xffffffff; /* never match anything */ 675 1.1 macallan vcons_lock(scr); 676 1.5 macallan if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) { 677 1.1 macallan 678 1.1 macallan /* 679 1.1 macallan * only clear the screen when RI_FULLCLEAR is set since we're 680 1.1 macallan * going to overwrite every single character cell anyway 681 1.1 macallan */ 682 1.1 macallan if (ri->ri_flg & RI_FULLCLEAR) { 683 1.63 riastrad vdp->eraserows(ri, 0, ri->ri_rows, 684 1.1 macallan scr->scr_defattr); 685 1.28 macallan cmp = scr->scr_defattr & mask; 686 1.1 macallan } 687 1.1 macallan 688 1.1 macallan /* redraw the screen */ 689 1.14 macallan #ifdef WSDISPLAY_SCROLLSUPPORT 690 1.14 macallan offset = scr->scr_current_offset; 691 1.14 macallan #else 692 1.1 macallan offset = 0; 693 1.14 macallan #endif 694 1.1 macallan for (i = 0; i < ri->ri_rows; i++) { 695 1.28 macallan start = -1; 696 1.1 macallan for (j = 0; j < ri->ri_cols; j++) { 697 1.1 macallan /* 698 1.55 riastrad * no need to use the wrapper function - we 699 1.1 macallan * don't change any characters or attributes 700 1.1 macallan * and we already made sure the screen we're 701 1.1 macallan * working on is visible 702 1.1 macallan */ 703 1.28 macallan c = charptr[offset]; 704 1.28 macallan a = attrptr[offset]; 705 1.28 macallan acmp = a & mask; 706 1.28 macallan if (c == ' ') { 707 1.28 macallan /* 708 1.28 macallan * if we already erased the background 709 1.55 riastrad * and if this blank uses the same 710 1.48 macallan * colour and flags we don't need to do 711 1.28 macallan * anything here 712 1.28 macallan */ 713 1.45 macallan if (acmp == cmp && start == -1) 714 1.28 macallan goto next; 715 1.28 macallan /* 716 1.28 macallan * see if we can optimize things a 717 1.28 macallan * little bit by drawing stretches of 718 1.28 macallan * blanks using erasecols 719 1.28 macallan */ 720 1.55 riastrad 721 1.28 macallan if (start == -1) { 722 1.28 macallan start = j; 723 1.28 macallan last_a = acmp; 724 1.28 macallan } else if (acmp != last_a) { 725 1.28 macallan /* 726 1.28 macallan * different attr, need to 727 1.55 riastrad * flush & restart 728 1.28 macallan */ 729 1.63 riastrad vdp->erasecols(ri, i, start, 730 1.28 macallan j - start, last_a); 731 1.36 macallan start = j; 732 1.36 macallan last_a = acmp; 733 1.28 macallan } 734 1.28 macallan } else { 735 1.28 macallan if (start != -1) { 736 1.63 riastrad vdp->erasecols(ri, i, start, 737 1.28 macallan j - start, last_a); 738 1.28 macallan start = -1; 739 1.28 macallan } 740 1.55 riastrad 741 1.37 macallan scr->putchar(ri, i, j, c, a); 742 1.28 macallan } 743 1.28 macallan next: 744 1.25 macallan #ifdef VCONS_DRAW_INTR 745 1.63 riastrad vdp->chars[boffset] = charptr[offset]; 746 1.63 riastrad vdp->attrs[boffset] = attrptr[offset]; 747 1.25 macallan #endif 748 1.25 macallan offset++; 749 1.25 macallan boffset++; 750 1.25 macallan } 751 1.68 andvar /* end of the line - draw all deferred blanks, if any */ 752 1.28 macallan if (start != -1) { 753 1.63 riastrad vdp->erasecols(ri, i, start, j - start, last_a); 754 1.55 riastrad } 755 1.25 macallan } 756 1.25 macallan ri->ri_flg &= ~RI_CURSOR; 757 1.63 riastrad scr->scr_vd->private->cursor(ri, 1, ri->ri_crow, ri->ri_ccol); 758 1.25 macallan #ifdef VCONS_DRAW_INTR 759 1.63 riastrad vdp->cursor_offset = ri->ri_crow * ri->ri_cols + ri->ri_ccol; 760 1.25 macallan #endif 761 1.25 macallan } 762 1.25 macallan vcons_unlock(scr); 763 1.25 macallan } 764 1.25 macallan 765 1.25 macallan void 766 1.25 macallan vcons_update_screen(struct vcons_screen *scr) 767 1.25 macallan { 768 1.63 riastrad #ifdef VCONS_DRAW_INTR 769 1.27 macallan uint32_t *charptr = scr->scr_chars; 770 1.25 macallan long *attrptr = scr->scr_attrs; 771 1.25 macallan struct rasops_info *ri = &scr->scr_ri; 772 1.25 macallan struct vcons_data *vd = scr->scr_vd; 773 1.63 riastrad struct vcons_data_private *vdp = vd->private; 774 1.25 macallan int i, j, offset, boffset = 0; 775 1.25 macallan 776 1.25 macallan vcons_lock(scr); 777 1.25 macallan if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) { 778 1.25 macallan 779 1.25 macallan /* redraw the screen */ 780 1.25 macallan #ifdef WSDISPLAY_SCROLLSUPPORT 781 1.25 macallan offset = scr->scr_current_offset; 782 1.25 macallan #else 783 1.25 macallan offset = 0; 784 1.25 macallan #endif 785 1.25 macallan /* 786 1.25 macallan * we mark the character cell occupied by the cursor as dirty 787 1.25 macallan * so we don't have to deal with it 788 1.25 macallan * notice that this isn't necessarily the position where rasops 789 1.25 macallan * thinks it is, just where we drew it the last time 790 1.25 macallan */ 791 1.63 riastrad if (vdp->cursor_offset >= 0) 792 1.63 riastrad vdp->attrs[vdp->cursor_offset] = 0xffffffff; 793 1.25 macallan 794 1.25 macallan for (i = 0; i < ri->ri_rows; i++) { 795 1.25 macallan for (j = 0; j < ri->ri_cols; j++) { 796 1.25 macallan /* 797 1.55 riastrad * no need to use the wrapper function - we 798 1.25 macallan * don't change any characters or attributes 799 1.25 macallan * and we already made sure the screen we're 800 1.25 macallan * working on is visible 801 1.25 macallan */ 802 1.63 riastrad if ((vdp->chars[boffset] != charptr[offset]) || 803 1.63 riastrad (vdp->attrs[boffset] != attrptr[offset])) { 804 1.55 riastrad scr->putchar(ri, i, j, 805 1.25 macallan charptr[offset], attrptr[offset]); 806 1.63 riastrad vdp->chars[boffset] = charptr[offset]; 807 1.63 riastrad vdp->attrs[boffset] = attrptr[offset]; 808 1.25 macallan } 809 1.1 macallan offset++; 810 1.25 macallan boffset++; 811 1.1 macallan } 812 1.1 macallan } 813 1.1 macallan ri->ri_flg &= ~RI_CURSOR; 814 1.63 riastrad scr->scr_vd->private->cursor(ri, 1, ri->ri_crow, ri->ri_ccol); 815 1.63 riastrad vdp->cursor_offset = ri->ri_crow * ri->ri_cols + ri->ri_ccol; 816 1.1 macallan } 817 1.1 macallan vcons_unlock(scr); 818 1.63 riastrad #else /* !VCONS_DRAW_INTR */ 819 1.63 riastrad vcons_redraw_screen(scr); 820 1.63 riastrad #endif 821 1.1 macallan } 822 1.1 macallan 823 1.1 macallan static int 824 1.10 christos vcons_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, 825 1.6 jmmv struct lwp *l) 826 1.6 jmmv { 827 1.6 jmmv struct vcons_data *vd = v; 828 1.63 riastrad struct vcons_data_private *vdp = vd->private; 829 1.27 macallan int error = 0; 830 1.27 macallan 831 1.6 jmmv 832 1.6 jmmv switch (cmd) { 833 1.6 jmmv case WSDISPLAYIO_GETWSCHAR: 834 1.6 jmmv error = vcons_getwschar((struct vcons_screen *)vs, 835 1.6 jmmv (struct wsdisplay_char *)data); 836 1.6 jmmv break; 837 1.6 jmmv 838 1.6 jmmv case WSDISPLAYIO_PUTWSCHAR: 839 1.6 jmmv error = vcons_putwschar((struct vcons_screen *)vs, 840 1.6 jmmv (struct wsdisplay_char *)data); 841 1.6 jmmv break; 842 1.6 jmmv 843 1.27 macallan case WSDISPLAYIO_SET_POLLING: { 844 1.27 macallan int poll = *(int *)data; 845 1.27 macallan 846 1.27 macallan /* first call the driver's ioctl handler */ 847 1.63 riastrad if (vdp->ioctl != NULL) 848 1.63 riastrad error = (*vdp->ioctl)(v, vs, cmd, data, flag, l); 849 1.27 macallan if (poll) { 850 1.27 macallan vcons_enable_polling(vd); 851 1.63 riastrad vcons_hard_switch(LIST_FIRST(&vdp->screens)); 852 1.27 macallan } else 853 1.27 macallan vcons_disable_polling(vd); 854 1.27 macallan } 855 1.27 macallan break; 856 1.27 macallan 857 1.69 mlelstv case WSDISPLAYIO_GFONT: { 858 1.69 mlelstv struct wsdisplay_getfont *gf = data; 859 1.69 mlelstv size_t actual; 860 1.69 mlelstv struct wsdisplay_font *font; 861 1.69 mlelstv const char *fontname; 862 1.69 mlelstv 863 1.69 mlelstv font = ((struct vcons_screen *)vs)->scr_ri.ri_font; 864 1.69 mlelstv fontname = font && font->name ? font->name : ""; 865 1.69 mlelstv error = copyoutstr(fontname, gf->gf_name, gf->gf_size, &actual); 866 1.69 mlelstv if (!error) 867 1.69 mlelstv gf->gf_actual = actual; 868 1.69 mlelstv } 869 1.69 mlelstv break; 870 1.69 mlelstv 871 1.6 jmmv default: 872 1.63 riastrad if (vdp->ioctl != NULL) 873 1.63 riastrad error = (*vdp->ioctl)(v, vs, cmd, data, flag, l); 874 1.6 jmmv else 875 1.6 jmmv error = EPASSTHROUGH; 876 1.6 jmmv } 877 1.6 jmmv 878 1.6 jmmv return error; 879 1.6 jmmv } 880 1.6 jmmv 881 1.6 jmmv static int 882 1.1 macallan vcons_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep, 883 1.1 macallan int *curxp, int *curyp, long *defattrp) 884 1.1 macallan { 885 1.1 macallan struct vcons_data *vd = v; 886 1.63 riastrad struct vcons_data_private *vdp = vd->private; 887 1.1 macallan struct vcons_screen *scr; 888 1.37 macallan struct wsscreen_descr *t = __UNCONST(type); 889 1.1 macallan int ret; 890 1.1 macallan 891 1.1 macallan scr = malloc(sizeof(struct vcons_screen), M_DEVBUF, M_WAITOK | M_ZERO); 892 1.1 macallan if (scr == NULL) 893 1.1 macallan return ENOMEM; 894 1.1 macallan 895 1.55 riastrad scr->scr_flags = 0; 896 1.2 macallan scr->scr_status = 0; 897 1.2 macallan scr->scr_busy = 0; 898 1.37 macallan scr->scr_type = __UNCONST(type); 899 1.1 macallan 900 1.1 macallan ret = vcons_init_screen(vd, scr, 0, defattrp); 901 1.1 macallan if (ret != 0) { 902 1.1 macallan free(scr, M_DEVBUF); 903 1.1 macallan return ret; 904 1.1 macallan } 905 1.37 macallan if (t->capabilities & WSSCREEN_RESIZE) { 906 1.37 macallan t->nrows = scr->scr_ri.ri_rows; 907 1.37 macallan t->ncols = scr->scr_ri.ri_cols; 908 1.37 macallan } 909 1.1 macallan 910 1.1 macallan if (vd->active == NULL) { 911 1.1 macallan SCREEN_VISIBLE(scr); 912 1.1 macallan vd->active = scr; 913 1.63 riastrad vdp->currenttype = type; 914 1.1 macallan } 915 1.1 macallan 916 1.1 macallan *cookiep = scr; 917 1.1 macallan *curxp = scr->scr_ri.ri_ccol; 918 1.1 macallan *curyp = scr->scr_ri.ri_crow; 919 1.1 macallan return 0; 920 1.1 macallan } 921 1.1 macallan 922 1.1 macallan static void 923 1.1 macallan vcons_free_screen(void *v, void *cookie) 924 1.1 macallan { 925 1.1 macallan struct vcons_data *vd = v; 926 1.1 macallan struct vcons_screen *scr = cookie; 927 1.1 macallan 928 1.1 macallan vcons_lock(scr); 929 1.1 macallan /* there should be no rasops activity here */ 930 1.1 macallan 931 1.1 macallan LIST_REMOVE(scr, next); 932 1.1 macallan 933 1.1 macallan if ((scr->scr_flags & VCONS_SCREEN_IS_STATIC) == 0) { 934 1.1 macallan free(scr->scr_attrs, M_DEVBUF); 935 1.1 macallan free(scr, M_DEVBUF); 936 1.1 macallan } else { 937 1.1 macallan /* 938 1.1 macallan * maybe we should just restore the old rasops_info methods 939 1.1 macallan * and free the character/attribute buffer here? 940 1.1 macallan */ 941 1.1 macallan #ifdef VCONS_DEBUG 942 1.1 macallan panic("vcons_free_screen: console"); 943 1.1 macallan #else 944 1.1 macallan printf("vcons_free_screen: console\n"); 945 1.1 macallan #endif 946 1.1 macallan } 947 1.1 macallan 948 1.1 macallan if (vd->active == scr) 949 1.1 macallan vd->active = NULL; 950 1.1 macallan } 951 1.1 macallan 952 1.1 macallan static int 953 1.9 christos vcons_show_screen(void *v, void *cookie, int waitok, 954 1.1 macallan void (*cb)(void *, int, int), void *cb_arg) 955 1.1 macallan { 956 1.1 macallan struct vcons_data *vd = v; 957 1.63 riastrad struct vcons_data_private *vdp = vd->private; 958 1.1 macallan struct vcons_screen *scr; 959 1.1 macallan 960 1.1 macallan scr = cookie; 961 1.1 macallan if (scr == vd->active) 962 1.1 macallan return 0; 963 1.1 macallan 964 1.63 riastrad vdp->wanted = scr; 965 1.63 riastrad vdp->switch_cb = cb; 966 1.63 riastrad vdp->switch_cb_arg = cb_arg; 967 1.1 macallan if (cb) { 968 1.63 riastrad callout_schedule(&vdp->switch_callout, 0); 969 1.1 macallan return EAGAIN; 970 1.1 macallan } 971 1.1 macallan 972 1.1 macallan vcons_do_switch(vd); 973 1.1 macallan return 0; 974 1.1 macallan } 975 1.1 macallan 976 1.1 macallan /* wrappers for rasops_info methods */ 977 1.1 macallan 978 1.1 macallan static void 979 1.1 macallan vcons_copycols_buffer(void *cookie, int row, int srccol, int dstcol, int ncols) 980 1.1 macallan { 981 1.1 macallan struct rasops_info *ri = cookie; 982 1.1 macallan struct vcons_screen *scr = ri->ri_hw; 983 1.1 macallan int from = srccol + row * ri->ri_cols; 984 1.1 macallan int to = dstcol + row * ri->ri_cols; 985 1.56 riastrad int offset = vcons_offset_to_zero(scr); 986 1.14 macallan 987 1.14 macallan memmove(&scr->scr_attrs[offset + to], &scr->scr_attrs[offset + from], 988 1.14 macallan ncols * sizeof(long)); 989 1.14 macallan memmove(&scr->scr_chars[offset + to], &scr->scr_chars[offset + from], 990 1.27 macallan ncols * sizeof(uint32_t)); 991 1.20 jmcneill 992 1.58 riastrad vcons_dirty(scr); 993 1.1 macallan } 994 1.1 macallan 995 1.1 macallan static void 996 1.1 macallan vcons_copycols(void *cookie, int row, int srccol, int dstcol, int ncols) 997 1.1 macallan { 998 1.1 macallan struct rasops_info *ri = cookie; 999 1.1 macallan struct vcons_screen *scr = ri->ri_hw; 1000 1.1 macallan 1001 1.1 macallan vcons_copycols_buffer(cookie, row, srccol, dstcol, ncols); 1002 1.1 macallan 1003 1.57 riastrad if (vcons_use_intr(scr)) 1004 1.21 jmcneill return; 1005 1.21 jmcneill 1006 1.1 macallan vcons_lock(scr); 1007 1.5 macallan if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) { 1008 1.34 mlelstv #if defined(VCONS_DRAW_INTR) 1009 1.34 mlelstv vcons_update_screen(scr); 1010 1.34 mlelstv #else 1011 1.63 riastrad scr->scr_vd->private->copycols(cookie, row, srccol, dstcol, 1012 1.63 riastrad ncols); 1013 1.30 mlelstv #endif 1014 1.1 macallan } 1015 1.1 macallan vcons_unlock(scr); 1016 1.1 macallan } 1017 1.1 macallan 1018 1.1 macallan static void 1019 1.17 macallan vcons_copycols_noread(void *cookie, int row, int srccol, int dstcol, int ncols) 1020 1.17 macallan { 1021 1.17 macallan struct rasops_info *ri = cookie; 1022 1.17 macallan struct vcons_screen *scr = ri->ri_hw; 1023 1.37 macallan #ifdef VCONS_DRAW_INTR 1024 1.25 macallan struct vcons_data *vd = scr->scr_vd; 1025 1.63 riastrad struct vcons_data_private *vdp = vd->private; 1026 1.37 macallan #endif 1027 1.17 macallan 1028 1.30 mlelstv vcons_lock(scr); 1029 1.17 macallan if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) { 1030 1.25 macallan int pos, c, offset, ppos; 1031 1.17 macallan 1032 1.17 macallan #ifdef WSDISPLAY_SCROLLSUPPORT 1033 1.17 macallan offset = scr->scr_current_offset; 1034 1.17 macallan #else 1035 1.17 macallan offset = 0; 1036 1.17 macallan #endif 1037 1.25 macallan ppos = ri->ri_cols * row + dstcol; 1038 1.25 macallan pos = ppos + offset; 1039 1.17 macallan for (c = dstcol; c < (dstcol + ncols); c++) { 1040 1.25 macallan #ifdef VCONS_DRAW_INTR 1041 1.63 riastrad if ((scr->scr_chars[pos] != vdp->chars[ppos]) || 1042 1.63 riastrad (scr->scr_attrs[pos] != vdp->attrs[ppos])) { 1043 1.55 riastrad scr->putchar(cookie, row, c, 1044 1.25 macallan scr->scr_chars[pos], scr->scr_attrs[pos]); 1045 1.63 riastrad vdp->chars[ppos] = scr->scr_chars[pos]; 1046 1.63 riastrad vdp->attrs[ppos] = scr->scr_attrs[pos]; 1047 1.25 macallan } 1048 1.25 macallan #else 1049 1.37 macallan scr->putchar(cookie, row, c, scr->scr_chars[pos], 1050 1.25 macallan scr->scr_attrs[pos]); 1051 1.25 macallan #endif 1052 1.17 macallan pos++; 1053 1.25 macallan ppos++; 1054 1.17 macallan } 1055 1.55 riastrad if (ri->ri_crow == row && 1056 1.50 macallan (ri->ri_ccol >= dstcol && ri->ri_ccol < (dstcol + ncols ))) 1057 1.50 macallan ri->ri_flg &= ~RI_CURSOR; 1058 1.17 macallan } 1059 1.30 mlelstv vcons_unlock(scr); 1060 1.17 macallan } 1061 1.17 macallan 1062 1.17 macallan static void 1063 1.1 macallan vcons_erasecols_buffer(void *cookie, int row, int startcol, int ncols, long fillattr) 1064 1.1 macallan { 1065 1.1 macallan struct rasops_info *ri = cookie; 1066 1.1 macallan struct vcons_screen *scr = ri->ri_hw; 1067 1.1 macallan int start = startcol + row * ri->ri_cols; 1068 1.1 macallan int end = start + ncols, i; 1069 1.56 riastrad int offset = vcons_offset_to_zero(scr); 1070 1.14 macallan 1071 1.14 macallan for (i = start; i < end; i++) { 1072 1.14 macallan scr->scr_attrs[offset + i] = fillattr; 1073 1.14 macallan scr->scr_chars[offset + i] = 0x20; 1074 1.14 macallan } 1075 1.20 jmcneill 1076 1.58 riastrad vcons_dirty(scr); 1077 1.1 macallan } 1078 1.1 macallan 1079 1.25 macallan #ifdef VCONS_DRAW_INTR 1080 1.25 macallan static void 1081 1.25 macallan vcons_erasecols_cached(void *cookie, int row, int startcol, int ncols, long fillattr) 1082 1.25 macallan { 1083 1.25 macallan struct rasops_info *ri = cookie; 1084 1.25 macallan struct vcons_screen *scr = ri->ri_hw; 1085 1.25 macallan struct vcons_data *vd = scr->scr_vd; 1086 1.63 riastrad struct vcons_data_private *vdp = vd->private; 1087 1.25 macallan int i, pos = row * ri->ri_cols + startcol; 1088 1.25 macallan 1089 1.63 riastrad vdp->erasecols(cookie, row, startcol, ncols, fillattr); 1090 1.25 macallan for (i = pos; i < ncols; i++) { 1091 1.63 riastrad vdp->chars[i] = scr->scr_chars[i]; 1092 1.63 riastrad vdp->attrs[i] = scr->scr_attrs[i]; 1093 1.25 macallan } 1094 1.25 macallan } 1095 1.25 macallan #endif 1096 1.25 macallan 1097 1.1 macallan static void 1098 1.1 macallan vcons_erasecols(void *cookie, int row, int startcol, int ncols, long fillattr) 1099 1.1 macallan { 1100 1.1 macallan struct rasops_info *ri = cookie; 1101 1.1 macallan struct vcons_screen *scr = ri->ri_hw; 1102 1.1 macallan 1103 1.1 macallan vcons_erasecols_buffer(cookie, row, startcol, ncols, fillattr); 1104 1.1 macallan 1105 1.57 riastrad if (vcons_use_intr(scr)) 1106 1.21 jmcneill return; 1107 1.21 jmcneill 1108 1.1 macallan vcons_lock(scr); 1109 1.5 macallan if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) { 1110 1.25 macallan #ifdef VCONS_DRAW_INTR 1111 1.55 riastrad vcons_erasecols_cached(cookie, row, startcol, ncols, 1112 1.30 mlelstv fillattr); 1113 1.25 macallan #else 1114 1.63 riastrad scr->scr_vd->private->erasecols(cookie, row, startcol, ncols, 1115 1.63 riastrad fillattr); 1116 1.55 riastrad #endif 1117 1.1 macallan } 1118 1.1 macallan vcons_unlock(scr); 1119 1.1 macallan } 1120 1.1 macallan 1121 1.1 macallan static void 1122 1.1 macallan vcons_copyrows_buffer(void *cookie, int srcrow, int dstrow, int nrows) 1123 1.1 macallan { 1124 1.1 macallan struct rasops_info *ri = cookie; 1125 1.1 macallan struct vcons_screen *scr = ri->ri_hw; 1126 1.1 macallan int from, to, len; 1127 1.56 riastrad int offset = vcons_offset_to_zero(scr); 1128 1.14 macallan 1129 1.14 macallan /* do we need to scroll the back buffer? */ 1130 1.56 riastrad if (dstrow == 0 && offset != 0) { 1131 1.14 macallan from = ri->ri_cols * srcrow; 1132 1.14 macallan to = ri->ri_cols * dstrow; 1133 1.14 macallan 1134 1.14 macallan memmove(&scr->scr_attrs[to], &scr->scr_attrs[from], 1135 1.56 riastrad offset * sizeof(long)); 1136 1.14 macallan memmove(&scr->scr_chars[to], &scr->scr_chars[from], 1137 1.56 riastrad offset * sizeof(uint32_t)); 1138 1.14 macallan } 1139 1.14 macallan from = ri->ri_cols * srcrow + offset; 1140 1.14 macallan to = ri->ri_cols * dstrow + offset; 1141 1.55 riastrad len = ri->ri_cols * nrows; 1142 1.55 riastrad 1143 1.1 macallan memmove(&scr->scr_attrs[to], &scr->scr_attrs[from], 1144 1.1 macallan len * sizeof(long)); 1145 1.1 macallan memmove(&scr->scr_chars[to], &scr->scr_chars[from], 1146 1.27 macallan len * sizeof(uint32_t)); 1147 1.20 jmcneill 1148 1.58 riastrad vcons_dirty(scr); 1149 1.1 macallan } 1150 1.1 macallan 1151 1.1 macallan static void 1152 1.1 macallan vcons_copyrows(void *cookie, int srcrow, int dstrow, int nrows) 1153 1.1 macallan { 1154 1.1 macallan struct rasops_info *ri = cookie; 1155 1.1 macallan struct vcons_screen *scr = ri->ri_hw; 1156 1.1 macallan 1157 1.1 macallan vcons_copyrows_buffer(cookie, srcrow, dstrow, nrows); 1158 1.1 macallan 1159 1.57 riastrad if (vcons_use_intr(scr)) 1160 1.21 jmcneill return; 1161 1.21 jmcneill 1162 1.1 macallan vcons_lock(scr); 1163 1.5 macallan if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) { 1164 1.34 mlelstv #if defined(VCONS_DRAW_INTR) 1165 1.34 mlelstv vcons_update_screen(scr); 1166 1.34 mlelstv #else 1167 1.63 riastrad scr->scr_vd->private->copyrows(cookie, srcrow, dstrow, nrows); 1168 1.30 mlelstv #endif 1169 1.1 macallan } 1170 1.1 macallan vcons_unlock(scr); 1171 1.1 macallan } 1172 1.1 macallan 1173 1.1 macallan static void 1174 1.17 macallan vcons_copyrows_noread(void *cookie, int srcrow, int dstrow, int nrows) 1175 1.17 macallan { 1176 1.17 macallan struct rasops_info *ri = cookie; 1177 1.17 macallan struct vcons_screen *scr = ri->ri_hw; 1178 1.37 macallan #ifdef VCONS_DRAW_INTR 1179 1.25 macallan struct vcons_data *vd = scr->scr_vd; 1180 1.63 riastrad struct vcons_data_private *vdp = vd->private; 1181 1.37 macallan #endif 1182 1.30 mlelstv vcons_lock(scr); 1183 1.17 macallan if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) { 1184 1.25 macallan int pos, l, c, offset, ppos; 1185 1.17 macallan 1186 1.17 macallan #ifdef WSDISPLAY_SCROLLSUPPORT 1187 1.17 macallan offset = scr->scr_current_offset; 1188 1.17 macallan #else 1189 1.17 macallan offset = 0; 1190 1.17 macallan #endif 1191 1.25 macallan ppos = ri->ri_cols * dstrow; 1192 1.25 macallan pos = ppos + offset; 1193 1.17 macallan for (l = dstrow; l < (dstrow + nrows); l++) { 1194 1.17 macallan for (c = 0; c < ri->ri_cols; c++) { 1195 1.25 macallan #ifdef VCONS_DRAW_INTR 1196 1.63 riastrad if ((scr->scr_chars[pos] != vdp->chars[ppos]) || 1197 1.63 riastrad (scr->scr_attrs[pos] != vdp->attrs[ppos])) { 1198 1.55 riastrad scr->putchar(cookie, l, c, 1199 1.25 macallan scr->scr_chars[pos], scr->scr_attrs[pos]); 1200 1.63 riastrad vdp->chars[ppos] = scr->scr_chars[pos]; 1201 1.63 riastrad vdp->attrs[ppos] = scr->scr_attrs[pos]; 1202 1.25 macallan } 1203 1.25 macallan #else 1204 1.37 macallan scr->putchar(cookie, l, c, scr->scr_chars[pos], 1205 1.25 macallan scr->scr_attrs[pos]); 1206 1.25 macallan #endif 1207 1.17 macallan pos++; 1208 1.25 macallan ppos++; 1209 1.17 macallan } 1210 1.17 macallan } 1211 1.50 macallan if (ri->ri_crow >= dstrow && ri->ri_crow < (dstrow + nrows)) 1212 1.50 macallan ri->ri_flg &= ~RI_CURSOR; 1213 1.17 macallan } 1214 1.30 mlelstv vcons_unlock(scr); 1215 1.17 macallan } 1216 1.17 macallan 1217 1.17 macallan static void 1218 1.1 macallan vcons_eraserows_buffer(void *cookie, int row, int nrows, long fillattr) 1219 1.1 macallan { 1220 1.1 macallan struct rasops_info *ri = cookie; 1221 1.1 macallan struct vcons_screen *scr = ri->ri_hw; 1222 1.56 riastrad int offset = vcons_offset_to_zero(scr); 1223 1.1 macallan int start, end, i; 1224 1.1 macallan 1225 1.14 macallan start = ri->ri_cols * row + offset; 1226 1.14 macallan end = ri->ri_cols * (row + nrows) + offset; 1227 1.1 macallan 1228 1.1 macallan for (i = start; i < end; i++) { 1229 1.1 macallan scr->scr_attrs[i] = fillattr; 1230 1.1 macallan scr->scr_chars[i] = 0x20; 1231 1.1 macallan } 1232 1.20 jmcneill 1233 1.58 riastrad vcons_dirty(scr); 1234 1.1 macallan } 1235 1.1 macallan 1236 1.30 mlelstv #ifdef VCONS_DRAW_INTR 1237 1.30 mlelstv static void 1238 1.30 mlelstv vcons_eraserows_cached(void *cookie, int row, int nrows, long fillattr) 1239 1.30 mlelstv { 1240 1.30 mlelstv struct rasops_info *ri = cookie; 1241 1.30 mlelstv struct vcons_screen *scr = ri->ri_hw; 1242 1.30 mlelstv struct vcons_data *vd = scr->scr_vd; 1243 1.63 riastrad struct vcons_data_private *vdp = vd->private; 1244 1.30 mlelstv int i, pos = row * ri->ri_cols, end = (row+nrows) * ri->ri_cols; 1245 1.30 mlelstv 1246 1.30 mlelstv for (i = pos; i < end; i++) { 1247 1.63 riastrad vdp->chars[i] = 0x20; 1248 1.63 riastrad vdp->attrs[i] = fillattr; 1249 1.30 mlelstv } 1250 1.63 riastrad vdp->eraserows(cookie, row, nrows, fillattr); 1251 1.30 mlelstv } 1252 1.30 mlelstv #endif 1253 1.30 mlelstv 1254 1.1 macallan static void 1255 1.1 macallan vcons_eraserows(void *cookie, int row, int nrows, long fillattr) 1256 1.1 macallan { 1257 1.1 macallan struct rasops_info *ri = cookie; 1258 1.1 macallan struct vcons_screen *scr = ri->ri_hw; 1259 1.1 macallan 1260 1.1 macallan vcons_eraserows_buffer(cookie, row, nrows, fillattr); 1261 1.1 macallan 1262 1.57 riastrad if (vcons_use_intr(scr)) 1263 1.21 jmcneill return; 1264 1.21 jmcneill 1265 1.1 macallan vcons_lock(scr); 1266 1.5 macallan if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) { 1267 1.30 mlelstv #ifdef VCONS_DRAW_INTR 1268 1.30 mlelstv vcons_eraserows_cached(cookie, row, nrows, fillattr); 1269 1.30 mlelstv #else 1270 1.63 riastrad scr->scr_vd->private->eraserows(cookie, row, nrows, fillattr); 1271 1.30 mlelstv #endif 1272 1.1 macallan } 1273 1.1 macallan vcons_unlock(scr); 1274 1.1 macallan } 1275 1.1 macallan 1276 1.65 macallan static int 1277 1.1 macallan vcons_putchar_buffer(void *cookie, int row, int col, u_int c, long attr) 1278 1.1 macallan { 1279 1.1 macallan struct rasops_info *ri = cookie; 1280 1.1 macallan struct vcons_screen *scr = ri->ri_hw; 1281 1.56 riastrad int offset = vcons_offset_to_zero(scr); 1282 1.65 macallan int pos, ret = 0; 1283 1.55 riastrad 1284 1.55 riastrad if ((row >= 0) && (row < ri->ri_rows) && (col >= 0) && 1285 1.67 riastrad (col < ri->ri_cols)) { 1286 1.14 macallan pos = col + row * ri->ri_cols; 1287 1.65 macallan ret = (scr->scr_attrs[pos + offset] != attr) || 1288 1.65 macallan (scr->scr_chars[pos + offset] != c); 1289 1.14 macallan scr->scr_attrs[pos + offset] = attr; 1290 1.14 macallan scr->scr_chars[pos + offset] = c; 1291 1.14 macallan } 1292 1.20 jmcneill 1293 1.67 riastrad if (ret) 1294 1.67 riastrad vcons_dirty(scr); 1295 1.65 macallan return ret; 1296 1.1 macallan } 1297 1.1 macallan 1298 1.25 macallan #ifdef VCONS_DRAW_INTR 1299 1.25 macallan static void 1300 1.25 macallan vcons_putchar_cached(void *cookie, int row, int col, u_int c, long attr) 1301 1.25 macallan { 1302 1.25 macallan struct rasops_info *ri = cookie; 1303 1.25 macallan struct vcons_screen *scr = ri->ri_hw; 1304 1.25 macallan struct vcons_data *vd = scr->scr_vd; 1305 1.63 riastrad struct vcons_data_private *vdp = vd->private; 1306 1.25 macallan int pos = row * ri->ri_cols + col; 1307 1.25 macallan 1308 1.63 riastrad if ((vdp->chars == NULL) || (vdp->attrs == NULL)) { 1309 1.37 macallan scr->putchar(cookie, row, col, c, attr); 1310 1.25 macallan return; 1311 1.25 macallan } 1312 1.63 riastrad if ((vdp->chars[pos] != c) || (vdp->attrs[pos] != attr)) { 1313 1.63 riastrad vdp->attrs[pos] = attr; 1314 1.63 riastrad vdp->chars[pos] = c; 1315 1.37 macallan scr->putchar(cookie, row, col, c, attr); 1316 1.25 macallan } 1317 1.25 macallan } 1318 1.25 macallan #endif 1319 1.25 macallan 1320 1.1 macallan static void 1321 1.1 macallan vcons_putchar(void *cookie, int row, int col, u_int c, long attr) 1322 1.1 macallan { 1323 1.1 macallan struct rasops_info *ri = cookie; 1324 1.1 macallan struct vcons_screen *scr = ri->ri_hw; 1325 1.65 macallan int need_draw; 1326 1.67 riastrad 1327 1.65 macallan need_draw = vcons_putchar_buffer(cookie, row, col, c, attr); 1328 1.21 jmcneill 1329 1.57 riastrad if (vcons_use_intr(scr)) 1330 1.21 jmcneill return; 1331 1.21 jmcneill 1332 1.1 macallan vcons_lock(scr); 1333 1.5 macallan if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) { 1334 1.25 macallan #ifdef VCONS_DRAW_INTR 1335 1.67 riastrad if (need_draw) 1336 1.67 riastrad vcons_putchar_cached(cookie, row, col, c, attr); 1337 1.25 macallan #else 1338 1.49 macallan if (row == ri->ri_crow && col == ri->ri_ccol) { 1339 1.49 macallan ri->ri_flg &= ~RI_CURSOR; 1340 1.65 macallan scr->putchar(cookie, row, col, c, attr); 1341 1.65 macallan } else if (need_draw) 1342 1.65 macallan scr->putchar(cookie, row, col, c, attr); 1343 1.25 macallan #endif 1344 1.1 macallan } 1345 1.1 macallan vcons_unlock(scr); 1346 1.1 macallan } 1347 1.1 macallan 1348 1.1 macallan static void 1349 1.1 macallan vcons_cursor(void *cookie, int on, int row, int col) 1350 1.1 macallan { 1351 1.1 macallan struct rasops_info *ri = cookie; 1352 1.1 macallan struct vcons_screen *scr = ri->ri_hw; 1353 1.1 macallan 1354 1.57 riastrad if (vcons_use_intr(scr)) { 1355 1.21 jmcneill vcons_lock(scr); 1356 1.21 jmcneill if (scr->scr_ri.ri_crow != row || scr->scr_ri.ri_ccol != col) { 1357 1.21 jmcneill scr->scr_ri.ri_crow = row; 1358 1.21 jmcneill scr->scr_ri.ri_ccol = col; 1359 1.58 riastrad vcons_dirty(scr); 1360 1.21 jmcneill } 1361 1.21 jmcneill vcons_unlock(scr); 1362 1.21 jmcneill return; 1363 1.20 jmcneill } 1364 1.21 jmcneill 1365 1.21 jmcneill vcons_lock(scr); 1366 1.21 jmcneill 1367 1.5 macallan if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) { 1368 1.63 riastrad scr->scr_vd->private->cursor(cookie, on, row, col); 1369 1.1 macallan } else { 1370 1.1 macallan scr->scr_ri.ri_crow = row; 1371 1.1 macallan scr->scr_ri.ri_ccol = col; 1372 1.1 macallan } 1373 1.1 macallan vcons_unlock(scr); 1374 1.1 macallan } 1375 1.1 macallan 1376 1.48 macallan static void 1377 1.48 macallan vcons_cursor_noread(void *cookie, int on, int row, int col) 1378 1.48 macallan { 1379 1.48 macallan struct rasops_info *ri = cookie; 1380 1.48 macallan struct vcons_screen *scr = ri->ri_hw; 1381 1.50 macallan int offset = 0, ofs; 1382 1.48 macallan 1383 1.48 macallan #ifdef WSDISPLAY_SCROLLSUPPORT 1384 1.48 macallan offset = scr->scr_current_offset; 1385 1.48 macallan #endif 1386 1.50 macallan ofs = offset + ri->ri_crow * ri->ri_cols + ri->ri_ccol; 1387 1.55 riastrad if ((ri->ri_flg & RI_CURSOR) && 1388 1.51 macallan (((scr->scr_flags & VCONS_DONT_READ) != VCONS_DONT_READ) || on)) { 1389 1.50 macallan scr->putchar(cookie, ri->ri_crow, ri->ri_ccol, 1390 1.50 macallan scr->scr_chars[ofs], scr->scr_attrs[ofs]); 1391 1.50 macallan ri->ri_flg &= ~RI_CURSOR; 1392 1.50 macallan } 1393 1.50 macallan ri->ri_crow = row; 1394 1.50 macallan ri->ri_ccol = col; 1395 1.50 macallan ofs = offset + ri->ri_crow * ri->ri_cols + ri->ri_ccol; 1396 1.50 macallan if (on) { 1397 1.50 macallan scr->putchar(cookie, row, col, scr->scr_chars[ofs], 1398 1.48 macallan #ifdef VCONS_DEBUG_CURSOR_NOREAD 1399 1.55 riastrad /* draw a red cursor so we can tell which cursor() 1400 1.50 macallan * implementation is being used */ 1401 1.50 macallan ((scr->scr_attrs[ofs] & 0xff00ffff) ^ 0x0f000000) | 1402 1.50 macallan 0x00010000); 1403 1.48 macallan #else 1404 1.50 macallan scr->scr_attrs[ofs] ^ 0x0f0f0000); 1405 1.48 macallan #endif 1406 1.50 macallan ri->ri_flg |= RI_CURSOR; 1407 1.48 macallan } 1408 1.48 macallan } 1409 1.48 macallan 1410 1.1 macallan /* methods to read/write characters via ioctl() */ 1411 1.1 macallan 1412 1.1 macallan static int 1413 1.6 jmmv vcons_putwschar(struct vcons_screen *scr, struct wsdisplay_char *wsc) 1414 1.1 macallan { 1415 1.1 macallan long attr; 1416 1.6 jmmv struct rasops_info *ri; 1417 1.35 christos int error; 1418 1.6 jmmv 1419 1.61 riastrad KASSERT(scr != NULL); 1420 1.61 riastrad KASSERT(wsc != NULL); 1421 1.6 jmmv 1422 1.13 rumble ri = &scr->scr_ri; 1423 1.13 rumble 1424 1.44 macallan /* allow col as linear index if row == 0 */ 1425 1.44 macallan if (wsc->row == 0) { 1426 1.44 macallan if (wsc->col < 0 || wsc->col > (ri->ri_cols * ri->ri_rows)) 1427 1.44 macallan return EINVAL; 1428 1.44 macallan int rem; 1429 1.44 macallan rem = wsc->col % ri->ri_cols; 1430 1.44 macallan wsc->row = wsc->col / ri->ri_cols; 1431 1.44 macallan DPRINTF("off %d -> %d, %d\n", wsc->col, rem, wsc->row); 1432 1.44 macallan wsc->col = rem; 1433 1.44 macallan } else { 1434 1.44 macallan if (__predict_false(wsc->col < 0 || wsc->col >= ri->ri_cols)) 1435 1.62 riastrad return EINVAL; 1436 1.55 riastrad 1437 1.44 macallan if (__predict_false(wsc->row < 0 || wsc->row >= ri->ri_rows)) 1438 1.62 riastrad return EINVAL; 1439 1.44 macallan } 1440 1.14 macallan 1441 1.44 macallan error = ri->ri_ops.allocattr(ri, wsc->foreground, 1442 1.44 macallan wsc->background, wsc->flags, &attr); 1443 1.44 macallan if (error) 1444 1.44 macallan return error; 1445 1.44 macallan vcons_putchar(ri, wsc->row, wsc->col, wsc->letter, attr); 1446 1.60 riastrad DPRINTF("vcons_putwschar(%d, %d, %x, %lx\n", wsc->row, wsc->col, 1447 1.44 macallan wsc->letter, attr); 1448 1.44 macallan return 0; 1449 1.1 macallan } 1450 1.1 macallan 1451 1.1 macallan static int 1452 1.6 jmmv vcons_getwschar(struct vcons_screen *scr, struct wsdisplay_char *wsc) 1453 1.1 macallan { 1454 1.6 jmmv int offset; 1455 1.1 macallan long attr; 1456 1.6 jmmv struct rasops_info *ri; 1457 1.53 mlelstv int fg, bg, ul; 1458 1.6 jmmv 1459 1.61 riastrad KASSERT(scr != NULL); 1460 1.61 riastrad KASSERT(wsc != NULL); 1461 1.6 jmmv 1462 1.6 jmmv ri = &scr->scr_ri; 1463 1.1 macallan 1464 1.44 macallan /* allow col as linear index if row == 0 */ 1465 1.44 macallan if (wsc->row == 0) { 1466 1.44 macallan if (wsc->col < 0 || wsc->col > (ri->ri_cols * ri->ri_rows)) 1467 1.44 macallan return EINVAL; 1468 1.44 macallan int rem; 1469 1.44 macallan rem = wsc->col % ri->ri_cols; 1470 1.44 macallan wsc->row = wsc->col / ri->ri_cols; 1471 1.44 macallan DPRINTF("off %d -> %d, %d\n", wsc->col, rem, wsc->row); 1472 1.44 macallan wsc->col = rem; 1473 1.44 macallan } else { 1474 1.44 macallan if (__predict_false(wsc->col < 0 || wsc->col >= ri->ri_cols)) 1475 1.62 riastrad return EINVAL; 1476 1.55 riastrad 1477 1.44 macallan if (__predict_false(wsc->row < 0 || wsc->row >= ri->ri_rows)) 1478 1.62 riastrad return EINVAL; 1479 1.44 macallan } 1480 1.14 macallan 1481 1.44 macallan offset = ri->ri_cols * wsc->row + wsc->col; 1482 1.56 riastrad offset += vcons_offset_to_zero(scr); 1483 1.44 macallan wsc->letter = scr->scr_chars[offset]; 1484 1.44 macallan attr = scr->scr_attrs[offset]; 1485 1.14 macallan 1486 1.60 riastrad DPRINTF("vcons_getwschar: %d, %d, %x, %lx\n", wsc->row, 1487 1.53 mlelstv wsc->col, wsc->letter, attr); 1488 1.53 mlelstv 1489 1.55 riastrad /* 1490 1.44 macallan * this is ugly. We need to break up an attribute into colours and 1491 1.44 macallan * flags but there's no rasops method to do that so we must rely on 1492 1.44 macallan * the 'canonical' encoding. 1493 1.44 macallan */ 1494 1.53 mlelstv 1495 1.53 mlelstv /* only fetches underline attribute */ 1496 1.53 mlelstv /* rasops_unpack_attr(attr, &fg, &bg, &ul); */ 1497 1.53 mlelstv fg = (attr >> 24) & 0xf; 1498 1.53 mlelstv bg = (attr >> 16) & 0xf; 1499 1.53 mlelstv ul = (attr & 1); 1500 1.53 mlelstv 1501 1.53 mlelstv wsc->foreground = fg; 1502 1.53 mlelstv wsc->background = bg; 1503 1.53 mlelstv 1504 1.53 mlelstv /* clear trashed bits and restore underline flag */ 1505 1.53 mlelstv attr &= ~(WSATTR_HILIT | WSATTR_BLINK | WSATTR_UNDERLINE); 1506 1.53 mlelstv if (ul) 1507 1.53 mlelstv attr |= WSATTR_UNDERLINE; 1508 1.53 mlelstv 1509 1.53 mlelstv /* restore highlight boost */ 1510 1.53 mlelstv if (attr & WSATTR_HILIT) 1511 1.53 mlelstv if (wsc->foreground >= 8) 1512 1.53 mlelstv wsc->foreground -= 8; 1513 1.53 mlelstv 1514 1.53 mlelstv /* we always use colors, even when not stored */ 1515 1.53 mlelstv attr |= WSATTR_WSCOLORS; 1516 1.44 macallan return 0; 1517 1.14 macallan } 1518 1.14 macallan 1519 1.63 riastrad int 1520 1.63 riastrad vcons_offset_to_zero(const struct vcons_screen *scr) 1521 1.63 riastrad { 1522 1.63 riastrad #ifdef WSDISPLAY_SCROLLSUPPORT 1523 1.63 riastrad return scr->scr_offset_to_zero; 1524 1.63 riastrad #else 1525 1.63 riastrad return 0; 1526 1.63 riastrad #endif 1527 1.63 riastrad } 1528 1.63 riastrad 1529 1.14 macallan #ifdef WSDISPLAY_SCROLLSUPPORT 1530 1.14 macallan 1531 1.14 macallan static void 1532 1.14 macallan vcons_scroll(void *cookie, void *vs, int where) 1533 1.14 macallan { 1534 1.14 macallan struct vcons_screen *scr = vs; 1535 1.14 macallan 1536 1.14 macallan if (where == 0) { 1537 1.14 macallan scr->scr_line_wanted = 0; 1538 1.14 macallan } else { 1539 1.14 macallan scr->scr_line_wanted = scr->scr_line_wanted - where; 1540 1.14 macallan if (scr->scr_line_wanted < 0) 1541 1.14 macallan scr->scr_line_wanted = 0; 1542 1.14 macallan if (scr->scr_line_wanted > scr->scr_lines_in_buffer) 1543 1.14 macallan scr->scr_line_wanted = scr->scr_lines_in_buffer; 1544 1.14 macallan } 1545 1.14 macallan 1546 1.14 macallan if (scr->scr_line_wanted != scr->scr_current_line) { 1547 1.14 macallan 1548 1.14 macallan vcons_do_scroll(scr); 1549 1.14 macallan } 1550 1.14 macallan } 1551 1.14 macallan 1552 1.14 macallan static void 1553 1.14 macallan vcons_do_scroll(struct vcons_screen *scr) 1554 1.14 macallan { 1555 1.14 macallan int dist, from, to, num; 1556 1.14 macallan int r_offset, r_start; 1557 1.14 macallan int i, j; 1558 1.14 macallan 1559 1.14 macallan if (scr->scr_line_wanted == scr->scr_current_line) 1560 1.14 macallan return; 1561 1.14 macallan dist = scr->scr_line_wanted - scr->scr_current_line; 1562 1.14 macallan scr->scr_current_line = scr->scr_line_wanted; 1563 1.14 macallan scr->scr_current_offset = scr->scr_ri.ri_cols * 1564 1.14 macallan (scr->scr_lines_in_buffer - scr->scr_current_line); 1565 1.14 macallan if (abs(dist) >= scr->scr_ri.ri_rows) { 1566 1.14 macallan vcons_redraw_screen(scr); 1567 1.14 macallan return; 1568 1.14 macallan } 1569 1.14 macallan /* scroll and redraw only what we really have to */ 1570 1.14 macallan if (dist > 0) { 1571 1.14 macallan /* we scroll down */ 1572 1.14 macallan from = 0; 1573 1.14 macallan to = dist; 1574 1.14 macallan num = scr->scr_ri.ri_rows - dist; 1575 1.14 macallan /* now the redraw parameters */ 1576 1.14 macallan r_offset = scr->scr_current_offset; 1577 1.14 macallan r_start = 0; 1578 1.14 macallan } else { 1579 1.14 macallan /* scrolling up */ 1580 1.14 macallan to = 0; 1581 1.14 macallan from = -dist; 1582 1.14 macallan num = scr->scr_ri.ri_rows + dist; 1583 1.14 macallan r_offset = scr->scr_current_offset + num * scr->scr_ri.ri_cols; 1584 1.14 macallan r_start = num; 1585 1.14 macallan } 1586 1.63 riastrad scr->scr_vd->private->copyrows(scr, from, to, num); 1587 1.14 macallan for (i = 0; i < abs(dist); i++) { 1588 1.14 macallan for (j = 0; j < scr->scr_ri.ri_cols; j++) { 1589 1.25 macallan #ifdef VCONS_DRAW_INTR 1590 1.25 macallan vcons_putchar_cached(scr, i + r_start, j, 1591 1.25 macallan scr->scr_chars[r_offset], 1592 1.25 macallan scr->scr_attrs[r_offset]); 1593 1.25 macallan #else 1594 1.37 macallan scr->putchar(scr, i + r_start, j, 1595 1.14 macallan scr->scr_chars[r_offset], 1596 1.14 macallan scr->scr_attrs[r_offset]); 1597 1.25 macallan #endif 1598 1.14 macallan r_offset++; 1599 1.14 macallan } 1600 1.14 macallan } 1601 1.14 macallan 1602 1.14 macallan if (scr->scr_line_wanted == 0) { 1603 1.14 macallan /* this was a reset - need to draw the cursor */ 1604 1.14 macallan scr->scr_ri.ri_flg &= ~RI_CURSOR; 1605 1.63 riastrad scr->scr_vd->private->cursor(scr, 1, scr->scr_ri.ri_crow, 1606 1.14 macallan scr->scr_ri.ri_ccol); 1607 1.14 macallan } 1608 1.14 macallan } 1609 1.14 macallan 1610 1.14 macallan #endif /* WSDISPLAY_SCROLLSUPPORT */ 1611 1.14 macallan 1612 1.20 jmcneill #ifdef VCONS_DRAW_INTR 1613 1.20 jmcneill static void 1614 1.20 jmcneill vcons_intr(void *cookie) 1615 1.20 jmcneill { 1616 1.20 jmcneill struct vcons_data *vd = cookie; 1617 1.63 riastrad struct vcons_data_private *vdp = vd->private; 1618 1.20 jmcneill 1619 1.63 riastrad softint_schedule(vdp->intr_softint); 1620 1.20 jmcneill } 1621 1.20 jmcneill 1622 1.20 jmcneill static void 1623 1.22 jmcneill vcons_softintr(void *cookie) 1624 1.20 jmcneill { 1625 1.20 jmcneill struct vcons_data *vd = cookie; 1626 1.63 riastrad struct vcons_data_private *vdp = vd->private; 1627 1.20 jmcneill struct vcons_screen *scr = vd->active; 1628 1.22 jmcneill unsigned int dirty; 1629 1.20 jmcneill 1630 1.63 riastrad if (scr && vdp->use_intr) { 1631 1.22 jmcneill if (!SCREEN_IS_BUSY(scr)) { 1632 1.22 jmcneill dirty = atomic_swap_uint(&scr->scr_dirty, 0); 1633 1.59 riastrad membar_acquire(); 1634 1.63 riastrad if (vdp->use_intr == 2) { 1635 1.30 mlelstv if ((scr->scr_flags & VCONS_NO_REDRAW) == 0) { 1636 1.63 riastrad vdp->use_intr = 1; 1637 1.30 mlelstv vcons_redraw_screen(scr); 1638 1.30 mlelstv } 1639 1.30 mlelstv } else if (dirty > 0) { 1640 1.22 jmcneill if ((scr->scr_flags & VCONS_NO_REDRAW) == 0) 1641 1.25 macallan vcons_update_screen(scr); 1642 1.22 jmcneill } 1643 1.20 jmcneill } 1644 1.20 jmcneill } 1645 1.20 jmcneill 1646 1.63 riastrad callout_schedule(&vdp->intr, mstohz(33)); 1647 1.20 jmcneill } 1648 1.21 jmcneill 1649 1.47 jmcneill static void 1650 1.47 jmcneill vcons_init_thread(void *cookie) 1651 1.21 jmcneill { 1652 1.47 jmcneill struct vcons_data *vd = (struct vcons_data *)cookie; 1653 1.63 riastrad struct vcons_data_private *vdp = vd->private; 1654 1.39 msaitoh 1655 1.63 riastrad vdp->use_intr = 2; 1656 1.63 riastrad callout_schedule(&vdp->intr, mstohz(33)); 1657 1.47 jmcneill kthread_exit(0); 1658 1.21 jmcneill } 1659 1.20 jmcneill #endif /* VCONS_DRAW_INTR */ 1660 1.23 jmcneill 1661 1.23 jmcneill void 1662 1.23 jmcneill vcons_enable_polling(struct vcons_data *vd) 1663 1.23 jmcneill { 1664 1.23 jmcneill struct vcons_screen *scr = vd->active; 1665 1.23 jmcneill 1666 1.23 jmcneill #ifdef VCONS_DRAW_INTR 1667 1.64 martin struct vcons_data_private *vdp = vd->private; 1668 1.64 martin 1669 1.63 riastrad vdp->use_intr = 0; 1670 1.23 jmcneill #endif 1671 1.23 jmcneill 1672 1.23 jmcneill if (scr && !SCREEN_IS_BUSY(scr)) { 1673 1.23 jmcneill if ((scr->scr_flags & VCONS_NO_REDRAW) == 0) 1674 1.23 jmcneill vcons_redraw_screen(scr); 1675 1.23 jmcneill } 1676 1.23 jmcneill } 1677 1.23 jmcneill 1678 1.23 jmcneill void 1679 1.23 jmcneill vcons_disable_polling(struct vcons_data *vd) 1680 1.23 jmcneill { 1681 1.23 jmcneill #ifdef VCONS_DRAW_INTR 1682 1.63 riastrad struct vcons_data_private *vdp = vd->private; 1683 1.23 jmcneill struct vcons_screen *scr = vd->active; 1684 1.23 jmcneill 1685 1.63 riastrad if (!vdp->intr_valid) 1686 1.23 jmcneill return; 1687 1.23 jmcneill 1688 1.63 riastrad vdp->use_intr = 2; 1689 1.23 jmcneill if (scr) 1690 1.58 riastrad vcons_dirty(scr); 1691 1.23 jmcneill #endif 1692 1.23 jmcneill } 1693 1.24 jmcneill 1694 1.24 jmcneill void 1695 1.24 jmcneill vcons_hard_switch(struct vcons_screen *scr) 1696 1.24 jmcneill { 1697 1.24 jmcneill struct vcons_data *vd = scr->scr_vd; 1698 1.63 riastrad struct vcons_data_private *vdp = vd->private; 1699 1.24 jmcneill struct vcons_screen *oldscr = vd->active; 1700 1.24 jmcneill 1701 1.24 jmcneill if (oldscr) { 1702 1.24 jmcneill SCREEN_INVISIBLE(oldscr); 1703 1.24 jmcneill oldscr->scr_ri.ri_flg &= ~RI_CURSOR; 1704 1.24 jmcneill } 1705 1.24 jmcneill SCREEN_VISIBLE(scr); 1706 1.24 jmcneill vd->active = scr; 1707 1.63 riastrad vdp->wanted = NULL; 1708 1.24 jmcneill 1709 1.24 jmcneill if (vd->show_screen_cb != NULL) 1710 1.38 macallan vd->show_screen_cb(scr, vd->show_screen_cookie); 1711 1.24 jmcneill } 1712 1.25 macallan 1713 1.25 macallan #ifdef VCONS_DRAW_INTR 1714 1.63 riastrad static void 1715 1.25 macallan vcons_invalidate_cache(struct vcons_data *vd) 1716 1.25 macallan { 1717 1.63 riastrad struct vcons_data_private *vdp = vd->private; 1718 1.25 macallan int i; 1719 1.25 macallan 1720 1.63 riastrad for (i = 0; i < vdp->cells; i++) { 1721 1.63 riastrad vdp->chars[i] = -1; 1722 1.63 riastrad vdp->attrs[i] = -1; 1723 1.25 macallan } 1724 1.25 macallan } 1725 1.25 macallan #endif 1726