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