1 1.51 andvar /* $NetBSD: vidcvideo.c,v 1.51 2025/01/05 21:37:21 andvar Exp $ */ 2 1.1 reinoud 3 1.1 reinoud /* 4 1.1 reinoud * Copyright (c) 2001 Reinoud Zandijk 5 1.1 reinoud * Copyright (c) 1998, 1999 Tohru Nishimura. All rights reserved. 6 1.1 reinoud * 7 1.1 reinoud * Redistribution and use in source and binary forms, with or without 8 1.1 reinoud * modification, are permitted provided that the following conditions 9 1.1 reinoud * are met: 10 1.1 reinoud * 1. Redistributions of source code must retain the above copyright 11 1.1 reinoud * notice, this list of conditions and the following disclaimer. 12 1.1 reinoud * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 reinoud * notice, this list of conditions and the following disclaimer in the 14 1.1 reinoud * documentation and/or other materials provided with the distribution. 15 1.1 reinoud * 16 1.1 reinoud * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 1.1 reinoud * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 1.1 reinoud * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 1.1 reinoud * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 1.1 reinoud * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 1.1 reinoud * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 1.1 reinoud * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 1.1 reinoud * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 1.1 reinoud * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 1.1 reinoud * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 1.1 reinoud * 27 1.1 reinoud * Created vidcvideo.c from /dev/tc/cfb.c to fit the Acorn/ARM VIDC1 and VIDC20 chips 28 1.1 reinoud * 29 1.1 reinoud */ 30 1.1 reinoud 31 1.1 reinoud #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ 32 1.1 reinoud 33 1.51 andvar __KERNEL_RCSID(0, "$NetBSD: vidcvideo.c,v 1.51 2025/01/05 21:37:21 andvar Exp $"); 34 1.1 reinoud 35 1.1 reinoud #include <sys/param.h> 36 1.1 reinoud #include <sys/systm.h> 37 1.1 reinoud #include <sys/kernel.h> 38 1.1 reinoud #include <sys/device.h> 39 1.1 reinoud #include <sys/buf.h> 40 1.1 reinoud #include <sys/ioctl.h> 41 1.1 reinoud 42 1.1 reinoud #include <arm/mainbus/mainbus.h> 43 1.39 dyoung #include <sys/bus.h> 44 1.1 reinoud #include <machine/intr.h> 45 1.1 reinoud 46 1.1 reinoud #include <dev/wscons/wsconsio.h> 47 1.1 reinoud #include <dev/wscons/wsdisplayvar.h> 48 1.1 reinoud 49 1.1 reinoud #include <dev/rasops/rasops.h> 50 1.1 reinoud #include <dev/wsfont/wsfont.h> 51 1.1 reinoud 52 1.34 chris #include <dev/wscons/wsdisplay_vconsvar.h> 53 1.34 chris 54 1.1 reinoud #include <uvm/uvm_extern.h> 55 1.1 reinoud #include <arm/arm32/pmap.h> 56 1.9 reinoud #include <arm/cpufunc.h> 57 1.1 reinoud 58 1.49 andvar /* for vidc_mode ... needs to be MI independent one day */ 59 1.1 reinoud #include <arm/iomd/vidc.h> 60 1.1 reinoud #include <arm/iomd/vidc20config.h> 61 1.9 reinoud #include <arm/iomd/vidcvideo.h> 62 1.1 reinoud #include <machine/bootconfig.h> 63 1.9 reinoud 64 1.1 reinoud /* FOR DEBUG */ 65 1.1 reinoud extern videomemory_t videomemory; 66 1.1 reinoud 67 1.1 reinoud struct hwcmap256 { 68 1.1 reinoud #define CMAP_SIZE 256 /* 256 R/G/B entries */ 69 1.34 chris uint8_t r[CMAP_SIZE]; 70 1.34 chris uint8_t g[CMAP_SIZE]; 71 1.34 chris uint8_t b[CMAP_SIZE]; 72 1.1 reinoud }; 73 1.1 reinoud 74 1.1 reinoud 75 1.1 reinoud /* XXX for CURSOR_MAX_WIDTH = 32 */ 76 1.1 reinoud struct hwcursor32 { 77 1.1 reinoud struct wsdisplay_curpos cc_pos; 78 1.1 reinoud struct wsdisplay_curpos cc_hot; 79 1.1 reinoud struct wsdisplay_curpos cc_size; 80 1.34 chris uint8_t cc_color[6]; /* how many? */ 81 1.34 chris uint32_t cc_image[(CURSOR_MAX_WIDTH/4) * CURSOR_MAX_HEIGHT]; 82 1.34 chris uint32_t cc_mask[(CURSOR_MAX_WIDTH/4) * CURSOR_MAX_HEIGHT]; 83 1.1 reinoud }; 84 1.1 reinoud 85 1.1 reinoud 86 1.9 reinoud struct fb_devconfig { 87 1.11 reinoud vaddr_t dc_vaddr; /* memory space virtual base address */ 88 1.11 reinoud paddr_t dc_paddr; /* memory space physical base address */ 89 1.11 reinoud vsize_t dc_size; /* size of slot memory */ 90 1.34 chris int dc_width; /* width of frame buffer */ 91 1.34 chris int dc_height; /* height of frame buffer */ 92 1.11 reinoud int dc_log2_depth; /* log2 of bits per pixel */ 93 1.11 reinoud int dc_depth; /* depth, bits per pixel */ 94 1.11 reinoud int dc_rowbytes; /* bytes in a FB scan line */ 95 1.11 reinoud vaddr_t dc_videobase; /* base of flat frame buffer */ 96 1.11 reinoud int dc_blanked; /* currently has video disabled */ 97 1.11 reinoud void *dc_hwscroll_cookie; /* cookie for hardware scroll */ 98 1.33 chris void *dc_ih; /* interrupt handler for dc */ 99 1.11 reinoud 100 1.11 reinoud int dc_curenb; /* is cursor sprite enabled ? */ 101 1.33 chris int _internal_dc_changed; /* need update of hardware */ 102 1.11 reinoud int dc_writeback_delay; /* Screenarea write back vsync counter */ 103 1.9 reinoud #define WSDISPLAY_CMAP_DOLUT 0x20 104 1.9 reinoud #define WSDISPLAY_VIDEO_ONOFF 0x40 105 1.9 reinoud #define WSDISPLAY_WB_COUNTER 0x80 106 1.9 reinoud 107 1.34 chris struct hwcmap256 dc_cmap; /* software copy of colormap */ 108 1.34 chris struct hwcursor32 dc_cursor; /* software copy of cursor */ 109 1.9 reinoud 110 1.9 reinoud struct vidc_mode mode_info; 111 1.9 reinoud 112 1.51 andvar struct wsdisplay_emulops orig_ri_ops; /* Rasops functions for delegation */ 113 1.34 chris 114 1.34 chris /* virtual console support */ 115 1.34 chris struct vcons_data dc_vd; 116 1.34 chris struct vcons_screen dc_console; 117 1.9 reinoud }; 118 1.9 reinoud 119 1.9 reinoud 120 1.1 reinoud struct vidcvideo_softc { 121 1.43 skrll device_t sc_dev; 122 1.9 reinoud struct fb_devconfig *sc_dc; /* device configuration */ 123 1.1 reinoud }; 124 1.1 reinoud 125 1.1 reinoud 126 1.1 reinoud /* Function prototypes for glue */ 127 1.43 skrll static int vidcvideo_match(device_t , cfdata_t , void *); 128 1.43 skrll static void vidcvideo_attach(device_t , device_t , void *); 129 1.1 reinoud 130 1.1 reinoud 131 1.1 reinoud /* config glue */ 132 1.43 skrll CFATTACH_DECL_NEW(vidcvideo, sizeof(struct vidcvideo_softc), 133 1.16 thorpej vidcvideo_match, vidcvideo_attach, NULL, NULL); 134 1.1 reinoud 135 1.1 reinoud static struct fb_devconfig vidcvideo_console_dc; 136 1.34 chris static bool vidcvideo_is_console = false; 137 1.1 reinoud 138 1.1 reinoud 139 1.1 reinoud static struct wsscreen_descr vidcvideo_stdscreen = { 140 1.1 reinoud "std", 0, 0, 141 1.34 chris NULL, /* textops */ 142 1.34 chris 8, 16, 143 1.34 chris WSSCREEN_WSCOLORS | WSSCREEN_HILIT, 144 1.34 chris NULL 145 1.1 reinoud }; 146 1.1 reinoud 147 1.1 reinoud static const struct wsscreen_descr *_vidcvideo_scrlist[] = { 148 1.1 reinoud &vidcvideo_stdscreen, 149 1.1 reinoud }; 150 1.1 reinoud 151 1.1 reinoud static const struct wsscreen_list vidcvideo_screenlist = { 152 1.25 bjh21 sizeof(_vidcvideo_scrlist) / sizeof(struct wsscreen_descr *), 153 1.25 bjh21 _vidcvideo_scrlist 154 1.1 reinoud }; 155 1.1 reinoud 156 1.31 christos static int vidcvideoioctl(void *, void *, u_long, void *, int, 157 1.25 bjh21 struct lwp *); 158 1.25 bjh21 static paddr_t vidcvideommap(void *, void *, off_t, int); 159 1.34 chris static void vidcvideoinit_screen(void *, struct vcons_screen *, int, long *); 160 1.1 reinoud 161 1.33 chris static void vidcvideo_queue_dc_change(struct fb_devconfig*, int); 162 1.33 chris static int flush_dc_changes_to_screen(struct fb_devconfig*); 163 1.33 chris 164 1.34 chris static struct wsdisplay_accessops vidcvideo_accessops = { 165 1.1 reinoud vidcvideoioctl, 166 1.1 reinoud vidcvideommap, 167 1.34 chris NULL, /* alloc_screen */ 168 1.34 chris NULL, /* free_screen */ 169 1.34 chris NULL, /* show_screen */ 170 1.34 chris NULL, /* load_font */ 171 1.34 chris NULL, /* pollc */ 172 1.34 chris NULL /* scroll */ 173 1.1 reinoud }; 174 1.1 reinoud 175 1.6 reinoud 176 1.1 reinoud /* Function prototypes */ 177 1.25 bjh21 int vidcvideo_cnattach(vaddr_t); 178 1.25 bjh21 static void vidcvideo_colourmap_and_cursor_init(struct fb_devconfig *); 179 1.1 reinoud 180 1.25 bjh21 static int get_cmap(struct vidcvideo_softc *, struct wsdisplay_cmap *); 181 1.25 bjh21 static int set_cmap(struct vidcvideo_softc *, struct wsdisplay_cmap *); 182 1.25 bjh21 static int set_cursor(struct vidcvideo_softc *, struct wsdisplay_cursor *); 183 1.25 bjh21 static int get_cursor(struct vidcvideo_softc *, struct wsdisplay_cursor *); 184 1.25 bjh21 static void set_curpos(struct vidcvideo_softc *, struct wsdisplay_curpos *); 185 1.34 chris static void vidcvideo_getdevconfig(vaddr_t, u_int, struct fb_devconfig *); 186 1.1 reinoud 187 1.25 bjh21 static int vidcvideointr(void *); 188 1.6 reinoud 189 1.1 reinoud /* Acceleration function prototypes */ 190 1.25 bjh21 static void vv_copyrows(void *, int, int, int); 191 1.25 bjh21 static void vv_eraserows(void *, int, int, long); 192 1.25 bjh21 static void vv_putchar(void *c, int row, int col, u_int uc, long attr); 193 1.1 reinoud 194 1.1 reinoud 195 1.1 reinoud static int 196 1.43 skrll vidcvideo_match(device_t parent, cfdata_t match, void *aux) 197 1.1 reinoud { 198 1.25 bjh21 199 1.1 reinoud /* Can't probe AFAIK ; how ? */ 200 1.25 bjh21 return 1; 201 1.1 reinoud } 202 1.1 reinoud 203 1.1 reinoud 204 1.1 reinoud static void 205 1.34 chris vidcvideo_getdevconfig(vaddr_t dense_addr, u_int mem_size, 206 1.34 chris struct fb_devconfig *dc) 207 1.1 reinoud { 208 1.25 bjh21 209 1.1 reinoud dc->dc_vaddr = dense_addr; 210 1.11 reinoud (void) pmap_extract(pmap_kernel(), dc->dc_vaddr, &(dc->dc_paddr)); 211 1.1 reinoud 212 1.1 reinoud vidcvideo_getmode(&dc->mode_info); 213 1.1 reinoud 214 1.34 chris dc->dc_width = dc->mode_info.timings.hdisplay; 215 1.34 chris dc->dc_height = dc->mode_info.timings.vdisplay; 216 1.1 reinoud dc->dc_log2_depth = dc->mode_info.log2_bpp; 217 1.1 reinoud dc->dc_depth = 1 << dc->dc_log2_depth; 218 1.1 reinoud dc->dc_videobase = dc->dc_vaddr; 219 1.1 reinoud dc->dc_blanked = 0; 220 1.1 reinoud 221 1.1 reinoud /* this should/could be done somewhat more elegant! */ 222 1.1 reinoud switch (dc->dc_depth) { 223 1.1 reinoud case 1: 224 1.34 chris dc->dc_rowbytes = dc->dc_width / 8; 225 1.1 reinoud break; 226 1.1 reinoud case 2: 227 1.34 chris dc->dc_rowbytes = dc->dc_width / 4; 228 1.1 reinoud break; 229 1.1 reinoud case 4: 230 1.34 chris dc->dc_rowbytes = dc->dc_width / 2; 231 1.1 reinoud break; 232 1.1 reinoud case 8: 233 1.34 chris dc->dc_rowbytes = dc->dc_width; 234 1.1 reinoud break; 235 1.1 reinoud case 16: 236 1.34 chris dc->dc_rowbytes = dc->dc_width * 2; 237 1.1 reinoud break; 238 1.1 reinoud case 32: 239 1.34 chris dc->dc_rowbytes = dc->dc_width * 4; 240 1.1 reinoud break; 241 1.1 reinoud default: 242 1.1 reinoud printf("Unknown colour depth %d ... what to do ?", dc->dc_depth); 243 1.1 reinoud break; 244 1.25 bjh21 } 245 1.1 reinoud 246 1.34 chris /* setup the correct size */ 247 1.34 chris dc->dc_size = mem_size; 248 1.1 reinoud 249 1.1 reinoud /* initialize colormap and cursor resource */ 250 1.1 reinoud vidcvideo_colourmap_and_cursor_init(dc); 251 1.1 reinoud 252 1.34 chris /* blank the memory */ 253 1.37 cegger memset((void*)dc->dc_vaddr, 0, dc->dc_size); 254 1.9 reinoud 255 1.51 andvar /* initialize miscellaneous */ 256 1.9 reinoud dc->dc_writeback_delay = 0; 257 1.1 reinoud } 258 1.1 reinoud 259 1.1 reinoud static void 260 1.34 chris vidcvideoinit_screen(void *cookie, struct vcons_screen *scr, 261 1.34 chris int existing, long *defattr) 262 1.1 reinoud { 263 1.34 chris struct rasops_info *ri = &scr->scr_ri; 264 1.34 chris struct fb_devconfig *dc = cookie; 265 1.1 reinoud 266 1.34 chris if ((scr == &dc->dc_console) && (dc->dc_vd.active != NULL)) 267 1.1 reinoud return; 268 1.1 reinoud 269 1.41 skrll ri->ri_flg = RI_NO_AUTO; /* RI_CENTER | RI_FULLCLEAR; */ 270 1.34 chris ri->ri_depth = dc->dc_depth; 271 1.34 chris ri->ri_bits = (void *) dc->dc_videobase; 272 1.34 chris ri->ri_width = dc->dc_width; 273 1.34 chris ri->ri_height = dc->dc_height; 274 1.34 chris ri->ri_stride = dc->dc_rowbytes; 275 1.34 chris ri->ri_hw = &dc->dc_console; /* link back */ 276 1.34 chris 277 1.34 chris rasops_init(ri, 278 1.34 chris ri->ri_height / 8, 279 1.34 chris ri->ri_width / 8); 280 1.34 chris 281 1.34 chris ri->ri_caps = WSSCREEN_WSCOLORS; 282 1.34 chris 283 1.34 chris rasops_reconfig(ri, 284 1.34 chris ri->ri_height / ri->ri_font->fontheight, 285 1.34 chris ri->ri_width / ri->ri_font->fontwidth); 286 1.1 reinoud 287 1.6 reinoud /* 288 1.6 reinoud * Provide a hook for the acceleration functions and make a copy of the 289 1.6 reinoud * original rasops functions for passing on calls 290 1.6 reinoud */ 291 1.34 chris memcpy(&(dc->orig_ri_ops), &(ri->ri_ops), 292 1.25 bjh21 sizeof(struct wsdisplay_emulops)); 293 1.6 reinoud 294 1.6 reinoud /* add our accelerated functions */ 295 1.34 chris ri->ri_ops.eraserows = vv_eraserows; 296 1.34 chris ri->ri_ops.copyrows = vv_copyrows; 297 1.1 reinoud 298 1.6 reinoud /* add the extra activity measuring functions; they just delegate on */ 299 1.34 chris ri->ri_ops.putchar = vv_putchar; 300 1.1 reinoud 301 1.34 chris vidcvideo_stdscreen.nrows = ri->ri_rows; 302 1.34 chris vidcvideo_stdscreen.ncols = ri->ri_cols; 303 1.34 chris vidcvideo_stdscreen.textops = &ri->ri_ops; 304 1.34 chris vidcvideo_stdscreen.capabilities = ri->ri_caps; 305 1.1 reinoud } 306 1.1 reinoud 307 1.1 reinoud static void 308 1.43 skrll vidcvideo_attach(device_t parent, device_t self, void *aux) 309 1.1 reinoud { 310 1.43 skrll struct vidcvideo_softc *sc = device_private(self); 311 1.9 reinoud struct fb_devconfig *dc; 312 1.1 reinoud struct wsemuldisplaydev_attach_args waa; 313 1.6 reinoud long defattr; 314 1.43 skrll 315 1.43 skrll sc->sc_dev = self; 316 1.1 reinoud 317 1.34 chris dc = sc->sc_dc = &vidcvideo_console_dc; 318 1.34 chris 319 1.34 chris /* 320 1.34 chris * for reasons which are crazy we init vidcvideo twice, 321 1.34 chris * the second time sets up the cursor 322 1.34 chris */ 323 1.1 reinoud vidcvideo_init(); 324 1.34 chris if (!vidcvideo_is_console) { 325 1.34 chris vidcvideo_getdevconfig(videomemory.vidm_vbase, 326 1.34 chris videomemory.vidm_size, 327 1.34 chris sc->sc_dc); 328 1.25 bjh21 } 329 1.1 reinoud 330 1.34 chris vcons_init(&dc->dc_vd, dc, &vidcvideo_stdscreen, &vidcvideo_accessops); 331 1.34 chris dc->dc_vd.init_screen = vidcvideoinit_screen; 332 1.34 chris 333 1.34 chris vcons_init_screen(&dc->dc_vd, &dc->dc_console, 1, &defattr); 334 1.34 chris 335 1.34 chris dc->dc_console.scr_flags |= VCONS_SCREEN_IS_STATIC; 336 1.9 reinoud 337 1.1 reinoud vidcvideo_printdetails(); 338 1.43 skrll aprint_normal(": mode %s, %dbpp\n", dc->mode_info.timings.name, 339 1.9 reinoud dc->dc_depth); 340 1.1 reinoud 341 1.1 reinoud /* set up interrupt flags */ 342 1.33 chris vidcvideo_queue_dc_change(dc, WSDISPLAY_CMAP_DOLUT); 343 1.1 reinoud 344 1.1 reinoud /* Establish an interrupt handler, and clear any pending interrupts */ 345 1.33 chris dc->dc_ih = intr_claim(IRQ_FLYBACK, IPL_TTY, "vblank", vidcvideointr, dc); 346 1.1 reinoud 347 1.1 reinoud waa.console = (vidcvideo_is_console ? 1 : 0); 348 1.1 reinoud waa.scrdata = &vidcvideo_screenlist; 349 1.1 reinoud waa.accessops = &vidcvideo_accessops; 350 1.34 chris waa.accesscookie = &dc->dc_vd; 351 1.1 reinoud 352 1.47 thorpej config_found(self, &waa, wsemuldisplaydevprint, CFARGS_NONE); 353 1.1 reinoud } 354 1.1 reinoud 355 1.1 reinoud 356 1.1 reinoud static int 357 1.31 christos vidcvideoioctl(void *v, void *vs, u_long cmd, void *data, int flag, 358 1.25 bjh21 struct lwp *l) 359 1.1 reinoud { 360 1.34 chris struct vcons_data *vd = v; 361 1.34 chris struct vidcvideo_softc *sc = vd->cookie; 362 1.1 reinoud struct fb_devconfig *dc = sc->sc_dc; 363 1.34 chris struct vcons_screen *ms = vd->active; 364 1.1 reinoud int state; 365 1.1 reinoud 366 1.1 reinoud switch (cmd) { 367 1.1 reinoud case WSDISPLAYIO_GTYPE: 368 1.1 reinoud *(u_int *)data = WSDISPLAY_TYPE_VIDC; 369 1.25 bjh21 return 0; 370 1.1 reinoud 371 1.1 reinoud case WSDISPLAYIO_GINFO: 372 1.34 chris if (ms == NULL) 373 1.34 chris return ENODEV; 374 1.1 reinoud #define wsd_fbip ((struct wsdisplay_fbinfo *)data) 375 1.34 chris wsd_fbip->height = dc->dc_height; 376 1.34 chris wsd_fbip->width = dc->dc_width; 377 1.9 reinoud wsd_fbip->depth = dc->dc_depth; 378 1.1 reinoud wsd_fbip->cmsize = CMAP_SIZE; 379 1.1 reinoud #undef fbt 380 1.25 bjh21 return 0; 381 1.1 reinoud 382 1.1 reinoud case WSDISPLAYIO_GETCMAP: 383 1.1 reinoud return get_cmap(sc, (struct wsdisplay_cmap *)data); 384 1.1 reinoud 385 1.1 reinoud case WSDISPLAYIO_PUTCMAP: 386 1.1 reinoud return set_cmap(sc, (struct wsdisplay_cmap *)data); 387 1.34 chris 388 1.34 chris case WSDISPLAYIO_LINEBYTES: 389 1.34 chris *(u_int *)data = dc->dc_rowbytes; 390 1.34 chris return 0; 391 1.1 reinoud 392 1.1 reinoud case WSDISPLAYIO_SVIDEO: 393 1.1 reinoud state = *(int *)data; 394 1.1 reinoud dc->dc_blanked = (state == WSDISPLAYIO_VIDEO_OFF); 395 1.33 chris vidcvideo_queue_dc_change(dc, WSDISPLAY_VIDEO_ONOFF); 396 1.1 reinoud /* done on video blank */ 397 1.25 bjh21 return 0; 398 1.1 reinoud 399 1.1 reinoud case WSDISPLAYIO_GVIDEO: 400 1.1 reinoud *(u_int *)data = dc->dc_blanked ? 401 1.1 reinoud WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON; 402 1.25 bjh21 return 0; 403 1.1 reinoud 404 1.1 reinoud case WSDISPLAYIO_GCURPOS: 405 1.9 reinoud *(struct wsdisplay_curpos *)data = dc->dc_cursor.cc_pos; 406 1.25 bjh21 return 0; 407 1.1 reinoud 408 1.1 reinoud case WSDISPLAYIO_SCURPOS: 409 1.1 reinoud set_curpos(sc, (struct wsdisplay_curpos *)data); 410 1.33 chris vidcvideo_queue_dc_change(dc, WSDISPLAY_CURSOR_DOPOS); 411 1.25 bjh21 return 0; 412 1.1 reinoud 413 1.1 reinoud case WSDISPLAYIO_GCURMAX: 414 1.1 reinoud ((struct wsdisplay_curpos *)data)->x = CURSOR_MAX_WIDTH; 415 1.1 reinoud ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_HEIGHT; 416 1.25 bjh21 return 0; 417 1.1 reinoud 418 1.1 reinoud case WSDISPLAYIO_GCURSOR: 419 1.1 reinoud return get_cursor(sc, (struct wsdisplay_cursor *)data); 420 1.1 reinoud 421 1.1 reinoud case WSDISPLAYIO_SCURSOR: 422 1.1 reinoud return set_cursor(sc, (struct wsdisplay_cursor *)data); 423 1.1 reinoud 424 1.1 reinoud case WSDISPLAYIO_SMODE: 425 1.1 reinoud state = *(int *)data; 426 1.25 bjh21 if (state == WSDISPLAYIO_MODE_MAPPED) 427 1.1 reinoud dc->dc_hwscroll_cookie = vidcvideo_hwscroll_reset(); 428 1.25 bjh21 if (state == WSDISPLAYIO_MODE_EMUL) 429 1.1 reinoud vidcvideo_hwscroll_back(dc->dc_hwscroll_cookie); 430 1.1 reinoud vidcvideo_progr_scroll(); 431 1.11 reinoud 432 1.25 bjh21 return 0; 433 1.1 reinoud } 434 1.5 atatat return EPASSTHROUGH; 435 1.1 reinoud } 436 1.1 reinoud 437 1.1 reinoud 438 1.1 reinoud paddr_t 439 1.25 bjh21 vidcvideommap(void *v, void *vs, off_t offset, int prot) 440 1.1 reinoud { 441 1.34 chris struct vcons_data *vd = v; 442 1.34 chris struct vidcvideo_softc *sc = vd->cookie; 443 1.1 reinoud 444 1.1 reinoud if (offset >= sc->sc_dc->dc_size || offset < 0) 445 1.25 bjh21 return -1; 446 1.11 reinoud 447 1.11 reinoud return arm_btop(sc->sc_dc->dc_paddr + offset); 448 1.1 reinoud } 449 1.1 reinoud 450 1.1 reinoud 451 1.1 reinoud /* EXPORT */ int 452 1.25 bjh21 vidcvideo_cnattach(vaddr_t addr) 453 1.1 reinoud { 454 1.34 chris struct fb_devconfig *dc = &vidcvideo_console_dc; 455 1.34 chris struct rasops_info *ri; 456 1.1 reinoud long defattr; 457 1.1 reinoud 458 1.1 reinoud vidcvideo_init(); 459 1.1 reinoud 460 1.34 chris /* fetch current framebuffer config */ 461 1.34 chris vidcvideo_getdevconfig(videomemory.vidm_vbase, 462 1.34 chris videomemory.vidm_size, 463 1.34 chris dc); 464 1.34 chris 465 1.34 chris dc->dc_vd.active = NULL; 466 1.34 chris vidcvideoinit_screen(dc, &dc->dc_console, 1, &defattr); 467 1.34 chris 468 1.34 chris ri = &(dc->dc_console.scr_ri); 469 1.34 chris ri->ri_hw = &dc->dc_console; 470 1.34 chris dc->dc_console.scr_cookie = dc; 471 1.34 chris 472 1.34 chris (*ri->ri_ops.allocattr)(ri, 473 1.34 chris WS_DEFAULT_FG, /* fg */ 474 1.34 chris WS_DEFAULT_BG, /* bg */ 475 1.34 chris 0, /* wsattrs */ 476 1.34 chris &defattr); 477 1.34 chris 478 1.34 chris wsdisplay_cnattach(&vidcvideo_stdscreen, 479 1.34 chris ri, /* emulcookie */ 480 1.34 chris 0, 0, /* cursor position */ 481 1.34 chris defattr); 482 1.34 chris 483 1.34 chris vidcvideo_is_console = true; 484 1.34 chris 485 1.25 bjh21 return 0; 486 1.1 reinoud } 487 1.1 reinoud 488 1.1 reinoud 489 1.1 reinoud static int 490 1.25 bjh21 vidcvideointr(void *arg) 491 1.1 reinoud { 492 1.9 reinoud struct fb_devconfig *dc = arg; 493 1.33 chris 494 1.33 chris return flush_dc_changes_to_screen(dc); 495 1.33 chris } 496 1.33 chris 497 1.33 chris static int 498 1.33 chris flush_dc_changes_to_screen(struct fb_devconfig *dc) 499 1.33 chris { 500 1.9 reinoud int v, cleared = 0; 501 1.1 reinoud 502 1.33 chris v = dc->_internal_dc_changed; 503 1.33 chris 504 1.33 chris if (v == 0) { 505 1.33 chris disable_irq(IRQ_FLYBACK); 506 1.25 bjh21 return 1; 507 1.33 chris } 508 1.1 reinoud 509 1.9 reinoud if (v & WSDISPLAY_WB_COUNTER) { 510 1.9 reinoud dc->dc_writeback_delay--; 511 1.9 reinoud if (dc->dc_writeback_delay == 0) { 512 1.9 reinoud cpu_dcache_wb_range(dc->dc_vaddr, dc->dc_size); 513 1.9 reinoud cleared |= WSDISPLAY_WB_COUNTER; 514 1.25 bjh21 } 515 1.9 reinoud } 516 1.9 reinoud 517 1.1 reinoud if (v & WSDISPLAY_CMAP_DOLUT) { 518 1.9 reinoud struct hwcmap256 *cm = &dc->dc_cmap; 519 1.1 reinoud int index; 520 1.1 reinoud 521 1.9 reinoud if (dc->dc_depth == 4) { 522 1.1 reinoud /* palette for 4 bpp is different from 8bpp */ 523 1.1 reinoud vidcvideo_write(VIDC_PALREG, 0x00000000); 524 1.9 reinoud for (index=0; index < (1 << dc->dc_depth); index++) 525 1.1 reinoud vidcvideo_write(VIDC_PALETTE, 526 1.1 reinoud VIDC_COL(cm->r[index], 527 1.1 reinoud cm->g[index], 528 1.1 reinoud cm->b[index])); 529 1.25 bjh21 } 530 1.1 reinoud 531 1.9 reinoud if (dc->dc_depth == 8) { 532 1.25 bjh21 /* 533 1.25 bjh21 * dunno what to do in more than 8bpp 534 1.25 bjh21 * palettes only make sense in 8bpp and less modes 535 1.25 bjh21 * on VIDC 536 1.25 bjh21 */ 537 1.1 reinoud vidcvideo_write(VIDC_PALREG, 0x00000000); 538 1.1 reinoud for (index = 0; index < CMAP_SIZE; index++) { 539 1.1 reinoud vidcvideo_write(VIDC_PALETTE, 540 1.25 bjh21 VIDC_COL(cm->r[index], cm->g[index], 541 1.25 bjh21 cm->b[index])); 542 1.25 bjh21 } 543 1.25 bjh21 } 544 1.9 reinoud cleared |= WSDISPLAY_CMAP_DOLUT; 545 1.1 reinoud } 546 1.1 reinoud 547 1.1 reinoud if (v & WSDISPLAY_VIDEO_ONOFF) { 548 1.9 reinoud vidcvideo_blank(dc->dc_blanked); 549 1.9 reinoud cleared |= WSDISPLAY_VIDEO_ONOFF; 550 1.25 bjh21 } 551 1.1 reinoud 552 1.1 reinoud if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) { 553 1.1 reinoud int x, y; 554 1.9 reinoud x = dc->dc_cursor.cc_pos.x - dc->dc_cursor.cc_hot.x; 555 1.9 reinoud y = dc->dc_cursor.cc_pos.y - dc->dc_cursor.cc_hot.y; 556 1.1 reinoud 557 1.1 reinoud vidcvideo_updatecursor(x, y); 558 1.9 reinoud cleared |= WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT; 559 1.25 bjh21 } 560 1.1 reinoud 561 1.1 reinoud if (v & WSDISPLAY_CURSOR_DOCUR) { 562 1.9 reinoud vidcvideo_enablecursor(dc->dc_curenb); 563 1.9 reinoud cleared |= WSDISPLAY_CURSOR_DOCUR; 564 1.25 bjh21 } 565 1.1 reinoud 566 1.33 chris dc->_internal_dc_changed ^= cleared; 567 1.33 chris 568 1.33 chris if (dc->_internal_dc_changed == 0) { 569 1.33 chris disable_irq(IRQ_FLYBACK); 570 1.33 chris } 571 1.9 reinoud 572 1.25 bjh21 return 1; 573 1.1 reinoud } 574 1.1 reinoud 575 1.1 reinoud 576 1.33 chris static void vidcvideo_queue_dc_change(struct fb_devconfig *dc, int dc_change) 577 1.33 chris { 578 1.33 chris dc->_internal_dc_changed |= dc_change; 579 1.33 chris 580 1.35 matt if (curcpl() == IPL_HIGH) { 581 1.33 chris /* running in ddb or without interrupts */ 582 1.33 chris dc->dc_writeback_delay = 1; 583 1.33 chris flush_dc_changes_to_screen(dc); 584 1.33 chris } else { 585 1.33 chris /* 586 1.33 chris * running with interrupts so handle this in the next 587 1.33 chris * vsync 588 1.33 chris */ 589 1.33 chris if (dc->dc_ih) { 590 1.33 chris enable_irq(IRQ_FLYBACK); 591 1.33 chris } 592 1.33 chris } 593 1.33 chris } 594 1.33 chris 595 1.33 chris 596 1.35 matt static const u_char ri_col_data[6][6] = { 597 1.1 reinoud { 0, 0, 0, 0, 0, 0}, /* 1 bpp */ 598 1.1 reinoud { 0, 0, 0, 0, 0, 0}, /* 2 bpp */ 599 1.1 reinoud { 0, 0, 0, 0, 0, 0}, /* 4 bpp */ 600 1.1 reinoud { 0, 0, 0, 0, 0, 0}, /* 8 bpp */ 601 1.12 bjh21 { 6, 5, 5, 0, 6, 11}, /* 16 bpp */ 602 1.1 reinoud { 8, 8, 8, 0, 8, 16}, /* 32 bpp */ 603 1.1 reinoud }; 604 1.1 reinoud 605 1.1 reinoud static void 606 1.25 bjh21 vidcvideo_colourmap_and_cursor_init(struct fb_devconfig *dc) 607 1.1 reinoud { 608 1.34 chris struct rasops_info *ri = &dc->dc_console.scr_ri; 609 1.35 matt const u_char *rgbdat; 610 1.34 chris struct hwcmap256 *cm; 611 1.42 skrll const uint8_t *p; 612 1.34 chris int index; 613 1.1 reinoud 614 1.1 reinoud /* Whatever we do later... just make sure we have a 615 1.1 reinoud * sane palette to start with 616 1.1 reinoud */ 617 1.1 reinoud vidcvideo_stdpalette(); 618 1.1 reinoud 619 1.1 reinoud /* set up rgb bit pattern values for rasops_init */ 620 1.1 reinoud rgbdat = ri_col_data[dc->dc_log2_depth]; 621 1.1 reinoud ri->ri_rnum = rgbdat[0]; 622 1.1 reinoud ri->ri_gnum = rgbdat[1]; 623 1.1 reinoud ri->ri_bnum = rgbdat[2]; 624 1.1 reinoud ri->ri_rpos = rgbdat[3]; 625 1.1 reinoud ri->ri_gpos = rgbdat[4]; 626 1.1 reinoud ri->ri_bpos = rgbdat[5]; 627 1.34 chris 628 1.51 andvar /* initialize color map */ 629 1.34 chris cm = &dc->dc_cmap; 630 1.34 chris p = rasops_cmap; 631 1.34 chris for (index = 0; index < CMAP_SIZE; index++, p += 3) { 632 1.34 chris cm->r[index] = p[0]; 633 1.34 chris cm->g[index] = p[1]; 634 1.34 chris cm->b[index] = p[2]; 635 1.34 chris } 636 1.34 chris /* flush to hardware */ 637 1.34 chris vidcvideo_queue_dc_change(dc, WSDISPLAY_CMAP_DOLUT); 638 1.1 reinoud } 639 1.1 reinoud 640 1.1 reinoud 641 1.1 reinoud static int 642 1.25 bjh21 get_cmap(struct vidcvideo_softc *sc, struct wsdisplay_cmap *p) 643 1.1 reinoud { 644 1.1 reinoud u_int index = p->index, count = p->count; 645 1.20 chs int error; 646 1.1 reinoud 647 1.14 itojun if (index >= CMAP_SIZE || count > CMAP_SIZE - index) 648 1.25 bjh21 return EINVAL; 649 1.1 reinoud 650 1.20 chs error = copyout(&sc->sc_dc->dc_cmap.r[index], p->red, count); 651 1.20 chs if (error) 652 1.20 chs return error; 653 1.20 chs error = copyout(&sc->sc_dc->dc_cmap.g[index], p->green, count); 654 1.20 chs if (error) 655 1.20 chs return error; 656 1.20 chs error = copyout(&sc->sc_dc->dc_cmap.b[index], p->blue, count); 657 1.20 chs return error; 658 1.1 reinoud } 659 1.1 reinoud 660 1.1 reinoud 661 1.1 reinoud static int 662 1.25 bjh21 set_cmap(struct vidcvideo_softc *sc, struct wsdisplay_cmap *p) 663 1.1 reinoud { 664 1.9 reinoud struct fb_devconfig *dc = sc->sc_dc; 665 1.20 chs struct hwcmap256 cmap; 666 1.1 reinoud u_int index = p->index, count = p->count; 667 1.20 chs int error; 668 1.1 reinoud 669 1.45 riastrad if (index >= CMAP_SIZE || count > CMAP_SIZE - index) 670 1.25 bjh21 return EINVAL; 671 1.1 reinoud 672 1.20 chs error = copyin(p->red, &cmap.r[index], count); 673 1.20 chs if (error) 674 1.20 chs return error; 675 1.20 chs error = copyin(p->green, &cmap.g[index], count); 676 1.20 chs if (error) 677 1.20 chs return error; 678 1.20 chs error = copyin(p->blue, &cmap.b[index], count); 679 1.20 chs if (error) 680 1.20 chs return error; 681 1.20 chs memcpy(&dc->dc_cmap.r[index], &cmap.r[index], count); 682 1.20 chs memcpy(&dc->dc_cmap.g[index], &cmap.g[index], count); 683 1.20 chs memcpy(&dc->dc_cmap.b[index], &cmap.b[index], count); 684 1.33 chris vidcvideo_queue_dc_change(dc, WSDISPLAY_CMAP_DOLUT); 685 1.25 bjh21 return 0; 686 1.1 reinoud } 687 1.1 reinoud 688 1.1 reinoud 689 1.1 reinoud static int 690 1.25 bjh21 set_cursor(struct vidcvideo_softc *sc, struct wsdisplay_cursor *p) 691 1.1 reinoud { 692 1.9 reinoud #define cc (&dc->dc_cursor) 693 1.9 reinoud struct fb_devconfig *dc = sc->sc_dc; 694 1.20 chs u_int v, index = 0, count = 0, icount = 0; 695 1.20 chs uint8_t r[2], g[2], b[2], image[512], mask[512]; 696 1.20 chs int error; 697 1.19 he 698 1.19 he /* XXX gcc does not detect identical conditions */ 699 1.19 he index = count = icount = 0; 700 1.1 reinoud 701 1.1 reinoud v = p->which; 702 1.1 reinoud if (v & WSDISPLAY_CURSOR_DOCMAP) { 703 1.1 reinoud index = p->cmap.index; 704 1.1 reinoud count = p->cmap.count; 705 1.20 chs if (index >= CURSOR_MAX_COLOURS || 706 1.20 chs (index + count) > CURSOR_MAX_COLOURS) 707 1.25 bjh21 return EINVAL; 708 1.20 chs error = copyin(p->cmap.red, &r[index], count); 709 1.20 chs if (error) 710 1.20 chs return error; 711 1.20 chs error = copyin(p->cmap.green, &g[index], count); 712 1.20 chs if (error) 713 1.20 chs return error; 714 1.20 chs error = copyin(p->cmap.blue, &b[index], count); 715 1.20 chs if (error) 716 1.20 chs return error; 717 1.1 reinoud } 718 1.1 reinoud if (v & WSDISPLAY_CURSOR_DOSHAPE) { 719 1.20 chs if (p->size.x > CURSOR_MAX_WIDTH || 720 1.20 chs p->size.y > CURSOR_MAX_HEIGHT) 721 1.25 bjh21 return EINVAL; 722 1.42 skrll icount = sizeof(uint32_t) * p->size.y; 723 1.20 chs error = copyin(p->image, &image, icount); 724 1.20 chs if (error) 725 1.20 chs return error; 726 1.20 chs error = copyin(p->mask, &mask, icount); 727 1.20 chs if (error) 728 1.20 chs return error; 729 1.1 reinoud } 730 1.1 reinoud 731 1.1 reinoud if (v & WSDISPLAY_CURSOR_DOCUR) 732 1.9 reinoud dc->dc_curenb = p->enable; 733 1.1 reinoud if (v & WSDISPLAY_CURSOR_DOPOS) 734 1.1 reinoud set_curpos(sc, &p->pos); 735 1.1 reinoud if (v & WSDISPLAY_CURSOR_DOHOT) 736 1.1 reinoud cc->cc_hot = p->hot; 737 1.1 reinoud if (v & WSDISPLAY_CURSOR_DOCMAP) { 738 1.20 chs memcpy(&cc->cc_color[index], &r[index], count); 739 1.20 chs memcpy(&cc->cc_color[index + 2], &g[index], count); 740 1.20 chs memcpy(&cc->cc_color[index + 4], &b[index], count); 741 1.1 reinoud } 742 1.1 reinoud if (v & WSDISPLAY_CURSOR_DOSHAPE) { 743 1.1 reinoud cc->cc_size = p->size; 744 1.1 reinoud memset(cc->cc_image, 0, sizeof cc->cc_image); 745 1.20 chs memcpy(cc->cc_image, image, icount); 746 1.1 reinoud memset(cc->cc_mask, 0, sizeof cc->cc_mask); 747 1.20 chs memcpy(cc->cc_mask, mask, icount); 748 1.1 reinoud } 749 1.33 chris vidcvideo_queue_dc_change(dc, v); 750 1.1 reinoud 751 1.25 bjh21 return 0; 752 1.1 reinoud #undef cc 753 1.1 reinoud } 754 1.1 reinoud 755 1.1 reinoud 756 1.1 reinoud static int 757 1.25 bjh21 get_cursor(struct vidcvideo_softc *sc, struct wsdisplay_cursor *p) 758 1.1 reinoud { 759 1.25 bjh21 760 1.25 bjh21 return EPASSTHROUGH; /* XXX */ 761 1.1 reinoud } 762 1.1 reinoud 763 1.1 reinoud 764 1.1 reinoud static void 765 1.25 bjh21 set_curpos(struct vidcvideo_softc *sc, struct wsdisplay_curpos *curpos) 766 1.1 reinoud { 767 1.1 reinoud struct fb_devconfig *dc = sc->sc_dc; 768 1.1 reinoud int x = curpos->x, y = curpos->y; 769 1.1 reinoud 770 1.1 reinoud if (y < 0) 771 1.1 reinoud y = 0; 772 1.34 chris else if (y > dc->dc_height) 773 1.34 chris y = dc->dc_height; 774 1.1 reinoud if (x < 0) 775 1.1 reinoud x = 0; 776 1.34 chris else if (x > dc->dc_width) 777 1.34 chris x = dc->dc_width; 778 1.9 reinoud dc->dc_cursor.cc_pos.x = x; 779 1.9 reinoud dc->dc_cursor.cc_pos.y = y; 780 1.1 reinoud } 781 1.1 reinoud 782 1.1 reinoud 783 1.25 bjh21 static void vv_copyrows(void *id, int srcrow, int dstrow, int nrows) 784 1.1 reinoud { 785 1.1 reinoud struct rasops_info *ri = id; 786 1.44 christos int height, size; 787 1.1 reinoud unsigned char *src, *dst; 788 1.34 chris struct vcons_screen *scr = ri->ri_hw; 789 1.34 chris struct fb_devconfig *dc = (struct fb_devconfig *) (scr->scr_cookie); 790 1.1 reinoud 791 1.51 andvar /* All movements are done in multiples of character heights */ 792 1.1 reinoud height = ri->ri_font->fontheight * nrows; 793 1.1 reinoud size = height * ri->ri_stride; 794 1.1 reinoud 795 1.1 reinoud /* check if we are full screen scrolling */ 796 1.1 reinoud 797 1.34 chris #if 0 798 1.44 christos int scrollup = (srcrow + nrows >= ri->ri_rows); 799 1.44 christos int scrolldown = (dstrow + nrows >= ri->ri_rows); 800 1.25 bjh21 if ((scrollup || scrolldown) && 801 1.25 bjh21 (videomemory.vidm_type == VIDEOMEM_TYPE_VRAM)) { 802 1.44 christos int offset = (srcrow - dstrow) * ri->ri_yscale; 803 1.1 reinoud ri->ri_bits = vidcvideo_hwscroll(offset); 804 1.1 reinoud vidcvideo_progr_scroll(); /* sadistic ; shouldnt this be on vsync? */ 805 1.1 reinoud 806 1.48 andvar /* wipe out remains of the screen if necessary */ 807 1.25 bjh21 if (ri->ri_emuheight != ri->ri_height) 808 1.25 bjh21 vv_eraserows(id, ri->ri_rows, 1, 0); 809 1.1 reinoud return; 810 1.25 bjh21 } 811 1.34 chris #endif 812 1.1 reinoud 813 1.25 bjh21 /* 814 1.25 bjh21 * Else we just copy the area : we're braindead for now 815 1.51 andvar * Note: we can't use hardware scrolling when the softc isn't 816 1.51 andvar * known yet... if it's not known we don't have interrupts and 817 1.25 bjh21 * we can't change the display address reliable other than in 818 1.25 bjh21 * a Vsync 819 1.1 reinoud */ 820 1.1 reinoud 821 1.1 reinoud src = ri->ri_bits + srcrow * ri->ri_font->fontheight * ri->ri_stride; 822 1.1 reinoud dst = ri->ri_bits + dstrow * ri->ri_font->fontheight * ri->ri_stride; 823 1.1 reinoud 824 1.32 chris memmove(dst, src, size); 825 1.33 chris 826 1.33 chris /* delay the write back operation of the screen area */ 827 1.33 chris dc->dc_writeback_delay = SCREEN_WRITE_BACK_DELAY; 828 1.33 chris vidcvideo_queue_dc_change(dc, WSDISPLAY_WB_COUNTER); 829 1.1 reinoud } 830 1.1 reinoud 831 1.1 reinoud 832 1.25 bjh21 static void vv_eraserows(void *id, int startrow, int nrows, long attr) 833 1.1 reinoud { 834 1.1 reinoud struct rasops_info *ri = id; 835 1.1 reinoud int height; 836 1.1 reinoud unsigned char *src; 837 1.34 chris struct vcons_screen *scr = ri->ri_hw; 838 1.34 chris struct fb_devconfig *dc = (struct fb_devconfig *) (scr->scr_cookie); 839 1.1 reinoud 840 1.1 reinoud /* we're braindead for now */ 841 1.1 reinoud height = ri->ri_font->fontheight * nrows * ri->ri_stride; 842 1.1 reinoud 843 1.1 reinoud src = ri->ri_bits + startrow * ri->ri_font->fontheight * ri->ri_stride; 844 1.1 reinoud 845 1.26 bjh21 memset(src, 0, height); 846 1.33 chris 847 1.33 chris /* delay the write back operation of the screen area */ 848 1.33 chris dc->dc_writeback_delay = SCREEN_WRITE_BACK_DELAY; 849 1.33 chris vidcvideo_queue_dc_change(dc, WSDISPLAY_WB_COUNTER); 850 1.6 reinoud } 851 1.6 reinoud 852 1.6 reinoud 853 1.25 bjh21 static void vv_putchar(void *id, int row, int col, u_int uc, long attr) 854 1.6 reinoud { 855 1.6 reinoud struct rasops_info *ri = id; 856 1.34 chris struct vcons_screen *scr = ri->ri_hw; 857 1.34 chris struct fb_devconfig *dc = (struct fb_devconfig *) (scr->scr_cookie); 858 1.9 reinoud 859 1.33 chris /* just delegate */ 860 1.33 chris dc->orig_ri_ops.putchar(id, row, col, uc, attr); 861 1.33 chris 862 1.9 reinoud /* delay the write back operation of the screen area */ 863 1.9 reinoud dc->dc_writeback_delay = SCREEN_WRITE_BACK_DELAY; 864 1.33 chris vidcvideo_queue_dc_change(dc, WSDISPLAY_WB_COUNTER); 865 1.1 reinoud } 866