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