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