1 /* $NetBSD: vidcvideo.c,v 1.44 2014/01/21 19:31:57 christos 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.44 2014/01/21 19:31:57 christos 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 device_t sc_dev; 123 struct fb_devconfig *sc_dc; /* device configuration */ 124 }; 125 126 127 /* Function prototypes for glue */ 128 static int vidcvideo_match(device_t , cfdata_t , void *); 129 static void vidcvideo_attach(device_t , device_t , void *); 130 131 132 /* config glue */ 133 CFATTACH_DECL_NEW(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(device_t parent, cfdata_t 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(device_t parent, device_t self, void *aux) 310 { 311 struct vidcvideo_softc *sc = device_private(self); 312 struct fb_devconfig *dc; 313 struct wsemuldisplaydev_attach_args waa; 314 long defattr; 315 316 sc->sc_dev = self; 317 318 dc = sc->sc_dc = &vidcvideo_console_dc; 319 320 /* 321 * for reasons which are crazy we init vidcvideo twice, 322 * the second time sets up the cursor 323 */ 324 vidcvideo_init(); 325 if (!vidcvideo_is_console) { 326 vidcvideo_getdevconfig(videomemory.vidm_vbase, 327 videomemory.vidm_size, 328 sc->sc_dc); 329 } 330 331 vcons_init(&dc->dc_vd, dc, &vidcvideo_stdscreen, &vidcvideo_accessops); 332 dc->dc_vd.init_screen = vidcvideoinit_screen; 333 334 vcons_init_screen(&dc->dc_vd, &dc->dc_console, 1, &defattr); 335 336 dc->dc_console.scr_flags |= VCONS_SCREEN_IS_STATIC; 337 338 vidcvideo_printdetails(); 339 aprint_normal(": mode %s, %dbpp\n", dc->mode_info.timings.name, 340 dc->dc_depth); 341 342 /* set up interrupt flags */ 343 vidcvideo_queue_dc_change(dc, WSDISPLAY_CMAP_DOLUT); 344 345 /* Establish an interrupt handler, and clear any pending interrupts */ 346 dc->dc_ih = intr_claim(IRQ_FLYBACK, IPL_TTY, "vblank", vidcvideointr, dc); 347 348 waa.console = (vidcvideo_is_console ? 1 : 0); 349 waa.scrdata = &vidcvideo_screenlist; 350 waa.accessops = &vidcvideo_accessops; 351 waa.accesscookie = &dc->dc_vd; 352 353 config_found(self, &waa, wsemuldisplaydevprint); 354 } 355 356 357 static int 358 vidcvideoioctl(void *v, void *vs, u_long cmd, void *data, int flag, 359 struct lwp *l) 360 { 361 struct vcons_data *vd = v; 362 struct vidcvideo_softc *sc = vd->cookie; 363 struct fb_devconfig *dc = sc->sc_dc; 364 struct vcons_screen *ms = vd->active; 365 int state; 366 367 switch (cmd) { 368 case WSDISPLAYIO_GTYPE: 369 *(u_int *)data = WSDISPLAY_TYPE_VIDC; 370 return 0; 371 372 case WSDISPLAYIO_GINFO: 373 if (ms == NULL) 374 return ENODEV; 375 #define wsd_fbip ((struct wsdisplay_fbinfo *)data) 376 wsd_fbip->height = dc->dc_height; 377 wsd_fbip->width = dc->dc_width; 378 wsd_fbip->depth = dc->dc_depth; 379 wsd_fbip->cmsize = CMAP_SIZE; 380 #undef fbt 381 return 0; 382 383 case WSDISPLAYIO_GETCMAP: 384 return get_cmap(sc, (struct wsdisplay_cmap *)data); 385 386 case WSDISPLAYIO_PUTCMAP: 387 return set_cmap(sc, (struct wsdisplay_cmap *)data); 388 389 case WSDISPLAYIO_LINEBYTES: 390 *(u_int *)data = dc->dc_rowbytes; 391 return 0; 392 393 case WSDISPLAYIO_SVIDEO: 394 state = *(int *)data; 395 dc->dc_blanked = (state == WSDISPLAYIO_VIDEO_OFF); 396 vidcvideo_queue_dc_change(dc, WSDISPLAY_VIDEO_ONOFF); 397 /* done on video blank */ 398 return 0; 399 400 case WSDISPLAYIO_GVIDEO: 401 *(u_int *)data = dc->dc_blanked ? 402 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON; 403 return 0; 404 405 case WSDISPLAYIO_GCURPOS: 406 *(struct wsdisplay_curpos *)data = dc->dc_cursor.cc_pos; 407 return 0; 408 409 case WSDISPLAYIO_SCURPOS: 410 set_curpos(sc, (struct wsdisplay_curpos *)data); 411 vidcvideo_queue_dc_change(dc, WSDISPLAY_CURSOR_DOPOS); 412 return 0; 413 414 case WSDISPLAYIO_GCURMAX: 415 ((struct wsdisplay_curpos *)data)->x = CURSOR_MAX_WIDTH; 416 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_HEIGHT; 417 return 0; 418 419 case WSDISPLAYIO_GCURSOR: 420 return get_cursor(sc, (struct wsdisplay_cursor *)data); 421 422 case WSDISPLAYIO_SCURSOR: 423 return set_cursor(sc, (struct wsdisplay_cursor *)data); 424 425 case WSDISPLAYIO_SMODE: 426 state = *(int *)data; 427 if (state == WSDISPLAYIO_MODE_MAPPED) 428 dc->dc_hwscroll_cookie = vidcvideo_hwscroll_reset(); 429 if (state == WSDISPLAYIO_MODE_EMUL) 430 vidcvideo_hwscroll_back(dc->dc_hwscroll_cookie); 431 vidcvideo_progr_scroll(); 432 433 return 0; 434 } 435 return EPASSTHROUGH; 436 } 437 438 439 paddr_t 440 vidcvideommap(void *v, void *vs, off_t offset, int prot) 441 { 442 struct vcons_data *vd = v; 443 struct vidcvideo_softc *sc = vd->cookie; 444 445 if (offset >= sc->sc_dc->dc_size || offset < 0) 446 return -1; 447 448 return arm_btop(sc->sc_dc->dc_paddr + offset); 449 } 450 451 452 /* EXPORT */ int 453 vidcvideo_cnattach(vaddr_t addr) 454 { 455 struct fb_devconfig *dc = &vidcvideo_console_dc; 456 struct rasops_info *ri; 457 long defattr; 458 459 vidcvideo_init(); 460 461 /* fetch current framebuffer config */ 462 vidcvideo_getdevconfig(videomemory.vidm_vbase, 463 videomemory.vidm_size, 464 dc); 465 466 dc->dc_vd.active = NULL; 467 vidcvideoinit_screen(dc, &dc->dc_console, 1, &defattr); 468 469 ri = &(dc->dc_console.scr_ri); 470 ri->ri_hw = &dc->dc_console; 471 dc->dc_console.scr_cookie = dc; 472 473 (*ri->ri_ops.allocattr)(ri, 474 WS_DEFAULT_FG, /* fg */ 475 WS_DEFAULT_BG, /* bg */ 476 0, /* wsattrs */ 477 &defattr); 478 479 wsdisplay_cnattach(&vidcvideo_stdscreen, 480 ri, /* emulcookie */ 481 0, 0, /* cursor position */ 482 defattr); 483 484 vidcvideo_is_console = true; 485 486 return 0; 487 } 488 489 490 static int 491 vidcvideointr(void *arg) 492 { 493 struct fb_devconfig *dc = arg; 494 495 return flush_dc_changes_to_screen(dc); 496 } 497 498 static int 499 flush_dc_changes_to_screen(struct fb_devconfig *dc) 500 { 501 int v, cleared = 0; 502 503 v = dc->_internal_dc_changed; 504 505 if (v == 0) { 506 disable_irq(IRQ_FLYBACK); 507 return 1; 508 } 509 510 if (v & WSDISPLAY_WB_COUNTER) { 511 dc->dc_writeback_delay--; 512 if (dc->dc_writeback_delay == 0) { 513 cpu_dcache_wb_range(dc->dc_vaddr, dc->dc_size); 514 cleared |= WSDISPLAY_WB_COUNTER; 515 } 516 } 517 518 if (v & WSDISPLAY_CMAP_DOLUT) { 519 struct hwcmap256 *cm = &dc->dc_cmap; 520 int index; 521 522 if (dc->dc_depth == 4) { 523 /* palette for 4 bpp is different from 8bpp */ 524 vidcvideo_write(VIDC_PALREG, 0x00000000); 525 for (index=0; index < (1 << dc->dc_depth); index++) 526 vidcvideo_write(VIDC_PALETTE, 527 VIDC_COL(cm->r[index], 528 cm->g[index], 529 cm->b[index])); 530 } 531 532 if (dc->dc_depth == 8) { 533 /* 534 * dunno what to do in more than 8bpp 535 * palettes only make sense in 8bpp and less modes 536 * on VIDC 537 */ 538 vidcvideo_write(VIDC_PALREG, 0x00000000); 539 for (index = 0; index < CMAP_SIZE; index++) { 540 vidcvideo_write(VIDC_PALETTE, 541 VIDC_COL(cm->r[index], cm->g[index], 542 cm->b[index])); 543 } 544 } 545 cleared |= WSDISPLAY_CMAP_DOLUT; 546 } 547 548 if (v & WSDISPLAY_VIDEO_ONOFF) { 549 vidcvideo_blank(dc->dc_blanked); 550 cleared |= WSDISPLAY_VIDEO_ONOFF; 551 } 552 553 if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) { 554 int x, y; 555 x = dc->dc_cursor.cc_pos.x - dc->dc_cursor.cc_hot.x; 556 y = dc->dc_cursor.cc_pos.y - dc->dc_cursor.cc_hot.y; 557 558 vidcvideo_updatecursor(x, y); 559 cleared |= WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT; 560 } 561 562 if (v & WSDISPLAY_CURSOR_DOCUR) { 563 vidcvideo_enablecursor(dc->dc_curenb); 564 cleared |= WSDISPLAY_CURSOR_DOCUR; 565 } 566 567 dc->_internal_dc_changed ^= cleared; 568 569 if (dc->_internal_dc_changed == 0) { 570 disable_irq(IRQ_FLYBACK); 571 } 572 573 return 1; 574 } 575 576 577 static void vidcvideo_queue_dc_change(struct fb_devconfig *dc, int dc_change) 578 { 579 dc->_internal_dc_changed |= dc_change; 580 581 if (curcpl() == IPL_HIGH) { 582 /* running in ddb or without interrupts */ 583 dc->dc_writeback_delay = 1; 584 flush_dc_changes_to_screen(dc); 585 } else { 586 /* 587 * running with interrupts so handle this in the next 588 * vsync 589 */ 590 if (dc->dc_ih) { 591 enable_irq(IRQ_FLYBACK); 592 } 593 } 594 } 595 596 597 static const u_char ri_col_data[6][6] = { 598 { 0, 0, 0, 0, 0, 0}, /* 1 bpp */ 599 { 0, 0, 0, 0, 0, 0}, /* 2 bpp */ 600 { 0, 0, 0, 0, 0, 0}, /* 4 bpp */ 601 { 0, 0, 0, 0, 0, 0}, /* 8 bpp */ 602 { 6, 5, 5, 0, 6, 11}, /* 16 bpp */ 603 { 8, 8, 8, 0, 8, 16}, /* 32 bpp */ 604 }; 605 606 static void 607 vidcvideo_colourmap_and_cursor_init(struct fb_devconfig *dc) 608 { 609 struct rasops_info *ri = &dc->dc_console.scr_ri; 610 const u_char *rgbdat; 611 struct hwcmap256 *cm; 612 const uint8_t *p; 613 int index; 614 615 /* Whatever we do later... just make sure we have a 616 * sane palette to start with 617 */ 618 vidcvideo_stdpalette(); 619 620 /* set up rgb bit pattern values for rasops_init */ 621 rgbdat = ri_col_data[dc->dc_log2_depth]; 622 ri->ri_rnum = rgbdat[0]; 623 ri->ri_gnum = rgbdat[1]; 624 ri->ri_bnum = rgbdat[2]; 625 ri->ri_rpos = rgbdat[3]; 626 ri->ri_gpos = rgbdat[4]; 627 ri->ri_bpos = rgbdat[5]; 628 629 /* initialise color map */ 630 cm = &dc->dc_cmap; 631 p = rasops_cmap; 632 for (index = 0; index < CMAP_SIZE; index++, p += 3) { 633 cm->r[index] = p[0]; 634 cm->g[index] = p[1]; 635 cm->b[index] = p[2]; 636 } 637 /* flush to hardware */ 638 vidcvideo_queue_dc_change(dc, WSDISPLAY_CMAP_DOLUT); 639 } 640 641 642 static int 643 get_cmap(struct vidcvideo_softc *sc, struct wsdisplay_cmap *p) 644 { 645 u_int index = p->index, count = p->count; 646 int error; 647 648 if (index >= CMAP_SIZE || count > CMAP_SIZE - index) 649 return EINVAL; 650 651 error = copyout(&sc->sc_dc->dc_cmap.r[index], p->red, count); 652 if (error) 653 return error; 654 error = copyout(&sc->sc_dc->dc_cmap.g[index], p->green, count); 655 if (error) 656 return error; 657 error = copyout(&sc->sc_dc->dc_cmap.b[index], p->blue, count); 658 return error; 659 } 660 661 662 static int 663 set_cmap(struct vidcvideo_softc *sc, struct wsdisplay_cmap *p) 664 { 665 struct fb_devconfig *dc = sc->sc_dc; 666 struct hwcmap256 cmap; 667 u_int index = p->index, count = p->count; 668 int error; 669 670 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE) 671 return EINVAL; 672 673 error = copyin(p->red, &cmap.r[index], count); 674 if (error) 675 return error; 676 error = copyin(p->green, &cmap.g[index], count); 677 if (error) 678 return error; 679 error = copyin(p->blue, &cmap.b[index], count); 680 if (error) 681 return error; 682 memcpy(&dc->dc_cmap.r[index], &cmap.r[index], count); 683 memcpy(&dc->dc_cmap.g[index], &cmap.g[index], count); 684 memcpy(&dc->dc_cmap.b[index], &cmap.b[index], count); 685 vidcvideo_queue_dc_change(dc, WSDISPLAY_CMAP_DOLUT); 686 return 0; 687 } 688 689 690 static int 691 set_cursor(struct vidcvideo_softc *sc, struct wsdisplay_cursor *p) 692 { 693 #define cc (&dc->dc_cursor) 694 struct fb_devconfig *dc = sc->sc_dc; 695 u_int v, index = 0, count = 0, icount = 0; 696 uint8_t r[2], g[2], b[2], image[512], mask[512]; 697 int error; 698 699 /* XXX gcc does not detect identical conditions */ 700 index = count = icount = 0; 701 702 v = p->which; 703 if (v & WSDISPLAY_CURSOR_DOCMAP) { 704 index = p->cmap.index; 705 count = p->cmap.count; 706 if (index >= CURSOR_MAX_COLOURS || 707 (index + count) > CURSOR_MAX_COLOURS) 708 return EINVAL; 709 error = copyin(p->cmap.red, &r[index], count); 710 if (error) 711 return error; 712 error = copyin(p->cmap.green, &g[index], count); 713 if (error) 714 return error; 715 error = copyin(p->cmap.blue, &b[index], count); 716 if (error) 717 return error; 718 } 719 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 720 if (p->size.x > CURSOR_MAX_WIDTH || 721 p->size.y > CURSOR_MAX_HEIGHT) 722 return EINVAL; 723 icount = sizeof(uint32_t) * p->size.y; 724 error = copyin(p->image, &image, icount); 725 if (error) 726 return error; 727 error = copyin(p->mask, &mask, icount); 728 if (error) 729 return error; 730 } 731 732 if (v & WSDISPLAY_CURSOR_DOCUR) 733 dc->dc_curenb = p->enable; 734 if (v & WSDISPLAY_CURSOR_DOPOS) 735 set_curpos(sc, &p->pos); 736 if (v & WSDISPLAY_CURSOR_DOHOT) 737 cc->cc_hot = p->hot; 738 if (v & WSDISPLAY_CURSOR_DOCMAP) { 739 memcpy(&cc->cc_color[index], &r[index], count); 740 memcpy(&cc->cc_color[index + 2], &g[index], count); 741 memcpy(&cc->cc_color[index + 4], &b[index], count); 742 } 743 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 744 cc->cc_size = p->size; 745 memset(cc->cc_image, 0, sizeof cc->cc_image); 746 memcpy(cc->cc_image, image, icount); 747 memset(cc->cc_mask, 0, sizeof cc->cc_mask); 748 memcpy(cc->cc_mask, mask, icount); 749 } 750 vidcvideo_queue_dc_change(dc, v); 751 752 return 0; 753 #undef cc 754 } 755 756 757 static int 758 get_cursor(struct vidcvideo_softc *sc, struct wsdisplay_cursor *p) 759 { 760 761 return EPASSTHROUGH; /* XXX */ 762 } 763 764 765 static void 766 set_curpos(struct vidcvideo_softc *sc, struct wsdisplay_curpos *curpos) 767 { 768 struct fb_devconfig *dc = sc->sc_dc; 769 int x = curpos->x, y = curpos->y; 770 771 if (y < 0) 772 y = 0; 773 else if (y > dc->dc_height) 774 y = dc->dc_height; 775 if (x < 0) 776 x = 0; 777 else if (x > dc->dc_width) 778 x = dc->dc_width; 779 dc->dc_cursor.cc_pos.x = x; 780 dc->dc_cursor.cc_pos.y = y; 781 } 782 783 784 static void vv_copyrows(void *id, int srcrow, int dstrow, int nrows) 785 { 786 struct rasops_info *ri = id; 787 int height, size; 788 unsigned char *src, *dst; 789 struct vcons_screen *scr = ri->ri_hw; 790 struct fb_devconfig *dc = (struct fb_devconfig *) (scr->scr_cookie); 791 792 /* All movements are done in multiples of character heigths */ 793 height = ri->ri_font->fontheight * nrows; 794 size = height * ri->ri_stride; 795 796 /* check if we are full screen scrolling */ 797 798 #if 0 799 int scrollup = (srcrow + nrows >= ri->ri_rows); 800 int scrolldown = (dstrow + nrows >= ri->ri_rows); 801 if ((scrollup || scrolldown) && 802 (videomemory.vidm_type == VIDEOMEM_TYPE_VRAM)) { 803 int offset = (srcrow - dstrow) * ri->ri_yscale; 804 ri->ri_bits = vidcvideo_hwscroll(offset); 805 vidcvideo_progr_scroll(); /* sadistic ; shouldnt this be on vsync? */ 806 807 /* wipe out remains of the screen if nessisary */ 808 if (ri->ri_emuheight != ri->ri_height) 809 vv_eraserows(id, ri->ri_rows, 1, 0); 810 return; 811 } 812 #endif 813 814 /* 815 * Else we just copy the area : we're braindead for now 816 * Note: we can't use hardware scrolling when the softc isnt 817 * known yet... if its not known we dont have interrupts and 818 * we can't change the display address reliable other than in 819 * a Vsync 820 */ 821 822 src = ri->ri_bits + srcrow * ri->ri_font->fontheight * ri->ri_stride; 823 dst = ri->ri_bits + dstrow * ri->ri_font->fontheight * ri->ri_stride; 824 825 memmove(dst, src, size); 826 827 /* delay the write back operation of the screen area */ 828 dc->dc_writeback_delay = SCREEN_WRITE_BACK_DELAY; 829 vidcvideo_queue_dc_change(dc, WSDISPLAY_WB_COUNTER); 830 } 831 832 833 static void vv_eraserows(void *id, int startrow, int nrows, long attr) 834 { 835 struct rasops_info *ri = id; 836 int height; 837 unsigned char *src; 838 struct vcons_screen *scr = ri->ri_hw; 839 struct fb_devconfig *dc = (struct fb_devconfig *) (scr->scr_cookie); 840 841 /* we're braindead for now */ 842 height = ri->ri_font->fontheight * nrows * ri->ri_stride; 843 844 src = ri->ri_bits + startrow * ri->ri_font->fontheight * ri->ri_stride; 845 846 memset(src, 0, height); 847 848 /* delay the write back operation of the screen area */ 849 dc->dc_writeback_delay = SCREEN_WRITE_BACK_DELAY; 850 vidcvideo_queue_dc_change(dc, WSDISPLAY_WB_COUNTER); 851 } 852 853 854 static void vv_putchar(void *id, int row, int col, u_int uc, long attr) 855 { 856 struct rasops_info *ri = id; 857 struct vcons_screen *scr = ri->ri_hw; 858 struct fb_devconfig *dc = (struct fb_devconfig *) (scr->scr_cookie); 859 860 /* just delegate */ 861 dc->orig_ri_ops.putchar(id, row, col, uc, attr); 862 863 /* delay the write back operation of the screen area */ 864 dc->dc_writeback_delay = SCREEN_WRITE_BACK_DELAY; 865 vidcvideo_queue_dc_change(dc, WSDISPLAY_WB_COUNTER); 866 } 867