1 /* $NetBSD: pm.c,v 1.19 2023/02/11 18:30:45 tsutsui Exp $ */ 2 3 /*- 4 * Copyright (c) 2002, 2003 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Andrew Doran. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: pm.c,v 1.19 2023/02/11 18:30:45 tsutsui Exp $"); 34 35 #include <sys/param.h> 36 #include <sys/buf.h> 37 #include <sys/bus.h> 38 #include <sys/device.h> 39 #include <sys/ioctl.h> 40 #include <sys/intr.h> 41 #include <sys/kernel.h> 42 #include <sys/systm.h> 43 44 #include <dev/wscons/wsconsio.h> 45 #include <dev/wscons/wsdisplayvar.h> 46 #include <dev/rasops/rasops.h> 47 #include <dev/wsfont/wsfont.h> 48 49 #include <dev/ic/dc503reg.h> 50 51 #include <pmax/pmax/kn01.h> 52 53 #include <pmax/ibus/ibusvar.h> 54 #include <pmax/ibus/pmreg.h> 55 56 #include <uvm/uvm_extern.h> 57 58 #define CURSOR_MAX_SIZE 16 59 60 struct hwcmap256 { 61 uint8_t r[256]; 62 uint8_t g[256]; 63 uint8_t b[256]; 64 }; 65 66 struct hwcursor64 { 67 struct wsdisplay_curpos cc_pos; 68 struct wsdisplay_curpos cc_hot; 69 struct wsdisplay_curpos cc_size; 70 uint8_t cc_color[6]; 71 72 /* 73 * Max cursor size is 16x16. The X server pads bitmap scanlines to 74 * a word boundary. We take the easy route and waste some space. 75 */ 76 u_short cc_image[32 + 32]; 77 }; 78 79 struct pm_softc { 80 device_t sc_dev; 81 size_t sc_cmap_size; 82 size_t sc_fb_size; 83 int sc_type; 84 int sc_blanked; 85 int sc_curenb; 86 int sc_changed; 87 int sc_nscreens; 88 struct hwcursor64 sc_cursor; 89 struct hwcmap256 sc_cmap; 90 }; 91 #define WSDISPLAY_CMAP_DOLUT 0x20 92 93 int pm_match(device_t, cfdata_t, void *); 94 void pm_attach(device_t, device_t, void *); 95 int pm_check_vfb(void); 96 int pm_ioctl(void *, void *, u_long, void *, int, struct lwp *); 97 paddr_t pm_mmap(void *, void *, off_t, int); 98 int pm_alloc_screen(void *, const struct wsscreen_descr *, 99 void **, int *, int *, long *); 100 void pm_free_screen(void *, void *); 101 int pm_show_screen(void *, void *, int, 102 void (*) (void *, int, int), void *); 103 void pm_cursor_off(void); 104 void pm_cursor_on(struct pm_softc *); 105 int pm_cnattach(void); 106 void pm_common_init(void); 107 int pm_flush(struct pm_softc *); 108 int pm_get_cmap(struct pm_softc *, struct wsdisplay_cmap *); 109 int pm_set_cmap(struct pm_softc *, struct wsdisplay_cmap *); 110 int pm_set_cursor(struct pm_softc *, struct wsdisplay_cursor *); 111 int pm_get_cursor(struct pm_softc *, struct wsdisplay_cursor *); 112 void pm_set_curpos(struct pm_softc *, struct wsdisplay_curpos *); 113 void pm_init_cmap(struct pm_softc *); 114 115 CFATTACH_DECL_NEW(pm, sizeof(struct pm_softc), 116 pm_match, pm_attach, NULL, NULL); 117 118 struct rasops_info pm_ri; 119 120 struct wsscreen_descr pm_stdscreen = { 121 "std", 0, 0, 122 0, /* textops */ 123 0, 0, 124 WSSCREEN_REVERSE 125 }; 126 127 const struct wsscreen_descr *_pm_scrlist[] = { 128 &pm_stdscreen, 129 }; 130 131 const struct wsscreen_list pm_screenlist = { 132 sizeof(_pm_scrlist) / sizeof(struct wsscreen_descr *), _pm_scrlist 133 }; 134 135 const struct wsdisplay_accessops pm_accessops = { 136 pm_ioctl, 137 pm_mmap, 138 pm_alloc_screen, 139 pm_free_screen, 140 pm_show_screen, 141 0 /* load_font */ 142 }; 143 144 u_int pm_creg; 145 146 int 147 pm_match(device_t parent, cfdata_t cf, void *aux) 148 { 149 struct ibus_attach_args *ia; 150 void *pmaddr; 151 152 ia = aux; 153 pmaddr = (void *)ia->ia_addr; 154 155 if (strcmp(ia->ia_name, "pm") != 0) 156 return (0); 157 158 if (badaddr(pmaddr, 4)) 159 return (0); 160 161 return (1); 162 } 163 164 void 165 pm_attach(device_t parent, device_t self, void *aux) 166 { 167 struct pm_softc *sc; 168 struct rasops_info *ri; 169 struct wsemuldisplaydev_attach_args waa; 170 int console; 171 172 sc = device_private(self); 173 sc->sc_dev = self; 174 ri = &pm_ri; 175 console = (ri->ri_bits != NULL); 176 177 if (console) { 178 sc->sc_nscreens = 1; 179 ri->ri_flg &= ~RI_NO_AUTO; 180 } else if (!pm_check_vfb()) { 181 printf(": VFB01/VFB02 frame buffer option not found\n"); 182 return; 183 } else 184 pm_common_init(); 185 186 printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth); 187 188 pm_init_cmap(sc); 189 190 sc->sc_blanked = 0; 191 sc->sc_curenb = 0; 192 193 waa.console = console; 194 waa.scrdata = &pm_screenlist; 195 waa.accessops = &pm_accessops; 196 waa.accesscookie = sc; 197 198 config_found(self, &waa, wsemuldisplaydevprint, CFARGS_NONE); 199 } 200 201 int 202 pm_check_vfb(void) 203 { 204 int *mem; 205 const int magic = 0xcafebabe; 206 207 mem = (void *)MIPS_PHYS_TO_KSEG1(KN01_PHYS_FBUF_START); 208 209 *mem = magic; 210 wbflush(); 211 if (*mem != magic) 212 return 0; 213 214 *mem = ~magic; 215 wbflush(); 216 if (*mem != ~magic) 217 return 0; 218 219 return 1; 220 } 221 222 void 223 pm_init_cmap(struct pm_softc *sc) 224 { 225 struct hwcmap256 *cm; 226 struct rasops_info *ri; 227 const uint8_t *p; 228 int index; 229 230 cm = &sc->sc_cmap; 231 ri = &pm_ri; 232 233 if (ri->ri_depth == 8) { 234 p = rasops_cmap; 235 for (index = 0; index < 256; index++, p += 3) { 236 cm->r[index] = p[0]; 237 cm->g[index] = p[1]; 238 cm->b[index] = p[2]; 239 } 240 241 sc->sc_type = WSDISPLAY_TYPE_PM_COLOR; 242 sc->sc_cmap_size = 256; 243 sc->sc_fb_size = 0x100000; 244 } else { 245 cm->r[0] = 0x00; 246 cm->g[0] = 0x00; 247 cm->b[0] = 0x00; 248 249 cm->r[1] = 0x00; 250 cm->g[1] = 0xff; 251 cm->b[1] = 0x00; 252 253 sc->sc_type = WSDISPLAY_TYPE_PM_MONO; 254 sc->sc_cmap_size = 2; 255 sc->sc_fb_size = 0x40000; 256 } 257 } 258 259 void 260 pm_common_init(void) 261 { 262 struct rasops_info *ri; 263 int cookie, bior, i; 264 struct dc503reg *pcc; 265 VDACRegs *vdac; 266 uint16_t kn01csr; 267 268 kn01csr = *(volatile uint16_t *)MIPS_PHYS_TO_KSEG1(KN01_SYS_CSR); 269 pcc = (void *)MIPS_PHYS_TO_KSEG1(KN01_SYS_PCC); 270 vdac = (void *)MIPS_PHYS_TO_KSEG1(KN01_SYS_VDAC); 271 ri = &pm_ri; 272 273 ri->ri_flg = RI_CENTER; 274 if (ri->ri_bits == NULL) 275 ri->ri_flg |= RI_NO_AUTO; 276 ri->ri_depth = ((kn01csr & KN01_CSR_MONO) != 0 ? 1 : 8); 277 ri->ri_width = 1024; 278 ri->ri_height = 864; 279 ri->ri_stride = (ri->ri_depth == 8 ? 1024 : 2048 / 8); 280 ri->ri_bits = (void *)MIPS_PHYS_TO_KSEG1(KN01_PHYS_FBUF_START); 281 282 /* 283 * Clear the screen. 284 */ 285 memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height); 286 287 /* 288 * Get a font to use. 289 */ 290 bior = (ri->ri_depth == 8 ? WSDISPLAY_FONTORDER_L2R : 291 WSDISPLAY_FONTORDER_R2L); 292 293 wsfont_init(); 294 if (ri->ri_depth == 8) 295 cookie = wsfont_find(NULL, 12, 0, 0, bior, 296 WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP); 297 else 298 cookie = wsfont_find(NULL, 8, 0, 0, bior, 299 WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP); 300 if (cookie <= 0) 301 cookie = wsfont_find(NULL, 0, 0, 0, bior, 302 WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP); 303 if (cookie <= 0) { 304 printf("pm: font table is empty\n"); 305 return; 306 } 307 308 if (wsfont_lock(cookie, &ri->ri_font)) { 309 printf("pm: couldn't lock font\n"); 310 return; 311 } 312 ri->ri_wsfcookie = cookie; 313 314 /* 315 * Set up the raster operations set. 316 */ 317 rasops_init(ri, 1000, 1000); 318 319 pm_stdscreen.nrows = ri->ri_rows; 320 pm_stdscreen.ncols = ri->ri_cols; 321 pm_stdscreen.textops = &ri->ri_ops; 322 pm_stdscreen.capabilities = ri->ri_caps; 323 324 /* 325 * Initialize the VDAC. 326 */ 327 *(uint8_t *)MIPS_PHYS_TO_KSEG1(KN01_PHYS_COLMASK_START) = 0xff; 328 wbflush(); 329 330 vdac->overWA = 0x04; wbflush(); 331 vdac->over = 0x00; wbflush(); 332 vdac->over = 0x00; wbflush(); 333 vdac->over = 0x00; wbflush(); 334 vdac->overWA = 0x08; wbflush(); 335 vdac->over = 0x00; wbflush(); 336 vdac->over = 0x00; wbflush(); 337 vdac->over = 0x7f; wbflush(); 338 vdac->overWA = 0x0c; wbflush(); 339 vdac->over = 0xff; wbflush(); 340 vdac->over = 0xff; wbflush(); 341 vdac->over = 0xff; wbflush(); 342 343 /* 344 * Set in the initial colormap. 345 */ 346 if (ri->ri_depth == 8) { 347 vdac->mapWA = 0; 348 wbflush(); 349 350 for (i = 0; i < 256 * 3; i += 3) { 351 vdac->map = rasops_cmap[i]; 352 wbflush(); 353 vdac->map = rasops_cmap[i + 1]; 354 wbflush(); 355 vdac->map = rasops_cmap[i + 2]; 356 wbflush(); 357 } 358 } else { 359 vdac->mapWA = 0; 360 wbflush(); 361 362 for (i = 0; i < 256; i++) { 363 vdac->map = 0x00; 364 wbflush(); 365 vdac->map = (i < 128 ? 0x00 : 0xff); 366 wbflush(); 367 vdac->map = 0x00; 368 wbflush(); 369 } 370 } 371 372 /* 373 * Turn off the hardware cursor sprite for text mode. 374 */ 375 pcc->cmdr = PCCCMD_FOPB | PCCCMD_VBHI; 376 wbflush(); 377 pm_creg = 0; 378 pm_cursor_off(); 379 } 380 381 void 382 pm_cursor_off(void) 383 { 384 struct dc503reg *pcc; 385 386 pcc = (void *)MIPS_PHYS_TO_KSEG1(KN01_SYS_PCC); 387 pcc->cmdr = (pm_creg &= ~(PCCCMD_ENPA | PCCCMD_ENPB)); 388 wbflush(); 389 } 390 391 void 392 pm_cursor_on(struct pm_softc *sc) 393 { 394 struct dc503reg *pcc; 395 396 if (sc->sc_curenb) { 397 pcc = (void *)MIPS_PHYS_TO_KSEG1(KN01_SYS_PCC); 398 pcc->cmdr = (pm_creg |= (PCCCMD_ENPA | PCCCMD_ENPB)); 399 wbflush(); 400 } 401 } 402 403 int 404 pm_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l) 405 { 406 struct pm_softc *sc; 407 struct rasops_info *ri; 408 int turnoff, rv, i; 409 struct dc503reg *pcc; 410 VDACRegs *vdac; 411 412 sc = v; 413 ri = &pm_ri; 414 rv = 0; 415 pcc = (void *)MIPS_PHYS_TO_KSEG1(KN01_SYS_PCC); 416 vdac = (void *)MIPS_PHYS_TO_KSEG1(KN01_SYS_VDAC); 417 418 switch (cmd) { 419 case WSDISPLAYIO_GTYPE: 420 *(u_int *)data = sc->sc_type; 421 break; 422 423 case WSDISPLAYIO_SMODE: 424 if (*(u_int *)data == WSDISPLAYIO_MODE_EMUL) { 425 pm_cursor_off(); 426 pm_init_cmap(sc); 427 memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height); 428 sc->sc_curenb = 0; 429 sc->sc_changed |= WSDISPLAY_CMAP_DOLUT; 430 } 431 break; 432 433 case WSDISPLAYIO_GINFO: 434 #define wsd_fbip ((struct wsdisplay_fbinfo *)data) 435 wsd_fbip->height = ri->ri_height; 436 wsd_fbip->width = ri->ri_width; 437 wsd_fbip->depth = ri->ri_depth; 438 wsd_fbip->cmsize = sc->sc_cmap_size; 439 #undef fbt 440 break; 441 442 case WSDISPLAYIO_GETCMAP: 443 rv = pm_get_cmap(sc, (struct wsdisplay_cmap *)data); 444 break; 445 446 case WSDISPLAYIO_PUTCMAP: 447 rv = pm_set_cmap(sc, (struct wsdisplay_cmap *)data); 448 break; 449 450 case WSDISPLAYIO_SVIDEO: 451 turnoff = (*(int *)data == WSDISPLAYIO_VIDEO_OFF); 452 if ((sc->sc_blanked == 0) ^ turnoff) { 453 sc->sc_blanked = turnoff; 454 if (turnoff == 0) { 455 pcc->cmdr = 456 (pm_creg &= ~(PCCCMD_FOPA | PCCCMD_FOPB)); 457 wbflush(); 458 pm_cursor_on(sc); 459 sc->sc_changed |= WSDISPLAY_CURSOR_DOCMAP; 460 } else { 461 pm_cursor_off(); 462 pcc->cmdr = 463 (pm_creg |= (PCCCMD_FOPA | PCCCMD_FOPB)); 464 wbflush(); 465 vdac->overWA = 0x0c; 466 wbflush(); 467 for (i = 0; i < 3; i++) { 468 vdac->over = 0; 469 wbflush(); 470 } 471 } 472 } 473 break; 474 475 case WSDISPLAYIO_GVIDEO: 476 *(u_int *)data = (sc->sc_blanked ? 477 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON); 478 break; 479 480 case WSDISPLAYIO_GCURPOS: 481 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos; 482 break; 483 484 case WSDISPLAYIO_SCURPOS: 485 pm_set_curpos(sc, (struct wsdisplay_curpos *)data); 486 sc->sc_changed |= WSDISPLAY_CURSOR_DOPOS; 487 break; 488 489 case WSDISPLAYIO_GCURMAX: 490 ((struct wsdisplay_curpos *)data)->x = 491 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE; 492 break; 493 494 case WSDISPLAYIO_GCURSOR: 495 rv = pm_get_cursor(sc, (struct wsdisplay_cursor *)data); 496 break; 497 498 case WSDISPLAYIO_SCURSOR: 499 rv = pm_set_cursor(sc, (struct wsdisplay_cursor *)data); 500 break; 501 502 default: 503 rv = ENOTTY; 504 break; 505 } 506 507 pm_flush(sc); 508 return (rv); 509 } 510 511 paddr_t 512 pm_mmap(void *v, void *vs, off_t offset, int prot) 513 { 514 struct pm_softc *sc; 515 516 sc = v; 517 518 if (offset >= sc->sc_fb_size || offset < 0) 519 return (-1); 520 521 return (mips_btop(KN01_PHYS_FBUF_START + offset)); 522 } 523 524 int 525 pm_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep, 526 int *curxp, int *curyp, long *attrp) 527 { 528 struct pm_softc *sc; 529 struct rasops_info *ri; 530 long defattr; 531 532 sc = v; 533 ri = &pm_ri; 534 535 if (sc->sc_nscreens > 0) 536 return (ENOMEM); 537 538 *cookiep = ri; /* one and only for now */ 539 *curxp = 0; 540 *curyp = 0; 541 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr); 542 *attrp = defattr; 543 sc->sc_nscreens++; 544 return (0); 545 } 546 547 void 548 pm_free_screen(void *v, void *cookie) 549 { 550 551 panic("pm_free_screen: console"); 552 } 553 554 int 555 pm_show_screen(void *v, void *cookie, int waitok, 556 void (*cb)(void *, int, int), void *cbarg) 557 { 558 559 return (0); 560 } 561 562 /* EXPORT */ int 563 pm_cnattach(void) 564 { 565 struct rasops_info *ri; 566 long defattr; 567 568 ri = &pm_ri; 569 570 pm_common_init(); 571 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr); 572 wsdisplay_cnattach(&pm_stdscreen, ri, 0, 0, defattr); 573 return (1); 574 } 575 576 int 577 pm_flush(struct pm_softc *sc) 578 { 579 VDACRegs *vdac; 580 struct dc503reg *pcc; 581 uint8_t *cp; 582 int v, i, x, y; 583 u_short *p, *pe; 584 struct hwcmap256 *cm; 585 586 if (sc->sc_changed == 0) 587 return (1); 588 589 vdac = (void *)MIPS_PHYS_TO_KSEG1(KN01_SYS_VDAC); 590 pcc = (void *)MIPS_PHYS_TO_KSEG1(KN01_SYS_PCC); 591 v = sc->sc_changed; 592 593 if ((v & WSDISPLAY_CURSOR_DOCUR) != 0) { 594 if (sc->sc_curenb) 595 pm_cursor_on(sc); 596 else 597 pm_cursor_off(); 598 } 599 600 if ((v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) != 0) { 601 x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x; 602 y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y; 603 pcc->xpos = x + PCC_X_OFFSET; 604 pcc->ypos = y + PCC_Y_OFFSET; 605 wbflush(); 606 } 607 if ((v & WSDISPLAY_CURSOR_DOCMAP) != 0) { 608 cp = sc->sc_cursor.cc_color; 609 610 vdac->overWA = 0x04; 611 wbflush(); 612 for (i = 1; i < 6; i += 2) { 613 vdac->over = cp[i]; 614 wbflush(); 615 } 616 617 vdac->overWA = 0x08; 618 wbflush(); 619 vdac->over = 0x00; 620 wbflush(); 621 vdac->over = 0x00; 622 wbflush(); 623 vdac->over = 0x7f; 624 wbflush(); 625 626 vdac->overWA = 0x0c; 627 wbflush(); 628 for (i = 0; i < 6; i += 2) { 629 vdac->over = cp[i]; 630 wbflush(); 631 } 632 } 633 if ((v & WSDISPLAY_CURSOR_DOSHAPE) != 0) { 634 pcc->cmdr = (pm_creg | PCCCMD_LODSA); 635 wbflush(); 636 637 p = sc->sc_cursor.cc_image; 638 x = 0xffff >> (16 - sc->sc_cursor.cc_size.x); 639 for (pe = p + 64; p < pe; p += 2) { 640 pcc->load = *p & x; 641 wbflush(); 642 } 643 644 pcc->cmdr = (pm_creg &= ~PCCCMD_LODSA); 645 wbflush(); 646 } 647 648 if ((v & WSDISPLAY_CMAP_DOLUT) != 0) { 649 cm = &sc->sc_cmap; 650 651 vdac->mapWA = 0; 652 wbflush(); 653 654 if (sc->sc_cmap_size == 2) { 655 for (i = 0; i < 128; i++) { 656 vdac->map = 0; 657 wbflush(); 658 vdac->map = cm->g[0]; 659 wbflush(); 660 vdac->map = 0; 661 wbflush(); 662 } 663 for (; i < 256; i++) { 664 vdac->map = 0; 665 wbflush(); 666 vdac->map = cm->g[1]; 667 wbflush(); 668 vdac->map = 0; 669 wbflush(); 670 } 671 } else { 672 for (i = 0; i < sc->sc_cmap_size; i++) { 673 vdac->map = cm->r[i]; 674 wbflush(); 675 vdac->map = cm->g[i]; 676 wbflush(); 677 vdac->map = cm->b[i]; 678 wbflush(); 679 } 680 } 681 } 682 683 sc->sc_changed = 0; 684 return (1); 685 } 686 687 int 688 pm_get_cmap(struct pm_softc *sc, struct wsdisplay_cmap *p) 689 { 690 u_int index, count; 691 int rv; 692 693 index = p->index; 694 count = p->count; 695 696 if (index >= sc->sc_cmap_size || count > sc->sc_cmap_size - index) 697 return (EINVAL); 698 699 if ((rv = copyout(&sc->sc_cmap.r[index], p->red, count)) != 0) 700 return (rv); 701 if ((rv = copyout(&sc->sc_cmap.g[index], p->green, count)) != 0) 702 return (rv); 703 return (copyout(&sc->sc_cmap.b[index], p->blue, count)); 704 } 705 706 int 707 pm_set_cmap(struct pm_softc *sc, struct wsdisplay_cmap *p) 708 { 709 u_int index, count; 710 int rv; 711 712 index = p->index; 713 count = p->count; 714 715 if (index >= sc->sc_cmap_size || count > sc->sc_cmap_size - index) 716 return (EINVAL); 717 718 if ((rv = copyin(p->red, &sc->sc_cmap.r[index], count)) != 0) 719 return (rv); 720 if ((rv = copyin(p->green, &sc->sc_cmap.g[index], count)) != 0) 721 return (rv); 722 if ((rv = copyin(p->blue, &sc->sc_cmap.b[index], count)) != 0) 723 return (rv); 724 sc->sc_changed |= WSDISPLAY_CMAP_DOLUT; 725 return (0); 726 } 727 728 int 729 pm_set_cursor(struct pm_softc *sc, struct wsdisplay_cursor *p) 730 { 731 u_int v, index, count; 732 struct hwcursor64 *cc; 733 int rv; 734 735 v = p->which; 736 cc = &sc->sc_cursor; 737 738 if ((v & WSDISPLAY_CURSOR_DOCUR) != 0) 739 sc->sc_curenb = p->enable; 740 if ((v & WSDISPLAY_CURSOR_DOPOS) != 0) 741 pm_set_curpos(sc, &p->pos); 742 if ((v & WSDISPLAY_CURSOR_DOHOT) != 0) 743 cc->cc_hot = p->hot; 744 if ((v & WSDISPLAY_CURSOR_DOCMAP) != 0) { 745 index = p->cmap.index; 746 count = p->cmap.count; 747 if (index >= 2 || count > 2 - index) 748 return (EINVAL); 749 750 rv = copyin(p->cmap.red, &cc->cc_color[index], count); 751 if (rv != 0) 752 return (rv); 753 rv = copyin(p->cmap.green, &cc->cc_color[index + 2], count); 754 if (rv != 0) 755 return (rv); 756 rv = copyin(p->cmap.blue, &cc->cc_color[index + 4], count); 757 if (rv != 0) 758 return (rv); 759 } 760 if ((v & WSDISPLAY_CURSOR_DOSHAPE) != 0) { 761 if (p->size.x > CURSOR_MAX_SIZE || 762 p->size.y > CURSOR_MAX_SIZE) 763 return (EINVAL); 764 765 cc->cc_size = p->size; 766 memset(cc->cc_image, 0, sizeof(cc->cc_image)); 767 rv = copyin(p->image, cc->cc_image, p->size.y * 4); 768 if (rv != 0) 769 return (rv); 770 rv = copyin(p->mask, cc->cc_image+32, p->size.y * 4); 771 if (rv != 0) 772 return (rv); 773 } 774 775 sc->sc_changed |= v; 776 return (0); 777 } 778 779 int 780 pm_get_cursor(struct pm_softc *sc, struct wsdisplay_cursor *p) 781 { 782 783 return (ENOTTY); /* XXX */ 784 } 785 786 void 787 pm_set_curpos(struct pm_softc *sc, struct wsdisplay_curpos *curpos) 788 { 789 struct rasops_info *ri; 790 int x, y; 791 792 ri = &pm_ri; 793 x = curpos->x; 794 y = curpos->y; 795 796 if (y < 0) 797 y = 0; 798 else if (y > ri->ri_height) 799 y = ri->ri_height; 800 if (x < 0) 801 x = 0; 802 else if (x > ri->ri_width) 803 x = ri->ri_width; 804 sc->sc_cursor.cc_pos.x = x; 805 sc->sc_cursor.cc_pos.y = y; 806 } 807