1 /* $NetBSD: pm.c,v 1.8 2010/05/15 20:31:10 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.8 2010/05/15 20:31:10 tsutsui 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 <machine/bus.h> 43 #include <machine/intr.h> 44 45 #include <dev/wscons/wsconsio.h> 46 #include <dev/wscons/wsdisplayvar.h> 47 #include <dev/rasops/rasops.h> 48 #include <dev/wsfont/wsfont.h> 49 50 #include <pmax/pmax/kn01.h> 51 52 #include <pmax/ibus/ibusvar.h> 53 #include <pmax/ibus/pmreg.h> 54 55 #include <uvm/uvm_extern.h> 56 57 #define CURSOR_MAX_SIZE 16 58 59 struct hwcmap256 { 60 uint8_t r[256]; 61 uint8_t g[256]; 62 uint8_t b[256]; 63 }; 64 65 struct hwcursor64 { 66 struct wsdisplay_curpos cc_pos; 67 struct wsdisplay_curpos cc_hot; 68 struct wsdisplay_curpos cc_size; 69 uint8_t cc_color[6]; 70 71 /* 72 * Max cursor size is 16x16. The X server pads bitmap scanlines to 73 * a word boundary. We take the easy route and waste some space. 74 */ 75 u_short cc_image[32 + 32]; 76 }; 77 78 struct pm_softc { 79 struct device sc_dev; 80 size_t sc_cmap_size; 81 size_t sc_fb_size; 82 int sc_type; 83 int sc_blanked; 84 int sc_curenb; 85 int sc_changed; 86 int sc_nscreens; 87 struct hwcursor64 sc_cursor; 88 struct hwcmap256 sc_cmap; 89 }; 90 #define WSDISPLAY_CMAP_DOLUT 0x20 91 92 int pm_match(struct device *, struct cfdata *, void *); 93 void pm_attach(struct device *, struct device *, 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(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(struct device *parent, struct cfdata *match, 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(struct device *parent, struct device *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 = (struct pm_softc *)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); 270 else 271 cookie = wsfont_find(NULL, 8, 0, 0, bior, 272 WSDISPLAY_FONTORDER_L2R); 273 if (cookie <= 0) 274 cookie = wsfont_find(NULL, 0, 0, 0, bior, 275 WSDISPLAY_FONTORDER_L2R); 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 struct rasops_info *ri; 559 560 if (sc->sc_changed == 0) 561 return (1); 562 563 vdac = (void *)MIPS_PHYS_TO_KSEG1(KN01_SYS_VDAC); 564 pcc = (void *)MIPS_PHYS_TO_KSEG1(KN01_SYS_PCC); 565 ri = &pm_ri; 566 v = sc->sc_changed; 567 568 if ((v & WSDISPLAY_CURSOR_DOCUR) != 0) { 569 if (sc->sc_curenb) 570 pm_cursor_on(sc); 571 else 572 pm_cursor_off(); 573 } 574 575 if ((v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) != 0) { 576 x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x; 577 y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y; 578 pcc->xpos = x + PCC_X_OFFSET; 579 pcc->ypos = y + PCC_Y_OFFSET; 580 wbflush(); 581 } 582 if ((v & WSDISPLAY_CURSOR_DOCMAP) != 0) { 583 cp = sc->sc_cursor.cc_color; 584 585 vdac->overWA = 0x04; 586 wbflush(); 587 for (i = 1; i < 6; i += 2) { 588 vdac->over = cp[i]; 589 wbflush(); 590 } 591 592 vdac->overWA = 0x08; 593 wbflush(); 594 vdac->over = 0x00; 595 wbflush(); 596 vdac->over = 0x00; 597 wbflush(); 598 vdac->over = 0x7f; 599 wbflush(); 600 601 vdac->overWA = 0x0c; 602 wbflush(); 603 for (i = 0; i < 6; i += 2) { 604 vdac->over = cp[i]; 605 wbflush(); 606 } 607 } 608 if ((v & WSDISPLAY_CURSOR_DOSHAPE) != 0) { 609 pcc->cmdr = (pm_creg | PCC_LODSA); 610 wbflush(); 611 612 p = sc->sc_cursor.cc_image; 613 x = 0xffff >> (16 - sc->sc_cursor.cc_size.x); 614 for (pe = p + 64; p < pe; p += 2) { 615 pcc->memory = *p & x; 616 wbflush(); 617 } 618 619 pcc->cmdr = (pm_creg &= ~PCC_LODSA); 620 wbflush(); 621 } 622 623 if ((v & WSDISPLAY_CMAP_DOLUT) != 0) { 624 cm = &sc->sc_cmap; 625 626 vdac->mapWA = 0; 627 wbflush(); 628 629 if (sc->sc_cmap_size == 2) { 630 for (i = 0; i < 128; i++) { 631 vdac->map = 0; 632 wbflush(); 633 vdac->map = cm->g[0]; 634 wbflush(); 635 vdac->map = 0; 636 wbflush(); 637 } 638 for (; i < 256; i++) { 639 vdac->map = 0; 640 wbflush(); 641 vdac->map = cm->g[1]; 642 wbflush(); 643 vdac->map = 0; 644 wbflush(); 645 } 646 } else { 647 for (i = 0; i < sc->sc_cmap_size; i++) { 648 vdac->map = cm->r[i]; 649 wbflush(); 650 vdac->map = cm->g[i]; 651 wbflush(); 652 vdac->map = cm->b[i]; 653 wbflush(); 654 } 655 } 656 } 657 658 sc->sc_changed = 0; 659 return (1); 660 } 661 662 int 663 pm_get_cmap(struct pm_softc *sc, struct wsdisplay_cmap *p) 664 { 665 u_int index, count; 666 int rv; 667 668 index = p->index; 669 count = p->count; 670 671 if (index >= sc->sc_cmap_size || (index + count) > sc->sc_cmap_size) 672 return (EINVAL); 673 674 if ((rv = copyout(&sc->sc_cmap.r[index], p->red, count)) != 0) 675 return (rv); 676 if ((rv = copyout(&sc->sc_cmap.g[index], p->green, count)) != 0) 677 return (rv); 678 return (copyout(&sc->sc_cmap.b[index], p->blue, count)); 679 } 680 681 int 682 pm_set_cmap(struct pm_softc *sc, struct wsdisplay_cmap *p) 683 { 684 u_int index, count; 685 int rv; 686 687 index = p->index; 688 count = p->count; 689 690 if (index >= sc->sc_cmap_size || (index + count) > sc->sc_cmap_size) 691 return (EINVAL); 692 693 if ((rv = copyin(p->red, &sc->sc_cmap.r[index], count)) != 0) 694 return (rv); 695 if ((rv = copyin(p->green, &sc->sc_cmap.g[index], count)) != 0) 696 return (rv); 697 if ((rv = copyin(p->blue, &sc->sc_cmap.b[index], count)) != 0) 698 return (rv); 699 sc->sc_changed |= WSDISPLAY_CMAP_DOLUT; 700 return (0); 701 } 702 703 int 704 pm_set_cursor(struct pm_softc *sc, struct wsdisplay_cursor *p) 705 { 706 u_int v, index, count; 707 struct hwcursor64 *cc; 708 int rv; 709 710 v = p->which; 711 cc = &sc->sc_cursor; 712 713 if ((v & WSDISPLAY_CURSOR_DOCUR) != 0) 714 sc->sc_curenb = p->enable; 715 if ((v & WSDISPLAY_CURSOR_DOPOS) != 0) 716 pm_set_curpos(sc, &p->pos); 717 if ((v & WSDISPLAY_CURSOR_DOHOT) != 0) 718 cc->cc_hot = p->hot; 719 if ((v & WSDISPLAY_CURSOR_DOCMAP) != 0) { 720 index = p->cmap.index; 721 count = p->cmap.count; 722 if (index >= 2 || (index + count) > 2) 723 return (EINVAL); 724 725 rv = copyin(p->cmap.red, &cc->cc_color[index], count); 726 if (rv != 0) 727 return (rv); 728 rv = copyin(p->cmap.green, &cc->cc_color[index + 2], count); 729 if (rv != 0) 730 return (rv); 731 rv = copyin(p->cmap.blue, &cc->cc_color[index + 4], count); 732 if (rv != 0) 733 return (rv); 734 } 735 if ((v & WSDISPLAY_CURSOR_DOSHAPE) != 0) { 736 if (p->size.x > CURSOR_MAX_SIZE || 737 p->size.y > CURSOR_MAX_SIZE) 738 return (EINVAL); 739 740 cc->cc_size = p->size; 741 memset(cc->cc_image, 0, sizeof(cc->cc_image)); 742 rv = copyin(p->image, cc->cc_image, p->size.y * 4); 743 if (rv != 0) 744 return (rv); 745 rv = copyin(p->mask, cc->cc_image+32, p->size.y * 4); 746 if (rv != 0) 747 return (rv); 748 } 749 750 sc->sc_changed |= v; 751 return (0); 752 } 753 754 int 755 pm_get_cursor(struct pm_softc *sc, struct wsdisplay_cursor *p) 756 { 757 758 return (ENOTTY); /* XXX */ 759 } 760 761 void 762 pm_set_curpos(struct pm_softc *sc, struct wsdisplay_curpos *curpos) 763 { 764 struct rasops_info *ri; 765 int x, y; 766 767 ri = &pm_ri; 768 x = curpos->x; 769 y = curpos->y; 770 771 if (y < 0) 772 y = 0; 773 else if (y > ri->ri_height) 774 y = ri->ri_height; 775 if (x < 0) 776 x = 0; 777 else if (x > ri->ri_width) 778 x = ri->ri_width; 779 sc->sc_cursor.cc_pos.x = x; 780 sc->sc_cursor.cc_pos.y = y; 781 } 782