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