summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorMiod Vallat <miod@cvs.openbsd.org>2008-03-23 20:07:22 +0000
committerMiod Vallat <miod@cvs.openbsd.org>2008-03-23 20:07:22 +0000
commitd7587c033f6201d88394130514279ca9634466aa (patch)
tree47d355ce67a051a0ab84f9d7a308d66bf861fc1a /sys
parent712a5571ca24ceaa215282115ec90a3520b6a71d (diff)
Not-functional-enough driver for the Sun Expert3D cards, put in tree as an
incentive for further tinkering only; not for the faint of heart.
Diffstat (limited to 'sys')
-rw-r--r--sys/arch/sparc64/conf/files.sparc646
-rw-r--r--sys/arch/sparc64/dev/ifb.c653
2 files changed, 658 insertions, 1 deletions
diff --git a/sys/arch/sparc64/conf/files.sparc64 b/sys/arch/sparc64/conf/files.sparc64
index f0b22d27137..dccf3ca42c8 100644
--- a/sys/arch/sparc64/conf/files.sparc64
+++ b/sys/arch/sparc64/conf/files.sparc64
@@ -1,4 +1,4 @@
-# $OpenBSD: files.sparc64,v 1.103 2008/03/16 22:21:27 kettenis Exp $
+# $OpenBSD: files.sparc64,v 1.104 2008/03/23 20:07:21 miod Exp $
# $NetBSD: files.sparc64,v 1.50 2001/08/10 20:53:50 eeh Exp $
# maxpartitions must be first item in files.${ARCH}
@@ -113,6 +113,10 @@ device vgafb: wsemuldisplaydev, rasops_bswap, rasops8, rasops16, rasops32
attach vgafb at pci
file arch/sparc64/dev/vgafb.c vgafb
+device ifb: wsemuldisplaydev, rasops8
+attach ifb at pci
+file arch/sparc64/dev/ifb.c ifb
+
# IOMMU is for both sbus and pci
file arch/sparc64/dev/iommu.c sbus | psycho | schizo | pyro | vpci
file arch/sparc64/dev/viommu.c vpci
diff --git a/sys/arch/sparc64/dev/ifb.c b/sys/arch/sparc64/dev/ifb.c
new file mode 100644
index 00000000000..6cdd2028d1e
--- /dev/null
+++ b/sys/arch/sparc64/dev/ifb.c
@@ -0,0 +1,653 @@
+/* $OpenBSD: ifb.c,v 1.1 2008/03/23 20:07:21 miod Exp $ */
+
+/*
+ * Copyright (c) 2007, 2008 Miodrag Vallat.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Least-effort driver for the Sun Expert3D cards (based on the
+ * ``Wildcat'' chips.
+ *
+ * There is no public documentation for these chips available.
+ * Since they are no longer supported by 3DLabs (which got bought by
+ * Creative), and Sun does not want to publish even minimal information
+ * or source code, the best we can do is experiment.
+ *
+ * Quoting Alan Coopersmith in
+ * http://mail.opensolaris.org/pipermail/opensolaris-discuss/2005-December/0118885.html
+ * ``Unfortunately, the lawyers have asked we not give details about why
+ * specific components are not being released.''
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <sys/malloc.h>
+#include <sys/pciio.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <machine/autoconf.h>
+#include <machine/bus.h>
+#include <machine/intr.h>
+#include <machine/openfirm.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcidevs.h>
+
+#include <dev/wscons/wsconsio.h>
+#include <dev/wscons/wsdisplayvar.h>
+
+#include <dev/rasops/rasops.h>
+
+#include <machine/fbvar.h>
+
+/*
+ * Parts of the following hardware knowledge come from David S. Miller's
+ * XVR-500 Linux driver (drivers/video/sunxvr500.c).
+ */
+
+/*
+ * The Expert3D and Expert3d-Lite cards are built around the Wildcat
+ * 5110, 6210 and 7210 chips.
+ *
+ * The card exposes the following resources:
+ * - a 32MB aperture window in which views to the different frame buffer
+ * areas can be mapped, in the first BAR.
+ * - a 64KB PROM and registers area, in the second BAR, with the registers
+ * starting 32KB within this area.
+ * - a 8MB memory mapping, which purpose is unknown, in the third BAR.
+ *
+ * In the state the PROM leaves us in, the 8MB frame buffer windows map
+ * the video memory as interleaved stripes:
+ * - frame buffer #0 will map horizontal pixels 00-1f, 60-9f, e0-11f, etc.
+ * - frame buffer #1 will map horizontal pixels 20-5f, a0-df, 120-15f, etc.
+ * However the non-visible parts of each stripe can still be addressed
+ * (probably for fast screen switching).
+ *
+ * Unfortunately, since we do not know how to reconfigured the stripes
+ * to provide at least a linear frame buffer, we have to write to both
+ * windows and have them provide the complete image. This however leads
+ * to parasite overlays appearing sometimes in the screen...
+ */
+
+#define IFB_REG_OFFSET 0x8000
+
+/*
+ * 0040 component configuration
+ * This register controls which parts of the board will be addressed by
+ * writes to other configuration registers.
+ * Apparently the low two bytes control the frame buffer windows for the
+ * given head (starting at 1).
+ * The high two bytes are texture related.
+ */
+#define IFB_REG_COMPONENT_SELECT 0x0040
+
+/*
+ * 0058 magnifying configuration
+ * This register apparently controls magnifying.
+ * bits 5-6 select the window width divider (00: by 2, 01: by 4, 10: by 8,
+ * 11: by 16)
+ * bits 7-8 select the zoom factor (00: disabled, 01: x2, 10: x4, 11: x8)
+ */
+#define IFB_REG_MAGNIFY 0x0058
+#define IFB_REG_MAGNIFY_DISABLE 0x00000000
+#define IFB_REG_MAGNIFY_X2 0x00000040
+#define IFB_REG_MAGNIFY_X4 0x00000080
+#define IFB_REG_MAGNIFY_X8 0x000000c0
+#define IFB_REG_MAGNIFY_WINDIV2 0x00000000
+#define IFB_REG_MAGNIFY_WINDIV4 0x00000010
+#define IFB_REG_MAGNIFY_WINDIV8 0x00000020
+#define IFB_REG_MAGNIFY_WINDIV16 0x00000030
+
+/*
+ * 0070 display resolution
+ * Contains the size of the display, as ((height - 1) << 16) | (width - 1)
+ */
+#define IFB_REG_RESOLUTION 0x0070
+/*
+ * 0074 configuration register
+ * Contains 0x1a000088 | ((Log2 stride) << 16)
+ */
+#define IFB_REG_CONFIG 0x0074
+/*
+ * 0078 32bit frame buffer window #0 (8 to 9 MB)
+ * Contains the offset (relative to BAR0) of the 32 bit frame buffer window.
+ */
+#define IFB_REG_FB32_0 0x0078
+/*
+ * 007c 32bit frame buffer window #1 (8 to 9 MB)
+ * Contains the offset (relative to BAR0) of the 32 bit frame buffer window.
+ */
+#define IFB_REG_FB32_1 0x007c
+/*
+ * 0080 8bit frame buffer window #0 (2 to 2.2 MB)
+ * Contains the offset (relative to BAR0) of the 8 bit frame buffer window.
+ */
+#define IFB_REG_FB8_0 0x0080
+/*
+ * 0084 8bit frame buffer window #1 (2 to 2.2 MB)
+ * Contains the offset (relative to BAR0) of the 8 bit frame buffer window.
+ */
+#define IFB_REG_FB8_1 0x0084
+/*
+ * 0088 unknown window (as large as a 32 bit frame buffer)
+ */
+#define IFB_REG_FB_UNK0 0x0088
+/*
+ * 008c unknown window (as large as a 8 bit frame buffer)
+ */
+#define IFB_REG_FB_UNK1 0x008c
+/*
+ * 0090 unknown window (as large as a 8 bit frame buffer)
+ */
+#define IFB_REG_FB_UNK2 0x0090
+
+/*
+ * 00bc RAMDAC palette index register
+ */
+#define IFB_REG_CMAP_INDEX 0x00bc
+/*
+ * 00c0 RAMDAC palette data register
+ */
+#define IFB_REG_CMAP_DATA 0x00c0
+
+/*
+ * 00e4 DPMS state register
+ * States ``off'' and ``suspend'' need chip reprogramming before video can
+ * be enabled again.
+ */
+#define IFB_REG_DPMS_STATE 0x00e4
+#define IFB_REG_DPMS_OFF 0x00000000
+#define IFB_REG_DPMS_SUSPEND 0x00000001
+#define IFB_REG_DPMS_STANDBY 0x00000002
+#define IFB_REG_DPMS_ON 0x00000003
+
+struct ifb_softc {
+ struct sunfb sc_sunfb;
+ int sc_nscreens;
+
+ bus_space_tag_t sc_mem_t;
+ pcitag_t sc_pcitag;
+
+ bus_space_handle_t sc_mem_h;
+ bus_addr_t sc_membase;
+ bus_size_t sc_memlen;
+ vaddr_t sc_memvaddr, sc_fb8bank0_vaddr, sc_fb8bank1_vaddr;
+ bus_space_handle_t sc_reg_h;
+
+ struct wsdisplay_emulops sc_old_ops;
+ void (*sc_old_cursor)(struct rasops_info *);
+
+ int sc_console;
+ u_int8_t sc_cmap_red[256];
+ u_int8_t sc_cmap_green[256];
+ u_int8_t sc_cmap_blue[256];
+};
+
+int ifb_ioctl(void *, u_long, caddr_t, int, struct proc *);
+paddr_t ifb_mmap(void *, off_t, int);
+int ifb_alloc_screen(void *, const struct wsscreen_descr *, void **,
+ int *, int *, long *);
+void ifb_free_screen(void *, void *);
+int ifb_show_screen(void *, void *, int,
+ void (*cb)(void *, int, int), void *);
+void ifb_burner(void *, u_int, u_int);
+
+struct wsdisplay_accessops ifb_accessops = {
+ ifb_ioctl,
+ ifb_mmap,
+ ifb_alloc_screen,
+ ifb_free_screen,
+ ifb_show_screen,
+ NULL,
+ NULL,
+ NULL,
+ ifb_burner
+};
+
+int ifbmatch(struct device *, void *, void *);
+void ifbattach(struct device *, struct device *, void *);
+
+struct cfattach ifb_ca = {
+ sizeof (struct ifb_softc), ifbmatch, ifbattach
+};
+
+struct cfdriver ifb_cd = {
+ NULL, "ifb", DV_DULL
+};
+
+int ifb_mapregs(struct ifb_softc *, struct pci_attach_args *);
+int ifb_is_console(int);
+int ifb_getcmap(struct ifb_softc *, struct wsdisplay_cmap *);
+int ifb_putcmap(struct ifb_softc *, struct wsdisplay_cmap *);
+void ifb_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t);
+
+void ifb_putchar(void *, int, int, u_int, long);
+void ifb_copycols(void *, int, int, int, int);
+void ifb_erasecols(void *, int, int, int, long);
+void ifb_copyrows(void *, int, int, int);
+void ifb_eraserows(void *, int, int, long);
+void ifb_do_cursor(struct rasops_info *);
+
+const struct pci_matchid ifb_devices[] = {
+ { PCI_VENDOR_INTERGRAPH, PCI_PRODUCT_INTERGRAPH_EXPERT3D },
+ { PCI_VENDOR_3DLABS, PCI_PRODUCT_3DLABS_WILDCAT_6210 },
+ { PCI_VENDOR_3DLABS, PCI_PRODUCT_3DLABS_WILDCAT_5110 },/* Sun XVR-500 */
+ { PCI_VENDOR_3DLABS, PCI_PRODUCT_3DLABS_WILDCAT_7210 },
+};
+
+int
+ifbmatch(struct device *parent, void *cf, void *aux)
+{
+ struct pci_attach_args *paa = aux;
+ int node;
+ char *name;
+
+ if (pci_matchbyid(paa, ifb_devices,
+ sizeof(ifb_devices) / sizeof(ifb_devices[0])) != 0)
+ return 1;
+
+ node = PCITAG_NODE(paa->pa_tag);
+ name = getpropstring(node, "name");
+ if (strcmp(name, "SUNW,Expert3D") == 0 ||
+ strcmp(name, "SUNW,Expert3D-Lite") == 0)
+ return 1;
+
+ return 0;
+}
+
+void
+ifbattach(struct device *parent, struct device *self, void *aux)
+{
+ struct ifb_softc *sc = (struct ifb_softc *)self;
+ struct pci_attach_args *paa = aux;
+ struct rasops_info *ri;
+ int node;
+
+ sc->sc_mem_t = paa->pa_memt;
+ sc->sc_pcitag = paa->pa_tag;
+
+ printf("\n");
+
+ if (ifb_mapregs(sc, paa))
+ return;
+
+ sc->sc_memvaddr = (vaddr_t)bus_space_vaddr(sc->sc_mem_t, sc->sc_mem_h);
+ sc->sc_fb8bank0_vaddr = sc->sc_memvaddr +
+ bus_space_read_4(sc->sc_mem_t, sc->sc_reg_h,
+ IFB_REG_OFFSET + IFB_REG_FB8_0) - sc->sc_membase;
+ sc->sc_fb8bank1_vaddr = sc->sc_memvaddr +
+ bus_space_read_4(sc->sc_mem_t, sc->sc_reg_h,
+ IFB_REG_OFFSET + IFB_REG_FB8_1) - sc->sc_membase;
+
+ node = PCITAG_NODE(paa->pa_tag);
+ sc->sc_console = ifb_is_console(node);
+
+ fb_setsize(&sc->sc_sunfb, 8, 1152, 900, node, 0);
+
+ printf("%s: %dx%d\n",
+ self->dv_xname, sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height);
+
+#if 0
+ /*
+ * Make sure the frame buffer is configured to sane values.
+ * So much more is needed there... documentation permitting.
+ */
+ bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
+ IFB_REG_OFFSET + IFB_REG_COMPONENT_SELECT, 0x00000101);
+ delay(1000);
+ bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
+ IFB_REG_OFFSET + IFB_REG_MAGNIFY, IFB_REG_MAGNIFY_DISABLE);
+#endif
+
+ ri = &sc->sc_sunfb.sf_ro;
+ ri->ri_bits = NULL;
+ ri->ri_hw = sc;
+
+ /* do NOT pass RI_CLEAR yet */
+ fbwscons_init(&sc->sc_sunfb, RI_BSWAP);
+ ri->ri_flg &= ~RI_FULLCLEAR; /* due to the way we handle updates */
+
+ if (!sc->sc_console) {
+ bzero((void *)sc->sc_fb8bank0_vaddr, sc->sc_sunfb.sf_fbsize);
+ bzero((void *)sc->sc_fb8bank1_vaddr, sc->sc_sunfb.sf_fbsize);
+ }
+
+ /* pick centering delta */
+ sc->sc_fb8bank0_vaddr += ri->ri_bits - ri->ri_origbits;
+ sc->sc_fb8bank1_vaddr += ri->ri_bits - ri->ri_origbits;
+
+ sc->sc_old_ops = ri->ri_ops; /* structure copy */
+ sc->sc_old_cursor = ri->ri_do_cursor;
+ ri->ri_ops.copyrows = ifb_copyrows;
+ ri->ri_ops.copycols = ifb_copycols;
+ ri->ri_ops.eraserows = ifb_eraserows;
+ ri->ri_ops.erasecols = ifb_erasecols;
+ ri->ri_ops.putchar = ifb_putchar;
+ ri->ri_do_cursor = ifb_do_cursor;
+
+ fbwscons_setcolormap(&sc->sc_sunfb, ifb_setcolor);
+ if (sc->sc_console)
+ fbwscons_console_init(&sc->sc_sunfb, -1);
+ fbwscons_attach(&sc->sc_sunfb, &ifb_accessops, sc->sc_console);
+}
+
+int
+ifb_ioctl(void *v, u_long cmd, caddr_t data, int flags, struct proc *p)
+{
+ struct ifb_softc *sc = v;
+ struct wsdisplay_fbinfo *wdf;
+ struct pcisel *sel;
+
+ switch (cmd) {
+ case WSDISPLAYIO_GTYPE:
+ *(u_int *)data = WSDISPLAY_TYPE_UNKNOWN;
+ break;
+
+ case WSDISPLAYIO_SMODE:
+ if (*(u_int *)data == WSDISPLAYIO_MODE_EMUL)
+ fbwscons_setcolormap(&sc->sc_sunfb, ifb_setcolor);
+ break;
+ case WSDISPLAYIO_GINFO:
+ wdf = (void *)data;
+ wdf->height = sc->sc_sunfb.sf_height;
+ wdf->width = sc->sc_sunfb.sf_width;
+ wdf->depth = sc->sc_sunfb.sf_depth;
+ wdf->cmsize = 256;
+ break;
+ case WSDISPLAYIO_LINEBYTES:
+ *(u_int *)data = sc->sc_sunfb.sf_linebytes;
+ break;
+
+ case WSDISPLAYIO_GETCMAP:
+ return ifb_getcmap(sc, (struct wsdisplay_cmap *)data);
+ case WSDISPLAYIO_PUTCMAP:
+ return ifb_putcmap(sc, (struct wsdisplay_cmap *)data);
+
+ case WSDISPLAYIO_GPCIID:
+ sel = (struct pcisel *)data;
+ sel->pc_bus = PCITAG_BUS(sc->sc_pcitag);
+ sel->pc_dev = PCITAG_DEV(sc->sc_pcitag);
+ sel->pc_func = PCITAG_FUN(sc->sc_pcitag);
+ break;
+
+ case WSDISPLAYIO_SVIDEO:
+ case WSDISPLAYIO_GVIDEO:
+ break;
+
+ case WSDISPLAYIO_GCURPOS:
+ case WSDISPLAYIO_SCURPOS:
+ case WSDISPLAYIO_GCURMAX:
+ case WSDISPLAYIO_GCURSOR:
+ case WSDISPLAYIO_SCURSOR:
+ default:
+ return -1; /* not supported yet */
+ }
+
+ return 0;
+}
+
+int
+ifb_getcmap(struct ifb_softc *sc, struct wsdisplay_cmap *cm)
+{
+ u_int index = cm->index;
+ u_int count = cm->count;
+ int error;
+
+ if (index >= 256 || count > 256 - index)
+ return EINVAL;
+
+ error = copyout(&sc->sc_cmap_red[index], cm->red, count);
+ if (error)
+ return error;
+ error = copyout(&sc->sc_cmap_green[index], cm->green, count);
+ if (error)
+ return error;
+ error = copyout(&sc->sc_cmap_blue[index], cm->blue, count);
+ if (error)
+ return error;
+ return 0;
+}
+
+int
+ifb_putcmap(struct ifb_softc *sc, struct wsdisplay_cmap *cm)
+{
+ u_int index = cm->index;
+ u_int count = cm->count;
+ u_int i;
+ int error;
+ u_char *r, *g, *b;
+
+ if (index >= 256 || count > 256 - index)
+ return EINVAL;
+
+ if ((error = copyin(cm->red, &sc->sc_cmap_red[index], count)) != 0)
+ return error;
+ if ((error = copyin(cm->green, &sc->sc_cmap_green[index], count)) != 0)
+ return error;
+ if ((error = copyin(cm->blue, &sc->sc_cmap_blue[index], count)) != 0)
+ return error;
+
+ r = &sc->sc_cmap_red[index];
+ g = &sc->sc_cmap_green[index];
+ b = &sc->sc_cmap_blue[index];
+
+ for (i = 0; i < count; i++) {
+ bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
+ IFB_REG_OFFSET + IFB_REG_CMAP_INDEX, index);
+ bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
+ IFB_REG_OFFSET + IFB_REG_CMAP_DATA,
+ (((u_int)*b) << 22) | (((u_int)*g) << 12) | (((u_int)*r) << 2));
+ r++, g++, b++, index++;
+ }
+ return 0;
+}
+
+void
+ifb_setcolor(void *v, u_int index, u_int8_t r, u_int8_t g, u_int8_t b)
+{
+ struct ifb_softc *sc = v;
+
+ sc->sc_cmap_red[index] = r;
+ sc->sc_cmap_green[index] = g;
+ sc->sc_cmap_blue[index] = b;
+
+ bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
+ IFB_REG_OFFSET + IFB_REG_CMAP_INDEX, index);
+ bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
+ IFB_REG_OFFSET + IFB_REG_CMAP_DATA,
+ (((u_int)b) << 22) | (((u_int)g) << 12) | (((u_int)r) << 2));
+}
+
+int
+ifb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
+ int *curxp, int *curyp, long *attrp)
+{
+ struct ifb_softc *sc = v;
+
+ if (sc->sc_nscreens > 0)
+ return ENOMEM;
+
+ *cookiep = &sc->sc_sunfb.sf_ro;
+ *curyp = 0;
+ *curxp = 0;
+ sc->sc_sunfb.sf_ro.ri_ops.alloc_attr(&sc->sc_sunfb.sf_ro,
+ WSCOL_BLACK, WSCOL_WHITE, WSATTR_WSCOLORS, attrp);
+ sc->sc_nscreens++;
+ return 0;
+}
+
+void
+ifb_free_screen(void *v, void *cookie)
+{
+ struct ifb_softc *sc = v;
+
+ sc->sc_nscreens--;
+}
+
+int
+ifb_show_screen(void *v, void *cookie, int waitok,
+ void (*cb)(void *, int, int), void *cbarg)
+{
+ return 0;
+}
+
+paddr_t
+ifb_mmap(void *v, off_t off, int prot)
+{
+ return -1;
+}
+
+void
+ifb_burner(void *v, u_int on, u_int flags)
+{
+ struct ifb_softc *sc = (struct ifb_softc *)v;
+ int s;
+ uint32_t dpms;
+
+ s = splhigh();
+ if (on)
+ dpms = IFB_REG_DPMS_ON;
+ else {
+#ifdef notyet
+ if (flags & WSDISPLAY_BURN_VBLANK)
+ dpms = IFB_REG_DPMS_SUSPEND;
+ else
+#endif
+ dpms = IFB_REG_DPMS_STANDBY;
+ }
+ bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
+ IFB_REG_OFFSET + IFB_REG_DPMS_STATE, dpms);
+ splx(s);
+}
+
+int
+ifb_is_console(int node)
+{
+ extern int fbnode;
+
+ return fbnode == node;
+}
+
+int
+ifb_mapregs(struct ifb_softc *sc, struct pci_attach_args *pa)
+{
+ u_int32_t cf;
+ int rc;
+
+ cf = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_MAPREG_START);
+ if (PCI_MAPREG_TYPE(cf) == PCI_MAPREG_TYPE_IO)
+ rc = EINVAL;
+ else {
+ rc = pci_mapreg_map(pa, PCI_MAPREG_START, cf,
+ BUS_SPACE_MAP_LINEAR, NULL, &sc->sc_mem_h,
+ &sc->sc_membase, &sc->sc_memlen, 0);
+ }
+ if (rc != 0) {
+ printf("%s: can't map video memory\n",
+ sc->sc_sunfb.sf_dev.dv_xname);
+ return rc;
+ }
+
+ cf = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_MAPREG_START + 4);
+ if (PCI_MAPREG_TYPE(cf) == PCI_MAPREG_TYPE_IO)
+ rc = EINVAL;
+ else {
+ rc = pci_mapreg_map(pa, PCI_MAPREG_START + 4, cf,
+ 0, NULL, &sc->sc_reg_h, NULL, NULL, 0x9000);
+ }
+ if (rc != 0) {
+ printf("%s: can't map register space\n",
+ sc->sc_sunfb.sf_dev.dv_xname);
+ return rc;
+ }
+
+ return 0;
+}
+
+void
+ifb_putchar(void *cookie, int row, int col, u_int uc, long attr)
+{
+ struct rasops_info *ri = cookie;
+ struct ifb_softc *sc = ri->ri_hw;
+
+ ri->ri_bits = (void *)sc->sc_fb8bank0_vaddr;
+ sc->sc_old_ops.putchar(cookie, row, col, uc, attr);
+ ri->ri_bits = (void *)sc->sc_fb8bank1_vaddr;
+ sc->sc_old_ops.putchar(cookie, row, col, uc, attr);
+}
+
+void
+ifb_copycols(void *cookie, int row, int src, int dst, int num)
+{
+ struct rasops_info *ri = cookie;
+ struct ifb_softc *sc = ri->ri_hw;
+
+ ri->ri_bits = (void *)sc->sc_fb8bank0_vaddr;
+ sc->sc_old_ops.copycols(cookie, row, src, dst, num);
+ ri->ri_bits = (void *)sc->sc_fb8bank1_vaddr;
+ sc->sc_old_ops.copycols(cookie, row, src, dst, num);
+}
+
+void
+ifb_erasecols(void *cookie, int row, int col, int num, long attr)
+{
+ struct rasops_info *ri = cookie;
+ struct ifb_softc *sc = ri->ri_hw;
+
+ ri->ri_bits = (void *)sc->sc_fb8bank0_vaddr;
+ sc->sc_old_ops.erasecols(cookie, row, col, num, attr);
+ ri->ri_bits = (void *)sc->sc_fb8bank1_vaddr;
+ sc->sc_old_ops.erasecols(cookie, row, col, num, attr);
+}
+
+void
+ifb_copyrows(void *cookie, int src, int dst, int num)
+{
+ struct rasops_info *ri = cookie;
+ struct ifb_softc *sc = ri->ri_hw;
+
+ ri->ri_bits = (void *)sc->sc_fb8bank0_vaddr;
+ sc->sc_old_ops.copyrows(cookie, src, dst, num);
+ ri->ri_bits = (void *)sc->sc_fb8bank1_vaddr;
+ sc->sc_old_ops.copyrows(cookie, src, dst, num);
+}
+
+void
+ifb_eraserows(void *cookie, int row, int num, long attr)
+{
+ struct rasops_info *ri = cookie;
+ struct ifb_softc *sc = ri->ri_hw;
+
+ ri->ri_bits = (void *)sc->sc_fb8bank0_vaddr;
+ sc->sc_old_ops.eraserows(cookie, row, num, attr);
+ ri->ri_bits = (void *)sc->sc_fb8bank1_vaddr;
+ sc->sc_old_ops.eraserows(cookie, row, num, attr);
+}
+
+void
+ifb_do_cursor(struct rasops_info *ri)
+{
+ struct ifb_softc *sc = ri->ri_hw;
+
+ ri->ri_bits = (void *)sc->sc_fb8bank0_vaddr;
+ sc->sc_old_cursor(ri);
+ ri->ri_bits = (void *)sc->sc_fb8bank1_vaddr;
+ sc->sc_old_cursor(ri);
+}