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