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