summaryrefslogtreecommitdiffstats
path: root/sys/dev/fb/creator.c
diff options
context:
space:
mode:
authormarius <marius@FreeBSD.org>2007-01-16 21:08:22 +0000
committermarius <marius@FreeBSD.org>2007-01-16 21:08:22 +0000
commit7f03dfc1a6b87b8864d6ef57dfdadb6d50bd5ed7 (patch)
treee68a50d95bd365525cc920ed6279efe547f46a99 /sys/dev/fb/creator.c
parent026ed31f96609de8425e069de20ddd11c3222561 (diff)
downloadFreeBSD-src-7f03dfc1a6b87b8864d6ef57dfdadb6d50bd5ed7.zip
FreeBSD-src-7f03dfc1a6b87b8864d6ef57dfdadb6d50bd5ed7.tar.gz
- Merge sys/sparc64/creator/creator_upa.c into sys/dev/fb/creator.c.
The separate bus front-end was inherited from the OpenBSD creator(4), which at that time had a mainbus(4) (for USI/II machines, which use an UPA interconnection bus as the nexus) and an upa(4) (for USIII machines, which use a subordinate/slave UPA bus hanging off from the Fireplane/Safari interconnection bus) front-end. With FreeBSD and newbus there is/will be no need to have two separate bus front-ends for these busses, so we can easily coallapse the shared front-end and the back-end into a single source file (note that the FreeBSD creator_upa.c was misnomer anyway; based on what it actually attached to that should have been creator_nexus.c), actually OpenBSD meanwhile also has moved to a shared front-end and a single source file. Due to the low-level console support creator.c also wasn't free from bus related things before. While at it, also split sys/sparc64/creator/creator.h into a sys/dev/fb/creatorreg.h that only contains register macros and move the structures to the top of sys/dev/fb/creator.c as suggested by style(9) so creator(4) is no longer scattered over two directories. - Use OF_decode_addr()/sparc64_fake_bustag() to obtain the bus tags and handles for the low-level console support instead of hardcoding support for AFB/FFB hanging off from nexus(4) only. This is part 2/4 of allowing creator(4) to work in USIII machines (which have a UPA bus hanging off from the Fireplane/Safari bus reflected by the nexus), which already makes it work as the low-level console there. - Allocate resources in the bus attach routine regardless of whether creator(4) is used as for the low-level console and thus the required bus tags and handles have been already obtained or not so the resources are marked as taken in the respective RMAN. - For both obtaining the bus tags and handles for the low-level console support as well as allocating the corresponding resources in the regular bus attach routine don't bother to get all for the maximum of 24 register banks but only (for) the two tag/handle pairs required for providing the video interface for syscons(4) support. If we can't allocate the rest of them just limit the memory range accessible via creator_fb_mmap() accordingly. - Sanity check the memory range spanned by the first and last resources and the resources in between as far as possible, as the XFree86/Xorg sunffb(4) expects to be able to access the whole region, even though the backing resources are actually non-continuous. Limit and check the memory range accessible via creator_fb_mmap() accordingly. - Reduce the size of buffers for OFW properties to what they actually need to hold. - Rename some tables to creator_<foo> for consistency. - Also for the sizes in the creator_fb_mmap() mapping table entries use macros for consistency, add macros for the remaining register banks for completeness.
Diffstat (limited to 'sys/dev/fb/creator.c')
-rw-r--r--sys/dev/fb/creator.c446
1 files changed, 405 insertions, 41 deletions
diff --git a/sys/dev/fb/creator.c b/sys/dev/fb/creator.c
index bfcf2bc..f9f293c 100644
--- a/sys/dev/fb/creator.c
+++ b/sys/dev/fb/creator.c
@@ -30,22 +30,170 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
+#include <sys/conf.h>
#include <sys/consio.h>
#include <sys/fbio.h>
#include <sys/kernel.h>
#include <sys/module.h>
+#include <sys/resource.h>
+
+#include <dev/ofw/openfirm.h>
#include <machine/bus.h>
+#include <machine/bus_private.h>
+#include <machine/nexusvar.h>
+#include <machine/ofw_machdep.h>
#include <machine/ofw_upa.h>
+#include <machine/resource.h>
#include <machine/sc_machdep.h>
+#include <sys/rman.h>
+
#include <dev/fb/fbreg.h>
+#include <dev/fb/creatorreg.h>
#include <dev/fb/gallant12x22.h>
#include <dev/syscons/syscons.h>
-#include <dev/ofw/openfirm.h>
+#define CREATOR_DRIVER_NAME "creator"
+
+struct creator_softc {
+ video_adapter_t sc_va; /* XXX must be first */
+
+ phandle_t sc_node;
+
+ struct cdev *sc_si;
+
+ int sc_rid[FFB_NREG];
+ struct resource *sc_reg[FFB_NREG];
+ bus_space_tag_t sc_bt[FFB_NREG];
+ bus_space_handle_t sc_bh[FFB_NREG];
+
+ int sc_height;
+ int sc_width;
+
+ int sc_xmargin;
+ int sc_ymargin;
+
+ u_char *sc_font;
+
+ int sc_bg_cache;
+ int sc_fg_cache;
+ int sc_fifo_cache;
+ int sc_fontinc_cache;
+ int sc_fontw_cache;
+ int sc_pmask_cache;
+
+ int sc_flags;
+#define CREATOR_AFB (1 << 0)
+#define CREATOR_CONSOLE (1 << 1)
+#define CREATOR_CUREN (1 << 2)
+#define CREATOR_CURINV (1 << 3)
+#define CREATOR_PAC1 (1 << 4)
+};
+
+#define FFB_READ(sc, reg, off) \
+ bus_space_read_4((sc)->sc_bt[(reg)], (sc)->sc_bh[(reg)], (off))
+#define FFB_WRITE(sc, reg, off, val) \
+ bus_space_write_4((sc)->sc_bt[(reg)], (sc)->sc_bh[(reg)], (off), (val))
+
+#define C(r, g, b) ((b << 16) | (g << 8) | (r))
+static const uint32_t creator_cmap[] = {
+ C(0x00, 0x00, 0x00), /* black */
+ C(0x00, 0x00, 0xff), /* blue */
+ C(0x00, 0xff, 0x00), /* green */
+ C(0x00, 0xc0, 0xc0), /* cyan */
+ C(0xff, 0x00, 0x00), /* red */
+ C(0xc0, 0x00, 0xc0), /* magenta */
+ C(0xc0, 0xc0, 0x00), /* brown */
+ C(0xc0, 0xc0, 0xc0), /* light grey */
+ C(0x80, 0x80, 0x80), /* dark grey */
+ C(0x80, 0x80, 0xff), /* light blue */
+ C(0x80, 0xff, 0x80), /* light green */
+ C(0x80, 0xff, 0xff), /* light cyan */
+ C(0xff, 0x80, 0x80), /* light red */
+ C(0xff, 0x80, 0xff), /* light magenta */
+ C(0xff, 0xff, 0x80), /* yellow */
+ C(0xff, 0xff, 0xff), /* white */
+};
+#undef C
+
+static const struct {
+ vm_offset_t virt;
+ vm_paddr_t phys;
+ vm_size_t size;
+} creator_fb_map[] = {
+ { FFB_VIRT_SFB8R, FFB_PHYS_SFB8R, FFB_SIZE_SFB8R },
+ { FFB_VIRT_SFB8G, FFB_PHYS_SFB8G, FFB_SIZE_SFB8G },
+ { FFB_VIRT_SFB8B, FFB_PHYS_SFB8B, FFB_SIZE_SFB8B },
+ { FFB_VIRT_SFB8X, FFB_PHYS_SFB8X, FFB_SIZE_SFB8X },
+ { FFB_VIRT_SFB32, FFB_PHYS_SFB32, FFB_SIZE_SFB32 },
+ { FFB_VIRT_SFB64, FFB_PHYS_SFB64, FFB_SIZE_SFB64 },
+ { FFB_VIRT_FBC, FFB_PHYS_FBC, FFB_SIZE_FBC },
+ { FFB_VIRT_FBC_BM, FFB_PHYS_FBC_BM, FFB_SIZE_FBC_BM },
+ { FFB_VIRT_DFB8R, FFB_PHYS_DFB8R, FFB_SIZE_DFB8R },
+ { FFB_VIRT_DFB8G, FFB_PHYS_DFB8G, FFB_SIZE_DFB8G },
+ { FFB_VIRT_DFB8B, FFB_PHYS_DFB8B, FFB_SIZE_DFB8B },
+ { FFB_VIRT_DFB8X, FFB_PHYS_DFB8X, FFB_SIZE_DFB8X },
+ { FFB_VIRT_DFB24, FFB_PHYS_DFB24, FFB_SIZE_DFB24 },
+ { FFB_VIRT_DFB32, FFB_PHYS_DFB32, FFB_SIZE_DFB32 },
+ { FFB_VIRT_DFB422A, FFB_PHYS_DFB422A, FFB_SIZE_DFB422A },
+ { FFB_VIRT_DFB422AD, FFB_PHYS_DFB422AD, FFB_SIZE_DFB422AD },
+ { FFB_VIRT_DFB24B, FFB_PHYS_DFB24B, FFB_SIZE_DFB24B },
+ { FFB_VIRT_DFB422B, FFB_PHYS_DFB422B, FFB_SIZE_DFB422B },
+ { FFB_VIRT_DFB422BD, FFB_PHYS_DFB422BD, FFB_SIZE_DFB422BD },
+ { FFB_VIRT_SFB16Z, FFB_PHYS_SFB16Z, FFB_SIZE_SFB16Z },
+ { FFB_VIRT_SFB8Z, FFB_PHYS_SFB8Z, FFB_SIZE_SFB8Z },
+ { FFB_VIRT_SFB422, FFB_PHYS_SFB422, FFB_SIZE_SFB422 },
+ { FFB_VIRT_SFB422D, FFB_PHYS_SFB422D, FFB_SIZE_SFB422D },
+ { FFB_VIRT_FBC_KREG, FFB_PHYS_FBC_KREG, FFB_SIZE_FBC_KREG },
+ { FFB_VIRT_DAC, FFB_PHYS_DAC, FFB_SIZE_DAC },
+ { FFB_VIRT_PROM, FFB_PHYS_PROM, FFB_SIZE_PROM },
+ { FFB_VIRT_EXP, FFB_PHYS_EXP, FFB_SIZE_EXP },
+};
+
+#define CREATOR_FB_MAP_SIZE \
+ (sizeof(creator_fb_map) / sizeof(creator_fb_map[0]))
+
+static struct creator_softc creator_softc;
+static struct bus_space_tag creator_bst_store[FFB_FBC];
+
+static device_probe_t creator_bus_probe;
+static device_attach_t creator_bus_attach;
-#include <sparc64/creator/creator.h>
+static device_method_t creator_bus_methods[] = {
+ DEVMETHOD(device_probe, creator_bus_probe),
+ DEVMETHOD(device_attach, creator_bus_attach),
+
+ { 0, 0 }
+};
+
+static devclass_t creator_devclass;
+
+DEFINE_CLASS_0(creator, creator_bus_driver, creator_bus_methods,
+ sizeof(struct creator_softc));
+DRIVER_MODULE(creator, nexus, creator_bus_driver, creator_devclass, 0, 0);
+#if 0
+DRIVER_MODULE(creator, upa, creator_bus_driver, creator_devclass, 0, 0);
+#endif
+
+static d_open_t creator_fb_open;
+static d_close_t creator_fb_close;
+static d_ioctl_t creator_fb_ioctl;
+static d_mmap_t creator_fb_mmap;
+
+static struct cdevsw creator_fb_devsw = {
+ .d_version = D_VERSION,
+ .d_flags = D_NEEDGIANT,
+ .d_open = creator_fb_open,
+ .d_close = creator_fb_close,
+ .d_ioctl = creator_fb_ioctl,
+ .d_mmap = creator_fb_mmap,
+ .d_name = "fb",
+};
+
+static void creator_cursor_enable(struct creator_softc *sc, int onoff);
+static void creator_cursor_install(struct creator_softc *sc);
+static void creator_shutdown(void *xsc);
static int creator_configure(int flags);
@@ -81,9 +229,6 @@ static vi_putc_t creator_putc;
static vi_puts_t creator_puts;
static vi_putm_t creator_putm;
-static void creator_cursor_enable(struct creator_softc *sc, int onoff);
-static void creator_cursor_install(struct creator_softc *sc);
-
static video_switch_t creatorvidsw = {
.probe = creator_probe,
.init = creator_init,
@@ -127,28 +272,6 @@ RENDERER(creator, 0, txtrndrsw, gfb_set);
RENDERER_MODULE(creator, gfb_set);
-extern struct bus_space_tag nexus_bustag;
-
-#define C(r, g, b) ((b << 16) | (g << 8) | (r))
-static const int cmap[] = {
- C(0x00, 0x00, 0x00), /* black */
- C(0x00, 0x00, 0xff), /* blue */
- C(0x00, 0xff, 0x00), /* green */
- C(0x00, 0xc0, 0xc0), /* cyan */
- C(0xff, 0x00, 0x00), /* red */
- C(0xc0, 0x00, 0xc0), /* magenta */
- C(0xc0, 0xc0, 0x00), /* brown */
- C(0xc0, 0xc0, 0xc0), /* light grey */
- C(0x80, 0x80, 0x80), /* dark grey */
- C(0x80, 0x80, 0xff), /* light blue */
- C(0x80, 0xff, 0x80), /* light green */
- C(0x80, 0xff, 0xff), /* light cyan */
- C(0xff, 0x80, 0x80), /* light red */
- C(0xff, 0x80, 0xff), /* light magenta */
- C(0xff, 0xff, 0x80), /* yellow */
- C(0xff, 0xff, 0xff), /* white */
-};
-
static const u_char creator_mouse_pointer[64][8] __aligned(8) = {
{ 0x00, 0x00, }, /* ............ */
{ 0x80, 0x00, }, /* *........... */
@@ -174,8 +297,6 @@ static const u_char creator_mouse_pointer[64][8] __aligned(8) = {
{ 0x00, 0x00, }, /* ............ */
};
-static struct creator_softc creator_softc;
-
static inline void creator_ras_fifo_wait(struct creator_softc *sc, int n);
static inline void creator_ras_setfontinc(struct creator_softc *sc, int fontinc);
static inline void creator_ras_setfontw(struct creator_softc *sc, int fontw);
@@ -272,16 +393,20 @@ creator_ras_setpmask(struct creator_softc *sc, int pmask)
creator_ras_wait(sc);
}
+/*
+ * video driver interface
+ */
static int
creator_configure(int flags)
{
- struct upa_regs reg[FFB_NREG];
struct creator_softc *sc;
phandle_t chosen;
phandle_t output;
ihandle_t stdout;
- char buf[32];
+ bus_addr_t addr;
+ char buf[sizeof("SUNW,ffb")];
int i;
+ int space;
/*
* For the high-level console probing return the number of
@@ -315,11 +440,11 @@ creator_configure(int flags)
} else
return (0);
- if (OF_getprop(output, "reg", reg, sizeof(reg)) == -1)
- return (0);
- for (i = 0; i < FFB_NREG; i++) {
- sc->sc_bt[i] = &nexus_bustag;
- sc->sc_bh[i] = UPA_REG_PHYS(reg + i);
+ for (i = FFB_DAC; i <= FFB_FBC; i++) {
+ if (OF_decode_addr(output, i, &space, &addr) != 0)
+ return (0);
+ sc->sc_bt[i] = &creator_bst_store[i - FFB_DAC];
+ sc->sc_bh[i] = sparc64_fake_bustag(space, addr, sc->sc_bt[i]);
}
if (creator_init(0, &sc->sc_va, 0) < 0)
@@ -343,7 +468,7 @@ creator_init(int unit, video_adapter_t *adp, int flags)
struct creator_softc *sc;
phandle_t options;
video_info_t *vi;
- char buf[32];
+ char buf[sizeof("screen-#columns")];
sc = (struct creator_softc *)adp;
vi = &adp->va_info;
@@ -628,7 +753,7 @@ creator_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy)
creator_ras_fifo_wait(sc, 2);
FFB_WRITE(sc, FFB_FBC, FFB_FBC_ROP, FBC_ROP_NEW);
FFB_WRITE(sc, FFB_FBC, FFB_FBC_DRAWOP, FBC_DRAWOP_RECTANGLE);
- creator_ras_setfg(sc, cmap[val & 0xf]);
+ creator_ras_setfg(sc, creator_cmap[val & 0xf]);
/*
* Note that at least the Elite3D cards are sensitive to the order
* of operations here.
@@ -702,8 +827,8 @@ creator_putc(video_adapter_t *adp, vm_offset_t off, u_int8_t c, u_int8_t a)
row = (off / adp->va_info.vi_width) * adp->va_info.vi_cheight;
col = (off % adp->va_info.vi_width) * adp->va_info.vi_cwidth;
p = (uint16_t *)sc->sc_font + (c * adp->va_info.vi_cheight);
- creator_ras_setfg(sc, cmap[a & 0xf]);
- creator_ras_setbg(sc, cmap[(a >> 4) & 0xf]);
+ creator_ras_setfg(sc, creator_cmap[a & 0xf]);
+ creator_ras_setbg(sc, creator_cmap[(a >> 4) & 0xf]);
creator_ras_fifo_wait(sc, 1 + adp->va_info.vi_cheight);
FFB_WRITE(sc, FFB_FBC, FFB_FBC_FONTXY,
((row + sc->sc_ymargin) << 16) | (col + sc->sc_xmargin));
@@ -745,6 +870,228 @@ creator_putm(video_adapter_t *adp, int x, int y, u_int8_t *pixel_image,
return (0);
}
+/*
+ * bus interface
+ */
+static int
+creator_bus_probe(device_t dev)
+{
+ const char *name;
+ phandle_t node;
+ int type;
+
+ name = nexus_get_name(dev);
+ node = nexus_get_node(dev);
+ if (strcmp(name, "SUNW,ffb") == 0) {
+ if (OF_getprop(node, "board_type", &type, sizeof(type)) == -1)
+ return (ENXIO);
+ switch (type & 7) {
+ case 0x0:
+ device_set_desc(dev, "Creator");
+ break;
+ case 0x3:
+ device_set_desc(dev, "Creator3D");
+ break;
+ default:
+ return (ENXIO);
+ }
+ } else if (strcmp(name, "SUNW,afb") == 0)
+ device_set_desc(dev, "Elite3D");
+ else
+ return (ENXIO);
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+creator_bus_attach(device_t dev)
+{
+ struct creator_softc *sc;
+ struct upa_regs *reg;
+ video_adapter_t *adp;
+ video_switch_t *sw;
+ phandle_t node;
+ bus_addr_t phys;
+ bus_size_t size;
+ int error;
+ int nreg;
+ int unit;
+ int i;
+
+ node = nexus_get_node(dev);
+ if ((sc = (struct creator_softc *)vid_get_adapter(vid_find_adapter(
+ CREATOR_DRIVER_NAME, 0))) != NULL && sc->sc_node == node) {
+ device_printf(dev, "console\n");
+ device_set_softc(dev, sc);
+ } else {
+ sc = device_get_softc(dev);
+ sc->sc_node = node;
+ }
+ adp = &sc->sc_va;
+
+ /*
+ * Allocate resources regardless of whether we are the console
+ * and already obtained the bus tags and handles for the FFB_DAC
+ * and FFB_FBC register banks in creator_configure() or not so
+ * the resources are marked as taken in the respective RMAN.
+ * The supported cards use either 15 (Creator, Elite3D?) or 24
+ * (Creator3D?) register banks. We make sure that we can also
+ * allocate the resources for at least the FFB_DAC and FFB_FBC
+ * banks here. We try but don't actually care whether we can
+ * allocate more than these two resources and just limit the
+ * range accessible via creator_fb_mmap() accordingly.
+ */
+ reg = nexus_get_reg(dev);
+ nreg = nexus_get_nreg(dev);
+ if (nreg <= FFB_FBC) {
+ device_printf(dev, "not enough resources\n");
+ error = ENXIO;
+ goto fail;
+ }
+ for (i = 0; i < nreg; i++) {
+ phys = UPA_REG_PHYS(reg + i);
+ size = UPA_REG_SIZE(reg + i);
+ sc->sc_rid[i] = i;
+ sc->sc_reg[i] = bus_alloc_resource(dev, SYS_RES_MEMORY,
+ &sc->sc_rid[i], phys, phys + size - 1, size,
+ RF_ACTIVE);
+ if (sc->sc_reg[i] == NULL) {
+ if (i <= FFB_FBC) {
+ device_printf(dev,
+ "cannot allocate resources\n");
+ error = ENXIO;
+ goto fail;
+ }
+ break;
+ }
+ sc->sc_bt[i] = rman_get_bustag(sc->sc_reg[i]);
+ sc->sc_bh[i] = rman_get_bushandle(sc->sc_reg[i]);
+ }
+ /*
+ * The XFree86/Xorg sunffb(4) expects to be able to access the
+ * memory spanned by the first and the last resource as one chunk
+ * via creator_fb_mmap(), using offsets from the first resource,
+ * even though the backing resources are actually non-continuous.
+ * So make sure that the memory we provide is at least backed by
+ * increasing resources.
+ */
+ adp->va_mem_base = rman_get_start(sc->sc_reg[0]);
+ for (i = 1; i < FFB_NREG && sc->sc_reg[i] != NULL &&
+ rman_get_start(sc->sc_reg[i]) > rman_get_start(sc->sc_reg[i - 1]);
+ i++)
+ ;
+ adp->va_mem_size = rman_get_end(sc->sc_reg[i - 1]) -
+ adp->va_mem_base + 1;
+
+ if (!(sc->sc_flags & CREATOR_CONSOLE)) {
+ if ((sw = vid_get_switch(CREATOR_DRIVER_NAME)) == NULL) {
+ device_printf(dev, "cannot get video switch\n");
+ error = ENODEV;
+ goto fail;
+ }
+ /*
+ * During device configuration we don't necessarily probe
+ * the adapter which is the console first so we can't use
+ * the device unit number for the video adapter unit. The
+ * worst case would be that we use the video adapter unit
+ * 0 twice. As it doesn't really matter which unit number
+ * the corresponding video adapter has just use the next
+ * unused one.
+ */
+ for (i = 0; i < devclass_get_maxunit(creator_devclass); i++)
+ if (vid_find_adapter(CREATOR_DRIVER_NAME, i) < 0)
+ break;
+ if (strcmp(nexus_get_name(dev), "SUNW,afb") == 0)
+ sc->sc_flags |= CREATOR_AFB;
+ if ((error = sw->init(i, adp, 0)) != 0) {
+ device_printf(dev, "cannot initialize adapter\n");
+ goto fail;
+ }
+ }
+
+ if (bootverbose) {
+ if (sc->sc_flags & CREATOR_PAC1)
+ device_printf(dev,
+ "BT9068/PAC1 RAMDAC (%s cursor control)\n",
+ sc->sc_flags & CREATOR_CURINV ? "inverted" :
+ "normal");
+ else
+ device_printf(dev, "BT498/PAC2 RAMDAC\n");
+ }
+ device_printf(dev, "resolution %dx%d\n", sc->sc_width, sc->sc_height);
+
+ unit = device_get_unit(dev);
+ sc->sc_si = make_dev(&creator_fb_devsw, unit, UID_ROOT, GID_WHEEL,
+ 0600, "fb%d", unit);
+ sc->sc_si->si_drv1 = sc;
+
+ EVENTHANDLER_REGISTER(shutdown_final, creator_shutdown, sc,
+ SHUTDOWN_PRI_DEFAULT);
+
+ return (0);
+
+ fail:
+ for (i = 0; i < FFB_NREG && sc->sc_reg[i] != NULL; i++)
+ bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rid[i],
+ sc->sc_reg[i]);
+ return (error);
+}
+
+/*
+ * /dev/fb interface
+ */
+static int
+creator_fb_open(struct cdev *dev, int flags, int mode, struct thread *td)
+{
+
+ return (0);
+}
+
+static int
+creator_fb_close(struct cdev *dev, int flags, int mode, struct thread *td)
+{
+
+ return (0);
+}
+
+static int
+creator_fb_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags,
+ struct thread *td)
+{
+ struct creator_softc *sc;
+
+ sc = dev->si_drv1;
+ return (creator_ioctl(&sc->sc_va, cmd, data));
+}
+
+static int
+creator_fb_mmap(struct cdev *dev, vm_offset_t offset, vm_paddr_t *paddr,
+ int prot)
+{
+ struct creator_softc *sc;
+ int i;
+
+ /*
+ * NB: This is a special implementation based on the /dev/fb
+ * requirements of the XFree86/Xorg sunffb(4).
+ */
+ sc = dev->si_drv1;
+ for (i = 0; i < CREATOR_FB_MAP_SIZE; i++) {
+ if (offset >= creator_fb_map[i].virt &&
+ offset < creator_fb_map[i].virt + creator_fb_map[i].size) {
+ offset += creator_fb_map[i].phys -
+ creator_fb_map[i].virt;
+ if (offset >= sc->sc_va.va_mem_size)
+ return (EINVAL);
+ *paddr = sc->sc_bh[0] + offset;
+ return (0);
+ }
+ }
+ return (EINVAL);
+}
+
+/*
+ * internal functions
+ */
static void
creator_cursor_enable(struct creator_softc *sc, int onoff)
{
@@ -773,8 +1120,25 @@ creator_cursor_install(struct creator_softc *sc)
for (j = 0; j < 64; j++) {
FFB_WRITE(sc, FFB_DAC, FFB_DAC_VALUE2,
*(const uint32_t *)(&creator_mouse_pointer[j][0]));
- FFB_WRITE(sc, FFB_DAC, FFB_DAC_VALUE2,
+ FFB_WRITE(sc, FFB_DAC, FFB_DAC_VALUE2,
*(const uint32_t *)(&creator_mouse_pointer[j][4]));
}
}
}
+
+static void
+creator_shutdown(void *xsc)
+{
+ struct creator_softc *sc = xsc;
+
+ creator_cursor_enable(sc, 0);
+ /*
+ * In case this is the console set the cursor of the stdout
+ * instance to the start of the last line so OFW output ends
+ * up beneath what FreeBSD left on the screen.
+ */
+ if (sc->sc_flags & CREATOR_CONSOLE) {
+ OF_interpret("stdout @ is my-self 0 to column#", 0);
+ OF_interpret("stdout @ is my-self #lines 1 - to line#", 0);
+ }
+}
OpenPOWER on IntegriCloud