1 /* $OpenBSD: ifb.c,v 1.4 2008/12/27 17:23:01 miod Exp $ */ 2 3 /* 4 * Copyright (c) 2007, 2008 Miodrag Vallat. 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /* 20 * Least-effort driver for the Sun Expert3D cards (based on the 21 * ``Wildcat'' chips. 22 * 23 * There is no public documentation for these chips available. 24 * Since they are no longer supported by 3DLabs (which got bought by 25 * Creative), and Sun does not want to publish even minimal information 26 * or source code, the best we can do is experiment. 27 * 28 * Quoting Alan Coopersmith in 29 * http://mail.opensolaris.org/pipermail/opensolaris-discuss/2005-December/011885.html 30 * ``Unfortunately, the lawyers have asked we not give details about why 31 * specific components are not being released.'' 32 */ 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/device.h> 37 #include <sys/errno.h> 38 #include <sys/ioctl.h> 39 #include <sys/malloc.h> 40 #include <sys/pciio.h> 41 42 #include <uvm/uvm_extern.h> 43 44 #include <machine/autoconf.h> 45 #include <machine/bus.h> 46 #include <machine/intr.h> 47 #include <machine/openfirm.h> 48 49 #include <dev/pci/pcireg.h> 50 #include <dev/pci/pcivar.h> 51 #include <dev/pci/pcidevs.h> 52 53 #include <dev/wscons/wsconsio.h> 54 #include <dev/wscons/wsdisplayvar.h> 55 56 #include <dev/rasops/rasops.h> 57 58 #include <machine/fbvar.h> 59 60 /* 61 * Parts of the following hardware knowledge come from David S. Miller's 62 * XVR-500 Linux driver (drivers/video/sunxvr500.c). 63 */ 64 65 /* 66 * The Expert3D and Expert3d-Lite cards are built around the Wildcat 67 * 5110, 6210 and 7210 chips. 68 * 69 * The card exposes the following resources: 70 * - a 32MB aperture window in which views to the different frame buffer 71 * areas can be mapped, in the first BAR. 72 * - a 64KB PROM and registers area, in the second BAR, with the registers 73 * starting 32KB within this area. 74 * - a 8MB memory mapping, which purpose is unknown, in the third BAR. 75 * 76 * In the state the PROM leaves us in, the 8MB frame buffer windows map 77 * the video memory as interleaved stripes: 78 * - frame buffer #0 will map horizontal pixels 00-1f, 60-9f, e0-11f, etc. 79 * - frame buffer #1 will map horizontal pixels 20-5f, a0-df, 120-15f, etc. 80 * However the non-visible parts of each stripe can still be addressed 81 * (probably for fast screen switching). 82 * 83 * Unfortunately, since we do not know how to reconfigured the stripes 84 * to provide at least a linear frame buffer, we have to write to both 85 * windows and have them provide the complete image. This however leads 86 * to parasite overlays appearing sometimes in the screen... 87 */ 88 89 /* 90 * The Expert3D has an extra BAR that is not present on the -Lite 91 * version. This register contains bits that tell us how many BARs to 92 * skip before we get to the BARs that interest us. 93 */ 94 #define IFB_PCI_CFG 0x5c 95 #define IFB_PCI_CFG_BAR_OFFSET(x) ((x & 0x000000e0) >> 3) 96 97 #define IFB_REG_OFFSET 0x8000 98 99 /* 100 * 0040 component configuration 101 * This register controls which parts of the board will be addressed by 102 * writes to other configuration registers. 103 * Apparently the low two bytes control the frame buffer windows for the 104 * given head (starting at 1). 105 * The high two bytes are texture related. 106 */ 107 #define IFB_REG_COMPONENT_SELECT 0x0040 108 109 /* 110 * 0058 magnifying configuration 111 * This register apparently controls magnifying. 112 * bits 5-6 select the window width divider (00: by 2, 01: by 4, 10: by 8, 113 * 11: by 16) 114 * bits 7-8 select the zoom factor (00: disabled, 01: x2, 10: x4, 11: x8) 115 */ 116 #define IFB_REG_MAGNIFY 0x0058 117 #define IFB_REG_MAGNIFY_DISABLE 0x00000000 118 #define IFB_REG_MAGNIFY_X2 0x00000040 119 #define IFB_REG_MAGNIFY_X4 0x00000080 120 #define IFB_REG_MAGNIFY_X8 0x000000c0 121 #define IFB_REG_MAGNIFY_WINDIV2 0x00000000 122 #define IFB_REG_MAGNIFY_WINDIV4 0x00000010 123 #define IFB_REG_MAGNIFY_WINDIV8 0x00000020 124 #define IFB_REG_MAGNIFY_WINDIV16 0x00000030 125 126 /* 127 * 0070 display resolution 128 * Contains the size of the display, as ((height - 1) << 16) | (width - 1) 129 */ 130 #define IFB_REG_RESOLUTION 0x0070 131 /* 132 * 0074 configuration register 133 * Contains 0x1a000088 | ((Log2 stride) << 16) 134 */ 135 #define IFB_REG_CONFIG 0x0074 136 /* 137 * 0078 32bit frame buffer window #0 (8 to 9 MB) 138 * Contains the offset (relative to BAR0) of the 32 bit frame buffer window. 139 */ 140 #define IFB_REG_FB32_0 0x0078 141 /* 142 * 007c 32bit frame buffer window #1 (8 to 9 MB) 143 * Contains the offset (relative to BAR0) of the 32 bit frame buffer window. 144 */ 145 #define IFB_REG_FB32_1 0x007c 146 /* 147 * 0080 8bit frame buffer window #0 (2 to 2.2 MB) 148 * Contains the offset (relative to BAR0) of the 8 bit frame buffer window. 149 */ 150 #define IFB_REG_FB8_0 0x0080 151 /* 152 * 0084 8bit frame buffer window #1 (2 to 2.2 MB) 153 * Contains the offset (relative to BAR0) of the 8 bit frame buffer window. 154 */ 155 #define IFB_REG_FB8_1 0x0084 156 /* 157 * 0088 unknown window (as large as a 32 bit frame buffer) 158 */ 159 #define IFB_REG_FB_UNK0 0x0088 160 /* 161 * 008c unknown window (as large as a 8 bit frame buffer) 162 */ 163 #define IFB_REG_FB_UNK1 0x008c 164 /* 165 * 0090 unknown window (as large as a 8 bit frame buffer) 166 */ 167 #define IFB_REG_FB_UNK2 0x0090 168 169 /* 170 * 00bc RAMDAC palette index register 171 */ 172 #define IFB_REG_CMAP_INDEX 0x00bc 173 /* 174 * 00c0 RAMDAC palette data register 175 */ 176 #define IFB_REG_CMAP_DATA 0x00c0 177 178 /* 179 * 00e4 DPMS state register 180 * States ``off'' and ``suspend'' need chip reprogramming before video can 181 * be enabled again. 182 */ 183 #define IFB_REG_DPMS_STATE 0x00e4 184 #define IFB_REG_DPMS_OFF 0x00000000 185 #define IFB_REG_DPMS_SUSPEND 0x00000001 186 #define IFB_REG_DPMS_STANDBY 0x00000002 187 #define IFB_REG_DPMS_ON 0x00000003 188 189 struct ifb_softc { 190 struct sunfb sc_sunfb; 191 int sc_nscreens; 192 193 bus_space_tag_t sc_mem_t; 194 pcitag_t sc_pcitag; 195 196 bus_space_handle_t sc_mem_h; 197 bus_addr_t sc_membase; 198 bus_size_t sc_memlen; 199 vaddr_t sc_memvaddr, sc_fb8bank0_vaddr, sc_fb8bank1_vaddr; 200 bus_space_handle_t sc_reg_h; 201 202 struct wsdisplay_emulops sc_old_ops; 203 void (*sc_old_cursor)(struct rasops_info *); 204 205 int sc_console; 206 u_int8_t sc_cmap_red[256]; 207 u_int8_t sc_cmap_green[256]; 208 u_int8_t sc_cmap_blue[256]; 209 }; 210 211 int ifb_ioctl(void *, u_long, caddr_t, int, struct proc *); 212 paddr_t ifb_mmap(void *, off_t, int); 213 void ifb_burner(void *, u_int, u_int); 214 215 struct wsdisplay_accessops ifb_accessops = { 216 ifb_ioctl, 217 ifb_mmap, 218 NULL, /* alloc_screen */ 219 NULL, /* free_screen */ 220 NULL, /* show_screen */ 221 NULL, /* load_font */ 222 NULL, /* scrollback */ 223 NULL, /* getchar */ 224 ifb_burner, 225 NULL /* pollc */ 226 }; 227 228 int ifbmatch(struct device *, void *, void *); 229 void ifbattach(struct device *, struct device *, void *); 230 231 struct cfattach ifb_ca = { 232 sizeof (struct ifb_softc), ifbmatch, ifbattach 233 }; 234 235 struct cfdriver ifb_cd = { 236 NULL, "ifb", DV_DULL 237 }; 238 239 int ifb_mapregs(struct ifb_softc *, struct pci_attach_args *); 240 int ifb_is_console(int); 241 int ifb_getcmap(struct ifb_softc *, struct wsdisplay_cmap *); 242 int ifb_putcmap(struct ifb_softc *, struct wsdisplay_cmap *); 243 void ifb_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t); 244 245 void ifb_putchar(void *, int, int, u_int, long); 246 void ifb_copycols(void *, int, int, int, int); 247 void ifb_erasecols(void *, int, int, int, long); 248 void ifb_copyrows(void *, int, int, int); 249 void ifb_eraserows(void *, int, int, long); 250 void ifb_do_cursor(struct rasops_info *); 251 252 const struct pci_matchid ifb_devices[] = { 253 { PCI_VENDOR_INTERGRAPH, PCI_PRODUCT_INTERGRAPH_EXPERT3D }, 254 { PCI_VENDOR_3DLABS, PCI_PRODUCT_3DLABS_WILDCAT_6210 }, 255 { PCI_VENDOR_3DLABS, PCI_PRODUCT_3DLABS_WILDCAT_5110 },/* Sun XVR-500 */ 256 { PCI_VENDOR_3DLABS, PCI_PRODUCT_3DLABS_WILDCAT_7210 }, 257 }; 258 259 int 260 ifbmatch(struct device *parent, void *cf, void *aux) 261 { 262 struct pci_attach_args *paa = aux; 263 int node; 264 char *name; 265 266 if (pci_matchbyid(paa, ifb_devices, 267 sizeof(ifb_devices) / sizeof(ifb_devices[0])) != 0) 268 return 1; 269 270 node = PCITAG_NODE(paa->pa_tag); 271 name = getpropstring(node, "name"); 272 if (strcmp(name, "SUNW,Expert3D") == 0 || 273 strcmp(name, "SUNW,Expert3D-Lite") == 0) 274 return 1; 275 276 return 0; 277 } 278 279 void 280 ifbattach(struct device *parent, struct device *self, void *aux) 281 { 282 struct ifb_softc *sc = (struct ifb_softc *)self; 283 struct pci_attach_args *paa = aux; 284 struct rasops_info *ri; 285 int node; 286 287 sc->sc_mem_t = paa->pa_memt; 288 sc->sc_pcitag = paa->pa_tag; 289 290 printf("\n"); 291 292 if (ifb_mapregs(sc, paa)) 293 return; 294 295 sc->sc_memvaddr = (vaddr_t)bus_space_vaddr(sc->sc_mem_t, sc->sc_mem_h); 296 sc->sc_fb8bank0_vaddr = sc->sc_memvaddr + 297 bus_space_read_4(sc->sc_mem_t, sc->sc_reg_h, 298 IFB_REG_OFFSET + IFB_REG_FB8_0) - sc->sc_membase; 299 sc->sc_fb8bank1_vaddr = sc->sc_memvaddr + 300 bus_space_read_4(sc->sc_mem_t, sc->sc_reg_h, 301 IFB_REG_OFFSET + IFB_REG_FB8_1) - sc->sc_membase; 302 303 node = PCITAG_NODE(paa->pa_tag); 304 sc->sc_console = ifb_is_console(node); 305 306 fb_setsize(&sc->sc_sunfb, 8, 1152, 900, node, 0); 307 308 printf("%s: %dx%d\n", 309 self->dv_xname, sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height); 310 311 #if 0 312 /* 313 * Make sure the frame buffer is configured to sane values. 314 * So much more is needed there... documentation permitting. 315 */ 316 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 317 IFB_REG_OFFSET + IFB_REG_COMPONENT_SELECT, 0x00000101); 318 delay(1000); 319 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 320 IFB_REG_OFFSET + IFB_REG_MAGNIFY, IFB_REG_MAGNIFY_DISABLE); 321 #endif 322 323 ri = &sc->sc_sunfb.sf_ro; 324 ri->ri_bits = NULL; 325 ri->ri_hw = sc; 326 327 fbwscons_init(&sc->sc_sunfb, RI_BSWAP, sc->sc_console); 328 ri->ri_flg &= ~RI_FULLCLEAR; /* due to the way we handle updates */ 329 330 if (!sc->sc_console) { 331 bzero((void *)sc->sc_fb8bank0_vaddr, sc->sc_sunfb.sf_fbsize); 332 bzero((void *)sc->sc_fb8bank1_vaddr, sc->sc_sunfb.sf_fbsize); 333 } 334 335 /* pick centering delta */ 336 sc->sc_fb8bank0_vaddr += ri->ri_bits - ri->ri_origbits; 337 sc->sc_fb8bank1_vaddr += ri->ri_bits - ri->ri_origbits; 338 339 sc->sc_old_ops = ri->ri_ops; /* structure copy */ 340 sc->sc_old_cursor = ri->ri_do_cursor; 341 ri->ri_ops.copyrows = ifb_copyrows; 342 ri->ri_ops.copycols = ifb_copycols; 343 ri->ri_ops.eraserows = ifb_eraserows; 344 ri->ri_ops.erasecols = ifb_erasecols; 345 ri->ri_ops.putchar = ifb_putchar; 346 ri->ri_do_cursor = ifb_do_cursor; 347 348 fbwscons_setcolormap(&sc->sc_sunfb, ifb_setcolor); 349 if (sc->sc_console) 350 fbwscons_console_init(&sc->sc_sunfb, -1); 351 fbwscons_attach(&sc->sc_sunfb, &ifb_accessops, sc->sc_console); 352 } 353 354 int 355 ifb_ioctl(void *v, u_long cmd, caddr_t data, int flags, struct proc *p) 356 { 357 struct ifb_softc *sc = v; 358 struct wsdisplay_fbinfo *wdf; 359 struct pcisel *sel; 360 361 switch (cmd) { 362 case WSDISPLAYIO_GTYPE: 363 *(u_int *)data = WSDISPLAY_TYPE_UNKNOWN; 364 break; 365 366 case WSDISPLAYIO_SMODE: 367 if (*(u_int *)data == WSDISPLAYIO_MODE_EMUL) 368 fbwscons_setcolormap(&sc->sc_sunfb, ifb_setcolor); 369 break; 370 case WSDISPLAYIO_GINFO: 371 wdf = (void *)data; 372 wdf->height = sc->sc_sunfb.sf_height; 373 wdf->width = sc->sc_sunfb.sf_width; 374 wdf->depth = sc->sc_sunfb.sf_depth; 375 wdf->cmsize = 256; 376 break; 377 case WSDISPLAYIO_LINEBYTES: 378 *(u_int *)data = sc->sc_sunfb.sf_linebytes; 379 break; 380 381 case WSDISPLAYIO_GETCMAP: 382 return ifb_getcmap(sc, (struct wsdisplay_cmap *)data); 383 case WSDISPLAYIO_PUTCMAP: 384 return ifb_putcmap(sc, (struct wsdisplay_cmap *)data); 385 386 case WSDISPLAYIO_GPCIID: 387 sel = (struct pcisel *)data; 388 sel->pc_bus = PCITAG_BUS(sc->sc_pcitag); 389 sel->pc_dev = PCITAG_DEV(sc->sc_pcitag); 390 sel->pc_func = PCITAG_FUN(sc->sc_pcitag); 391 break; 392 393 case WSDISPLAYIO_SVIDEO: 394 case WSDISPLAYIO_GVIDEO: 395 break; 396 397 case WSDISPLAYIO_GCURPOS: 398 case WSDISPLAYIO_SCURPOS: 399 case WSDISPLAYIO_GCURMAX: 400 case WSDISPLAYIO_GCURSOR: 401 case WSDISPLAYIO_SCURSOR: 402 default: 403 return -1; /* not supported yet */ 404 } 405 406 return 0; 407 } 408 409 int 410 ifb_getcmap(struct ifb_softc *sc, struct wsdisplay_cmap *cm) 411 { 412 u_int index = cm->index; 413 u_int count = cm->count; 414 int error; 415 416 if (index >= 256 || count > 256 - index) 417 return EINVAL; 418 419 error = copyout(&sc->sc_cmap_red[index], cm->red, count); 420 if (error) 421 return error; 422 error = copyout(&sc->sc_cmap_green[index], cm->green, count); 423 if (error) 424 return error; 425 error = copyout(&sc->sc_cmap_blue[index], cm->blue, count); 426 if (error) 427 return error; 428 return 0; 429 } 430 431 int 432 ifb_putcmap(struct ifb_softc *sc, struct wsdisplay_cmap *cm) 433 { 434 u_int index = cm->index; 435 u_int count = cm->count; 436 u_int i; 437 int error; 438 u_char *r, *g, *b; 439 440 if (index >= 256 || count > 256 - index) 441 return EINVAL; 442 443 if ((error = copyin(cm->red, &sc->sc_cmap_red[index], count)) != 0) 444 return error; 445 if ((error = copyin(cm->green, &sc->sc_cmap_green[index], count)) != 0) 446 return error; 447 if ((error = copyin(cm->blue, &sc->sc_cmap_blue[index], count)) != 0) 448 return error; 449 450 r = &sc->sc_cmap_red[index]; 451 g = &sc->sc_cmap_green[index]; 452 b = &sc->sc_cmap_blue[index]; 453 454 for (i = 0; i < count; i++) { 455 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 456 IFB_REG_OFFSET + IFB_REG_CMAP_INDEX, index); 457 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 458 IFB_REG_OFFSET + IFB_REG_CMAP_DATA, 459 (((u_int)*b) << 22) | (((u_int)*g) << 12) | (((u_int)*r) << 2)); 460 r++, g++, b++, index++; 461 } 462 return 0; 463 } 464 465 void 466 ifb_setcolor(void *v, u_int index, u_int8_t r, u_int8_t g, u_int8_t b) 467 { 468 struct ifb_softc *sc = v; 469 470 sc->sc_cmap_red[index] = r; 471 sc->sc_cmap_green[index] = g; 472 sc->sc_cmap_blue[index] = b; 473 474 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 475 IFB_REG_OFFSET + IFB_REG_CMAP_INDEX, index); 476 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 477 IFB_REG_OFFSET + IFB_REG_CMAP_DATA, 478 (((u_int)b) << 22) | (((u_int)g) << 12) | (((u_int)r) << 2)); 479 } 480 481 paddr_t 482 ifb_mmap(void *v, off_t off, int prot) 483 { 484 return -1; 485 } 486 487 void 488 ifb_burner(void *v, u_int on, u_int flags) 489 { 490 struct ifb_softc *sc = (struct ifb_softc *)v; 491 int s; 492 uint32_t dpms; 493 494 s = splhigh(); 495 if (on) 496 dpms = IFB_REG_DPMS_ON; 497 else { 498 #ifdef notyet 499 if (flags & WSDISPLAY_BURN_VBLANK) 500 dpms = IFB_REG_DPMS_SUSPEND; 501 else 502 #endif 503 dpms = IFB_REG_DPMS_STANDBY; 504 } 505 bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, 506 IFB_REG_OFFSET + IFB_REG_DPMS_STATE, dpms); 507 splx(s); 508 } 509 510 int 511 ifb_is_console(int node) 512 { 513 extern int fbnode; 514 515 return fbnode == node; 516 } 517 518 int 519 ifb_mapregs(struct ifb_softc *sc, struct pci_attach_args *pa) 520 { 521 u_int32_t cf; 522 int bar, rc; 523 524 cf = pci_conf_read(pa->pa_pc, pa->pa_tag, IFB_PCI_CFG); 525 bar = PCI_MAPREG_START + IFB_PCI_CFG_BAR_OFFSET(cf); 526 527 cf = pci_conf_read(pa->pa_pc, pa->pa_tag, bar); 528 if (PCI_MAPREG_TYPE(cf) == PCI_MAPREG_TYPE_IO) 529 rc = EINVAL; 530 else { 531 rc = pci_mapreg_map(pa, bar, cf, 532 BUS_SPACE_MAP_LINEAR, NULL, &sc->sc_mem_h, 533 &sc->sc_membase, &sc->sc_memlen, 0); 534 } 535 if (rc != 0) { 536 printf("%s: can't map video memory\n", 537 sc->sc_sunfb.sf_dev.dv_xname); 538 return rc; 539 } 540 541 cf = pci_conf_read(pa->pa_pc, pa->pa_tag, bar + 4); 542 if (PCI_MAPREG_TYPE(cf) == PCI_MAPREG_TYPE_IO) 543 rc = EINVAL; 544 else { 545 rc = pci_mapreg_map(pa, bar + 4, cf, 546 0, NULL, &sc->sc_reg_h, NULL, NULL, 0x9000); 547 } 548 if (rc != 0) { 549 printf("%s: can't map register space\n", 550 sc->sc_sunfb.sf_dev.dv_xname); 551 return rc; 552 } 553 554 return 0; 555 } 556 557 void 558 ifb_putchar(void *cookie, int row, int col, u_int uc, long attr) 559 { 560 struct rasops_info *ri = cookie; 561 struct ifb_softc *sc = ri->ri_hw; 562 563 ri->ri_bits = (void *)sc->sc_fb8bank0_vaddr; 564 sc->sc_old_ops.putchar(cookie, row, col, uc, attr); 565 ri->ri_bits = (void *)sc->sc_fb8bank1_vaddr; 566 sc->sc_old_ops.putchar(cookie, row, col, uc, attr); 567 } 568 569 void 570 ifb_copycols(void *cookie, int row, int src, int dst, int num) 571 { 572 struct rasops_info *ri = cookie; 573 struct ifb_softc *sc = ri->ri_hw; 574 575 ri->ri_bits = (void *)sc->sc_fb8bank0_vaddr; 576 sc->sc_old_ops.copycols(cookie, row, src, dst, num); 577 ri->ri_bits = (void *)sc->sc_fb8bank1_vaddr; 578 sc->sc_old_ops.copycols(cookie, row, src, dst, num); 579 } 580 581 void 582 ifb_erasecols(void *cookie, int row, int col, int num, long attr) 583 { 584 struct rasops_info *ri = cookie; 585 struct ifb_softc *sc = ri->ri_hw; 586 587 ri->ri_bits = (void *)sc->sc_fb8bank0_vaddr; 588 sc->sc_old_ops.erasecols(cookie, row, col, num, attr); 589 ri->ri_bits = (void *)sc->sc_fb8bank1_vaddr; 590 sc->sc_old_ops.erasecols(cookie, row, col, num, attr); 591 } 592 593 void 594 ifb_copyrows(void *cookie, int src, int dst, int num) 595 { 596 struct rasops_info *ri = cookie; 597 struct ifb_softc *sc = ri->ri_hw; 598 599 ri->ri_bits = (void *)sc->sc_fb8bank0_vaddr; 600 sc->sc_old_ops.copyrows(cookie, src, dst, num); 601 ri->ri_bits = (void *)sc->sc_fb8bank1_vaddr; 602 sc->sc_old_ops.copyrows(cookie, src, dst, num); 603 } 604 605 void 606 ifb_eraserows(void *cookie, int row, int num, long attr) 607 { 608 struct rasops_info *ri = cookie; 609 struct ifb_softc *sc = ri->ri_hw; 610 611 ri->ri_bits = (void *)sc->sc_fb8bank0_vaddr; 612 sc->sc_old_ops.eraserows(cookie, row, num, attr); 613 ri->ri_bits = (void *)sc->sc_fb8bank1_vaddr; 614 sc->sc_old_ops.eraserows(cookie, row, num, attr); 615 } 616 617 void 618 ifb_do_cursor(struct rasops_info *ri) 619 { 620 struct ifb_softc *sc = ri->ri_hw; 621 622 ri->ri_bits = (void *)sc->sc_fb8bank0_vaddr; 623 sc->sc_old_cursor(ri); 624 ri->ri_bits = (void *)sc->sc_fb8bank1_vaddr; 625 sc->sc_old_cursor(ri); 626 } 627