1 /* $NetBSD: igsfb.c,v 1.2 2002/04/05 03:29:05 uwe Exp $ */ 2 3 /* 4 * Copyright (c) 2002 Valeriy E. Ushakov 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 /* 31 * Integraphics Systems IGA 1682 and (untested) CyberPro 2k. 32 */ 33 #include <sys/cdefs.h> 34 __KERNEL_RCSID(0, "$NetBSD: igsfb.c,v 1.2 2002/04/05 03:29:05 uwe Exp $"); 35 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 #include <sys/kernel.h> 39 #include <sys/device.h> 40 #include <sys/malloc.h> 41 #include <sys/ioctl.h> 42 #include <sys/buf.h> 43 #include <uvm/uvm_extern.h> 44 45 #include <machine/bus.h> 46 47 #include <dev/wscons/wsdisplayvar.h> 48 #include <dev/rasops/rasops.h> 49 #include <dev/wsfont/wsfont.h> 50 #include <dev/wscons/wsconsio.h> 51 52 #include <dev/ic/igsfbreg.h> 53 #include <dev/ic/igsfbvar.h> 54 55 56 /* 57 * wsscreen 58 */ 59 60 /* filled from rasops_info in igsfb_common_init */ 61 static struct wsscreen_descr igsfb_stdscreen = { 62 "std", /* name */ 63 0, 0, /* ncols, nrows */ 64 NULL, /* textops */ 65 0, 0, /* fontwidth, fontheight */ 66 0 /* capabilities */ 67 }; 68 69 static const struct wsscreen_descr *_igsfb_scrlist[] = { 70 &igsfb_stdscreen, 71 }; 72 73 static const struct wsscreen_list igsfb_screenlist = { 74 sizeof(_igsfb_scrlist) / sizeof(struct wsscreen_descr *), 75 _igsfb_scrlist 76 }; 77 78 79 /* 80 * wsdisplay_accessops 81 */ 82 83 static int igsfb_ioctl(void *, u_long, caddr_t, int, struct proc *); 84 static paddr_t igsfb_mmap(void *, off_t, int); 85 86 static int igsfb_alloc_screen(void *, const struct wsscreen_descr *, 87 void **, int *, int *, long *); 88 static void igsfb_free_screen(void *, void *); 89 static int igsfb_show_screen(void *, void *, int, 90 void (*) (void *, int, int), void *); 91 92 static const struct wsdisplay_accessops igsfb_accessops = { 93 igsfb_ioctl, 94 igsfb_mmap, 95 igsfb_alloc_screen, 96 igsfb_free_screen, 97 igsfb_show_screen, 98 NULL /* load_font */ 99 }; 100 101 102 /* 103 * internal functions 104 */ 105 static void igsfb_common_init(struct igsfb_softc *); 106 static void igsfb_init_bit_tables(struct igsfb_softc *); 107 static void igsfb_blank_screen(struct igsfb_softc *, int); 108 static int igsfb_get_cmap(struct igsfb_softc *, struct wsdisplay_cmap *); 109 static int igsfb_set_cmap(struct igsfb_softc *, struct wsdisplay_cmap *); 110 static void igsfb_update_cmap(struct igsfb_softc *sc, u_int, u_int); 111 static void igsfb_set_curpos(struct igsfb_softc *, 112 struct wsdisplay_curpos *); 113 static void igsfb_update_curpos(struct igsfb_softc *); 114 static int igsfb_get_cursor(struct igsfb_softc *, 115 struct wsdisplay_cursor *); 116 static int igsfb_set_cursor(struct igsfb_softc *, 117 struct wsdisplay_cursor *); 118 static void igsfb_update_cursor(struct igsfb_softc *, u_int); 119 static void igsfb_convert_cursor_data(struct igsfb_softc *, u_int, u_int); 120 121 /* 122 * bit expanders 123 */ 124 static u_int16_t igsfb_spread_bits_8(u_int8_t); 125 126 struct igs_bittab *igsfb_bittab = NULL; 127 struct igs_bittab *igsfb_bittab_bswap = NULL; 128 129 static __inline__ u_int16_t 130 igsfb_spread_bits_8(b) 131 u_int8_t b; 132 { 133 u_int16_t s = b; 134 135 s = ((s & 0x00f0) << 4) | (s & 0x000f); 136 s = ((s & 0x0c0c) << 2) | (s & 0x0303); 137 s = ((s & 0x2222) << 1) | (s & 0x1111); 138 return (s); 139 } 140 141 142 /* 143 * Enable Video. This might go through either memory or i/o space and 144 * requires access to registers that we don't need for normal 145 * operation. So for greater flexibility this function takes bus tag 146 * and base address, not the igsfb_softc. 147 */ 148 int 149 igsfb_io_enable(bt, base) 150 bus_space_tag_t bt; 151 bus_addr_t base; 152 { 153 bus_space_handle_t vdoh; 154 bus_space_handle_t vseh; 155 int ret; 156 157 ret = bus_space_map(bt, base + IGS_VDO, 1, 0, &vdoh); 158 if (ret != 0) { 159 printf("unable to map VDO register\n"); 160 return (ret); 161 } 162 163 ret = bus_space_map(bt, base + IGS_VSE, 1, 0, &vseh); 164 if (ret != 0) { 165 bus_space_unmap(bt, vdoh, 1); 166 printf("unable to map VSE register\n"); 167 return (ret); 168 } 169 170 /* enable video: start decoding i/o space accesses */ 171 bus_space_write_1(bt, vdoh, 0, IGS_VDO_ENABLE | IGS_VDO_SETUP); 172 bus_space_write_1(bt, vseh, 0, IGS_VSE_ENABLE); 173 bus_space_write_1(bt, vdoh, 0, IGS_VDO_ENABLE); 174 175 bus_space_unmap(bt, vdoh, 1); 176 bus_space_unmap(bt, vseh, 1); 177 178 return (0); 179 } 180 181 182 /* 183 * Enable linear: start decoding memory space accesses. 184 * while here, enable coprocessor and set its addrress to 0xbf000. 185 */ 186 void 187 igsfb_mem_enable(sc) 188 struct igsfb_softc *sc; 189 { 190 191 igs_ext_write(sc->sc_iot, sc->sc_ioh, IGS_EXT_BIU_MISC_CTL, 192 IGS_EXT_BIU_LINEAREN 193 | IGS_EXT_BIU_COPREN 194 | IGS_EXT_BIU_COPASELB); 195 } 196 197 198 /* 199 * Finish off the attach. Bus specific attach method should have 200 * enabled io and memory accesses and mapped io and cop registers. 201 */ 202 void 203 igsfb_common_attach(sc, isconsole) 204 struct igsfb_softc *sc; 205 int isconsole; 206 { 207 bus_addr_t craddr; 208 off_t croffset; 209 struct rasops_info *ri; 210 struct wsemuldisplaydev_attach_args waa; 211 u_int8_t busctl, curctl; 212 213 busctl = igs_ext_read(sc->sc_iot, sc->sc_ioh, IGS_EXT_BUS_CTL); 214 if (busctl & 0x2) 215 sc->sc_memsz = 4 * 1024 * 1024; 216 else if (busctl & 0x1) 217 sc->sc_memsz = 2 * 1024 * 1024; 218 else 219 sc->sc_memsz = 1 * 1024 * 1024; 220 221 /* 222 * Don't map in all N megs, just the amount we need for wsscreen 223 */ 224 sc->sc_fbsz = 1024 * 768; /* XXX: 8bpp specific */ 225 if (bus_space_map(sc->sc_memt, sc->sc_memaddr, sc->sc_fbsz, 226 sc->sc_memflags | BUS_SPACE_MAP_LINEAR, 227 &sc->sc_fbh) != 0) 228 { 229 bus_space_unmap(sc->sc_iot, sc->sc_ioh, IGS_IO_SIZE); 230 printf("unable to map framebuffer\n"); 231 return; 232 } 233 234 /* 235 * 1Kb for cursor sprite data at the very end of linear space 236 */ 237 croffset = sc->sc_memsz - IGS_CURSOR_DATA_SIZE; 238 craddr = sc->sc_memaddr + croffset; 239 if (bus_space_map(sc->sc_memt, craddr, IGS_CURSOR_DATA_SIZE, 240 sc->sc_memflags | BUS_SPACE_MAP_LINEAR, 241 &sc->sc_crh) != 0) 242 { 243 bus_space_unmap(sc->sc_iot, sc->sc_ioh, IGS_IO_SIZE); 244 bus_space_unmap(sc->sc_memt, sc->sc_fbh, sc->sc_fbsz); 245 printf("unable to map cursor sprite region\n"); 246 return; 247 } 248 249 /* 250 * Tell device where cursor sprite data are located in linear 251 * space (it takes data offset in 1k units). 252 */ 253 croffset >>= 10; 254 igs_ext_write(sc->sc_iot, sc->sc_ioh, 255 IGS_EXT_SPRITE_DATA_LO, croffset & 0xff); 256 igs_ext_write(sc->sc_iot, sc->sc_ioh, 257 IGS_EXT_SPRITE_DATA_HI, (croffset >> 8) & 0xf); 258 259 memset(&sc->sc_cursor, 0, sizeof(struct igs_hwcursor)); 260 memset(bus_space_vaddr(sc->sc_memt, sc->sc_crh), 261 0xaa, IGS_CURSOR_DATA_SIZE); /* transparent */ 262 263 curctl = igs_ext_read(sc->sc_iot, sc->sc_ioh, IGS_EXT_SPRITE_CTL); 264 curctl |= IGS_EXT_SPRITE_64x64; 265 curctl &= ~IGS_EXT_SPRITE_VISIBLE; 266 igs_ext_write(sc->sc_iot, sc->sc_ioh, IGS_EXT_SPRITE_CTL, curctl); 267 268 /* bit expanders for cursor sprite data */ 269 igsfb_init_bit_tables(sc); 270 271 /* alloc and cross-link raster ops */ 272 ri = malloc(sizeof(struct rasops_info), M_DEVBUF, M_NOWAIT | M_ZERO); 273 if (ri == NULL) 274 panic("unable to allocate rasops"); 275 ri->ri_hw = sc; 276 sc->sc_ri = ri; 277 278 igsfb_common_init(sc); 279 280 /* 281 * XXX: console attachment needs rethinking 282 */ 283 if (isconsole) { 284 long defattr; 285 (*ri->ri_ops.alloc_attr)(ri, 0, 0, 0, &defattr); 286 wsdisplay_cnattach(&igsfb_stdscreen, ri, 0, 0, defattr); 287 } 288 289 290 printf("%s: %dx%d, %dbpp\n", 291 sc->sc_dev.dv_xname, ri->ri_width, ri->ri_height, ri->ri_depth); 292 293 /* attach wsdisplay */ 294 waa.console = isconsole; 295 waa.scrdata = &igsfb_screenlist; 296 waa.accessops = &igsfb_accessops; 297 waa.accesscookie = sc; 298 299 config_found(&sc->sc_dev, &waa, wsemuldisplaydevprint); 300 } 301 302 303 /* 304 * Cursor sprite data are in 2bpp. Incoming image/mask are in 1bpp. 305 * Prebuild tables to expand 1bpp->2bpp with bswapping if neccessary. 306 */ 307 static void 308 igsfb_init_bit_tables(sc) 309 struct igsfb_softc *sc; 310 { 311 struct igs_bittab *tab; 312 u_int i; 313 314 if (sc->sc_hwflags & IGSFB_HW_BSWAP) { 315 if (igsfb_bittab_bswap == NULL) { 316 tab = malloc(sizeof(struct igs_bittab), 317 M_DEVBUF, M_NOWAIT); 318 for (i = 0; i < 256; ++i) { 319 u_int16_t s = igsfb_spread_bits_8(i); 320 tab->iexpand[i] = bswap16(s); 321 tab->mexpand[i] = bswap16((s << 1) | s); 322 } 323 igsfb_bittab_bswap = tab; 324 } 325 sc->sc_bittab = igsfb_bittab_bswap; 326 } else { 327 if (igsfb_bittab == NULL) { 328 tab = malloc(sizeof(struct igs_bittab), 329 M_DEVBUF, M_NOWAIT); 330 for (i = 0; i < 256; ++i) { 331 u_int16_t s = igsfb_spread_bits_8(i); 332 tab->iexpand[i] = s; 333 tab->mexpand[i] = (s << 1) | s; 334 } 335 igsfb_bittab = tab; 336 } 337 sc->sc_bittab = igsfb_bittab; 338 } 339 } 340 341 /* 342 * I/O and memory are mapped, video enabled, structures allocated. 343 */ 344 static void 345 igsfb_common_init(sc) 346 struct igsfb_softc *sc; 347 { 348 bus_space_tag_t iot = sc->sc_iot; 349 bus_space_handle_t ioh = sc->sc_ioh; 350 struct rasops_info *ri = sc->sc_ri; 351 int wsfcookie; 352 const u_int8_t *p; 353 int i; 354 355 sc->sc_blanked = 0; 356 357 ri->ri_flg = RI_CENTER | RI_CLEAR; 358 if (sc->sc_hwflags & IGSFB_HW_BSWAP) 359 ri->ri_flg |= RI_BSWAP; 360 361 ri->ri_depth = 8; 362 ri->ri_width = 1024; 363 ri->ri_height = 768; 364 ri->ri_stride = 1024; 365 ri->ri_bits = (u_char *)sc->sc_fbh; 366 367 /* 368 * Initialize wsfont related stuff. 369 */ 370 wsfont_init(); 371 372 /* prefer gallant that is identical to the one the prom uses */ 373 wsfcookie = wsfont_find("Gallant", 12, 22, 0, 374 WSDISPLAY_FONTORDER_L2R, 375 WSDISPLAY_FONTORDER_L2R); 376 if (wsfcookie <= 0) { 377 #ifdef DIAGNOSTIC 378 printf("%s: unable to find font Gallant 12x22\n", 379 sc->sc_dev.dv_xname); 380 #endif 381 /* any font at all? */ 382 wsfcookie = wsfont_find(NULL, 0, 0, 0, 383 WSDISPLAY_FONTORDER_L2R, 384 WSDISPLAY_FONTORDER_L2R); 385 } 386 387 if (wsfcookie <= 0) { 388 printf("%s: unable to find any fonts\n", sc->sc_dev.dv_xname); 389 return; 390 } 391 392 if (wsfont_lock(wsfcookie, &ri->ri_font) != 0) { 393 printf("%s: unable to lock font\n", sc->sc_dev.dv_xname); 394 return; 395 } 396 ri->ri_wsfcookie = wsfcookie; 397 398 399 /* 400 * Initialize colormap related stuff. 401 */ 402 403 /* ANSI color map */ 404 p = rasops_cmap; 405 for (i = 0; i < IGS_CMAP_SIZE; ++i, p += 3) { /* software copy */ 406 sc->sc_cmap.r[i] = p[0]; 407 sc->sc_cmap.g[i] = p[1]; 408 sc->sc_cmap.b[i] = p[2]; 409 } 410 igsfb_update_cmap(sc, 0, IGS_CMAP_SIZE); 411 412 /* set overscan color r/g/b (XXX: use defattr's rgb?) */ 413 igs_ext_write(iot, ioh, IGS_EXT_OVERSCAN_RED, 0); 414 igs_ext_write(iot, ioh, IGS_EXT_OVERSCAN_GREEN, 0); 415 igs_ext_write(iot, ioh, IGS_EXT_OVERSCAN_BLUE, 0); 416 417 418 /* TODO: compute term size based on font dimensions? */ 419 rasops_init(ri, 34, 80); 420 421 igsfb_stdscreen.nrows = ri->ri_rows; 422 igsfb_stdscreen.ncols = ri->ri_cols; 423 igsfb_stdscreen.textops = &ri->ri_ops; 424 igsfb_stdscreen.capabilities = ri->ri_caps; 425 } 426 427 428 /* 429 * wsdisplay_accessops: mmap() 430 */ 431 static paddr_t 432 igsfb_mmap(v, offset, prot) 433 void *v; 434 off_t offset; 435 int prot; 436 { 437 struct igsfb_softc *sc = v; 438 439 if (offset >= sc->sc_memsz || offset < 0) 440 return (-1); 441 442 return (bus_space_mmap(sc->sc_memt, sc->sc_memaddr, offset, prot, 443 sc->sc_memflags | BUS_SPACE_MAP_LINEAR)); 444 } 445 446 447 /* 448 * wsdisplay_accessops: ioctl() 449 */ 450 static int 451 igsfb_ioctl(v, cmd, data, flag, p) 452 void *v; 453 u_long cmd; 454 caddr_t data; 455 int flag; 456 struct proc *p; 457 { 458 struct igsfb_softc *sc = v; 459 struct rasops_info *ri = sc->sc_ri; 460 int turnoff; 461 462 switch (cmd) { 463 464 case WSDISPLAYIO_GTYPE: 465 *(u_int *)data = WSDISPLAY_TYPE_PCIMISC; 466 return (0); 467 468 case WSDISPLAYIO_GINFO: 469 #define wsd_fbip ((struct wsdisplay_fbinfo *)data) 470 wsd_fbip->height = ri->ri_height; 471 wsd_fbip->width = ri->ri_width; 472 wsd_fbip->depth = ri->ri_depth; 473 wsd_fbip->cmsize = IGS_CMAP_SIZE; 474 #undef wsd_fbip 475 return (0); 476 477 case WSDISPLAYIO_GVIDEO: 478 *(u_int *)data = sc->sc_blanked ? 479 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON; 480 return (0); 481 482 case WSDISPLAYIO_SVIDEO: 483 turnoff = (*(u_int *)data == WSDISPLAYIO_VIDEO_OFF); 484 if (sc->sc_blanked != turnoff) { 485 sc->sc_blanked = turnoff; 486 igsfb_blank_screen(sc, sc->sc_blanked); 487 } 488 return (0); 489 490 case WSDISPLAYIO_GETCMAP: 491 return (igsfb_get_cmap(sc, (struct wsdisplay_cmap *)data)); 492 493 case WSDISPLAYIO_PUTCMAP: 494 return (igsfb_set_cmap(sc, (struct wsdisplay_cmap *)data)); 495 496 case WSDISPLAYIO_GCURMAX: 497 ((struct wsdisplay_curpos *)data)->x = IGS_CURSOR_MAX_SIZE; 498 ((struct wsdisplay_curpos *)data)->y = IGS_CURSOR_MAX_SIZE; 499 return (0); 500 501 case WSDISPLAYIO_GCURPOS: 502 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos; 503 return (0); 504 505 case WSDISPLAYIO_SCURPOS: 506 igsfb_set_curpos(sc, (struct wsdisplay_curpos *)data); 507 return (0); 508 509 case WSDISPLAYIO_GCURSOR: 510 return (igsfb_get_cursor(sc, (struct wsdisplay_cursor *)data)); 511 512 case WSDISPLAYIO_SCURSOR: 513 return (igsfb_set_cursor(sc, (struct wsdisplay_cursor *)data)); 514 } 515 516 return (EPASSTHROUGH); 517 } 518 519 520 /* 521 * wsdisplay_accessops: ioctl(WSDISPLAYIO_SVIDEO) 522 */ 523 static void 524 igsfb_blank_screen(sc, blank) 525 struct igsfb_softc *sc; 526 int blank; 527 { 528 529 igs_ext_write(sc->sc_iot, sc->sc_ioh, 530 IGS_EXT_SYNC_CTL, 531 blank ? IGS_EXT_SYNC_H0 | IGS_EXT_SYNC_V0 532 : 0); 533 } 534 535 536 /* 537 * wsdisplay_accessops: ioctl(WSDISPLAYIO_GETCMAP) 538 * Served from software cmap copy. 539 */ 540 static int 541 igsfb_get_cmap(sc, p) 542 struct igsfb_softc *sc; 543 struct wsdisplay_cmap *p; 544 { 545 u_int index = p->index, count = p->count; 546 547 if (index >= IGS_CMAP_SIZE || (index + count) > IGS_CMAP_SIZE) 548 return (EINVAL); 549 550 if (!uvm_useracc(p->red, count, B_WRITE) || 551 !uvm_useracc(p->green, count, B_WRITE) || 552 !uvm_useracc(p->blue, count, B_WRITE)) 553 return (EFAULT); 554 555 copyout(&sc->sc_cmap.r[index], p->red, count); 556 copyout(&sc->sc_cmap.g[index], p->green, count); 557 copyout(&sc->sc_cmap.b[index], p->blue, count); 558 559 return (0); 560 } 561 562 563 /* 564 * wsdisplay_accessops: ioctl(WSDISPLAYIO_SETCMAP) 565 * Set software cmap copy and propagate changed range to device. 566 */ 567 static int 568 igsfb_set_cmap(sc, p) 569 struct igsfb_softc *sc; 570 struct wsdisplay_cmap *p; 571 { 572 u_int index = p->index, count = p->count; 573 574 if (index >= IGS_CMAP_SIZE || (index + count) > IGS_CMAP_SIZE) 575 return (EINVAL); 576 577 if (!uvm_useracc(p->red, count, B_READ) || 578 !uvm_useracc(p->green, count, B_READ) || 579 !uvm_useracc(p->blue, count, B_READ)) 580 return (EFAULT); 581 582 copyin(p->red, &sc->sc_cmap.r[index], count); 583 copyin(p->green, &sc->sc_cmap.g[index], count); 584 copyin(p->blue, &sc->sc_cmap.b[index], count); 585 586 igsfb_update_cmap(sc, p->index, p->count); 587 588 return (0); 589 } 590 591 592 /* 593 * Propagate specified part of the software cmap copy to device. 594 */ 595 static void 596 igsfb_update_cmap(sc, index, count) 597 struct igsfb_softc *sc; 598 u_int index, count; 599 { 600 bus_space_tag_t t; 601 bus_space_handle_t h; 602 u_int last, i; 603 604 if (index >= IGS_CMAP_SIZE) 605 return; 606 607 last = index + count; 608 if (last > IGS_CMAP_SIZE) 609 last = IGS_CMAP_SIZE; 610 611 t = sc->sc_iot; 612 h = sc->sc_ioh; 613 614 /* start palette writing, index is autoincremented by hardware */ 615 bus_space_write_1(t, h, IGS_DAC_PEL_WRITE_IDX, index); 616 617 for (i = index; i < last; ++i) { 618 bus_space_write_1(t, h, IGS_DAC_PEL_DATA, sc->sc_cmap.r[i]); 619 bus_space_write_1(t, h, IGS_DAC_PEL_DATA, sc->sc_cmap.g[i]); 620 bus_space_write_1(t, h, IGS_DAC_PEL_DATA, sc->sc_cmap.b[i]); 621 } 622 } 623 624 625 /* 626 * wsdisplay_accessops: ioctl(WSDISPLAYIO_SCURPOS) 627 */ 628 static void 629 igsfb_set_curpos(sc, curpos) 630 struct igsfb_softc *sc; 631 struct wsdisplay_curpos *curpos; 632 { 633 struct rasops_info *ri = sc->sc_ri; 634 int x = curpos->x, y = curpos->y; 635 636 if (y < 0) 637 y = 0; 638 else if (y > ri->ri_height) 639 y = ri->ri_height; 640 if (x < 0) 641 x = 0; 642 else if (x > ri->ri_width) 643 x = ri->ri_width; 644 sc->sc_cursor.cc_pos.x = x; 645 sc->sc_cursor.cc_pos.y = y; 646 647 igsfb_update_curpos(sc); 648 } 649 650 651 static void 652 igsfb_update_curpos(sc) 653 struct igsfb_softc *sc; 654 { 655 bus_space_tag_t t; 656 bus_space_handle_t h; 657 int x, xoff, y, yoff; 658 659 xoff = 0; 660 x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x; 661 if (x < 0) { 662 x = 0; 663 xoff = -x; 664 } 665 666 yoff = 0; 667 y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y; 668 if (y < 0) { 669 y = 0; 670 yoff = -y; 671 } 672 673 t = sc->sc_iot; 674 h = sc->sc_ioh; 675 676 igs_ext_write(t, h, IGS_EXT_SPRITE_HSTART_LO, x & 0xff); 677 igs_ext_write(t, h, IGS_EXT_SPRITE_HSTART_HI, (x >> 8) & 0x07); 678 igs_ext_write(t, h, IGS_EXT_SPRITE_HPRESET, xoff & 0x3f); 679 680 igs_ext_write(t, h, IGS_EXT_SPRITE_VSTART_LO, y & 0xff); 681 igs_ext_write(t, h, IGS_EXT_SPRITE_VSTART_HI, (y >> 8) & 0x07); 682 igs_ext_write(t, h, IGS_EXT_SPRITE_VPRESET, yoff & 0x3f); 683 } 684 685 686 /* 687 * wsdisplay_accessops: ioctl(WSDISPLAYIO_GCURSOR) 688 */ 689 static int 690 igsfb_get_cursor(sc, p) 691 struct igsfb_softc *sc; 692 struct wsdisplay_cursor *p; 693 { 694 695 /* XXX: TODO */ 696 return (0); 697 } 698 699 700 /* 701 * wsdisplay_accessops: ioctl(WSDISPLAYIO_SCURSOR) 702 */ 703 static int 704 igsfb_set_cursor(sc, p) 705 struct igsfb_softc *sc; 706 struct wsdisplay_cursor *p; 707 { 708 struct igs_hwcursor *cc; 709 u_int v, index, count, icount, iwidth; 710 711 cc = &sc->sc_cursor; 712 v = p->which; 713 714 if (v & WSDISPLAY_CURSOR_DOCMAP) { 715 index = p->cmap.index; 716 count = p->cmap.count; 717 if (index >= 2 || (index + count) > 2) 718 return (EINVAL); 719 if (!uvm_useracc(p->cmap.red, count, B_READ) 720 || !uvm_useracc(p->cmap.green, count, B_READ) 721 || !uvm_useracc(p->cmap.blue, count, B_READ)) 722 return (EFAULT); 723 } 724 725 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 726 if (p->size.x > IGS_CURSOR_MAX_SIZE 727 || p->size.y > IGS_CURSOR_MAX_SIZE) 728 return (EINVAL); 729 730 iwidth = (p->size.x + 7) >> 3; /* bytes per scan line */ 731 icount = iwidth * p->size.y; 732 if (!uvm_useracc(p->image, icount, B_READ) 733 || !uvm_useracc(p->mask, icount, B_READ)) 734 return (EFAULT); 735 } 736 737 /* XXX: verify that hot is within size, pos within screen? */ 738 739 /* arguments verified, do the processing */ 740 741 if (v & WSDISPLAY_CURSOR_DOCUR) 742 sc->sc_curenb = p->enable; 743 744 if (v & WSDISPLAY_CURSOR_DOPOS) 745 cc->cc_pos = p->pos; 746 747 if (v & WSDISPLAY_CURSOR_DOHOT) 748 cc->cc_hot = p->hot; 749 750 if (v & WSDISPLAY_CURSOR_DOCMAP) { 751 copyin(p->cmap.red, &cc->cc_color[index], count); 752 copyin(p->cmap.green, &cc->cc_color[index + 2], count); 753 copyin(p->cmap.blue, &cc->cc_color[index + 4], count); 754 } 755 756 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 757 u_int trailing_bits; 758 759 copyin(p->image, cc->cc_image, icount); 760 copyin(p->mask, cc->cc_mask, icount); 761 cc->cc_size = p->size; 762 763 /* clear trailing bits in the "partial" mask bytes */ 764 trailing_bits = p->size.x & 0x07; 765 if (trailing_bits != 0) { 766 const u_int cutmask = ~((~0) << trailing_bits); 767 u_char *mp; 768 u_int i; 769 770 mp = cc->cc_mask + iwidth - 1; 771 for (i = 0; i < p->size.y; ++i) { 772 *mp &= cutmask; 773 mp += iwidth; 774 } 775 } 776 igsfb_convert_cursor_data(sc, iwidth, p->size.y); 777 } 778 779 igsfb_update_cursor(sc, v); 780 return (0); 781 } 782 783 /* 784 * Convert incoming 1bpp cursor image/mask into native 2bpp format. 785 */ 786 static void 787 igsfb_convert_cursor_data(sc, w, h) 788 struct igsfb_softc *sc; 789 u_int w, h; 790 { 791 struct igs_hwcursor *cc = &sc->sc_cursor; 792 struct igs_bittab *btab = sc->sc_bittab; 793 u_int8_t *ip, *mp; 794 u_int16_t *dp; 795 u_int line, i; 796 797 /* init sprite to be all transparent */ 798 memset(cc->cc_sprite, 0xaa, IGS_CURSOR_DATA_SIZE); 799 800 /* first scanline */ 801 ip = cc->cc_image; 802 mp = cc->cc_mask; 803 dp = cc->cc_sprite; 804 805 for (line = 0; line < h; ++line) { 806 for (i = 0; i < w; ++i) { 807 u_int16_t is = btab->iexpand[ip[i]]; 808 u_int16_t ms = btab->mexpand[mp[i]]; 809 810 /* NB: tables are pre-bswapped if needed */ 811 dp[i] = (0xaaaa & ~ms) | (is & ms); 812 } 813 814 /* next scanline */ 815 ip += w; 816 mp += w; 817 dp += 8; /* 2bpp, 8 pixels per short = 8 shorts */ 818 } 819 } 820 821 822 /* 823 * Propagate cursor changes to device. 824 * "which" is composed from WSDISPLAY_CURSOR_DO* bits. 825 */ 826 static void 827 igsfb_update_cursor(sc, which) 828 struct igsfb_softc *sc; 829 u_int which; 830 { 831 bus_space_tag_t iot = sc->sc_iot; 832 bus_space_handle_t ioh = sc->sc_ioh; 833 u_int8_t curctl; 834 835 /* 836 * We will need to tweak sprite control register for cursor 837 * visibility and cursor color map manipualtion. 838 */ 839 if (which & (WSDISPLAY_CURSOR_DOCUR | WSDISPLAY_CURSOR_DOCMAP)) { 840 curctl = igs_ext_read(iot, ioh, IGS_EXT_SPRITE_CTL); 841 } 842 843 if (which & WSDISPLAY_CURSOR_DOSHAPE) { 844 u_int8_t *dst = bus_space_vaddr(sc->sc_memt, sc->sc_crh); 845 846 /* 847 * memcpy between spaces of different endianness would 848 * be ... special. We cannot be sure if memset gonna 849 * push data in 4-byte chunks, we can't pre-bswap it, 850 * so do it byte-by-byte to preserve byte ordering. 851 */ 852 if (sc->sc_hwflags & IGSFB_HW_BSWAP) { 853 u_int8_t *src = (u_int8_t *)sc->sc_cursor.cc_sprite; 854 int i; 855 856 for (i = 0; i < 1024; ++i) 857 *dst++ = *src++; 858 } else { 859 memcpy(dst, sc->sc_cursor.cc_sprite, 1024); 860 } 861 } 862 863 if (which & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) { 864 /* code shared with WSDISPLAYIO_SCURPOS */ 865 igsfb_update_curpos(sc); 866 } 867 868 if (which & WSDISPLAY_CURSOR_DOCMAP) { 869 u_int8_t *p; 870 871 /* tell DAC we want access to the cursor palette */ 872 igs_ext_write(iot, ioh, IGS_EXT_SPRITE_CTL, 873 curctl | IGS_EXT_SPRITE_SELECT); 874 875 p = sc->sc_cursor.cc_color; 876 877 bus_space_write_1(iot, ioh, IGS_DAC_PEL_WRITE_IDX, 0); 878 bus_space_write_1(iot, ioh, IGS_DAC_PEL_DATA, p[0]); 879 bus_space_write_1(iot, ioh, IGS_DAC_PEL_DATA, p[2]); 880 bus_space_write_1(iot, ioh, IGS_DAC_PEL_DATA, p[4]); 881 882 bus_space_write_1(iot, ioh, IGS_DAC_PEL_WRITE_IDX, 1); 883 bus_space_write_1(iot, ioh, IGS_DAC_PEL_DATA, p[1]); 884 bus_space_write_1(iot, ioh, IGS_DAC_PEL_DATA, p[3]); 885 bus_space_write_1(iot, ioh, IGS_DAC_PEL_DATA, p[5]); 886 887 /* restore access to normal palette */ 888 igs_ext_write(iot, ioh, IGS_EXT_SPRITE_CTL, curctl); 889 } 890 891 if (which & WSDISPLAY_CURSOR_DOCUR) { 892 if ((curctl & IGS_EXT_SPRITE_VISIBLE) == 0 893 && sc->sc_curenb) 894 igs_ext_write(iot, ioh, IGS_EXT_SPRITE_CTL, 895 curctl | IGS_EXT_SPRITE_VISIBLE); 896 else if ((curctl & IGS_EXT_SPRITE_VISIBLE) != 0 897 && !sc->sc_curenb) 898 igs_ext_write(iot, ioh, IGS_EXT_SPRITE_CTL, 899 curctl & ~IGS_EXT_SPRITE_VISIBLE); 900 } 901 } 902 903 904 /* 905 * wsdisplay_accessops: alloc_screen() 906 */ 907 static int 908 igsfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp) 909 void *v; 910 const struct wsscreen_descr *type; 911 void **cookiep; 912 int *curxp, *curyp; 913 long *attrp; 914 { 915 916 /* TODO */ 917 return (ENOMEM); 918 } 919 920 921 /* 922 * wsdisplay_accessops: free_screen() 923 */ 924 static void 925 igsfb_free_screen(v, cookie) 926 void *v; 927 void *cookie; 928 { 929 930 /* TODO */ 931 return; 932 } 933 934 935 /* 936 * wsdisplay_accessops: show_screen() 937 */ 938 static int 939 igsfb_show_screen(v, cookie, waitok, cb, cbarg) 940 void *v; 941 void *cookie; 942 int waitok; 943 void (*cb)(void *, int, int); 944 void *cbarg; 945 { 946 947 return (0); 948 } 949