Пример #1
0
paddr_t
cgthree_mmap(void *v, off_t offset, int prot)
{
	struct cgthree_softc *sc = v;

	if (offset & PGOFSET || offset < 0)
		return (-1);

	switch (sc->sc_mode) {
	case WSDISPLAYIO_MODE_MAPPED:
		if (offset >= NOOVERLAY)
			offset -= NOOVERLAY;
		else if (offset >= START)
			offset -= START;
		else
			offset = 0;
		if (offset >= sc->sc_sunfb.sf_fbsize)
			return (-1);
		return (bus_space_mmap(sc->sc_bustag, sc->sc_paddr,
		    CGTHREE_VID_OFFSET + offset, prot, BUS_SPACE_MAP_LINEAR));
	case WSDISPLAYIO_MODE_DUMBFB:
		if (offset < sc->sc_sunfb.sf_fbsize)
			return (bus_space_mmap(sc->sc_bustag, sc->sc_paddr,
			    CGTHREE_VID_OFFSET + offset, prot,
			    BUS_SPACE_MAP_LINEAR));
		break;
	}
	return (-1);
}
Пример #2
0
static paddr_t
pcimmap(dev_t dev, off_t offset, int prot)
{
	struct pci_softc *sc = device_lookup_private(&pci_cd, minor(dev));
	struct pci_child *c;
	struct pci_range *r;
	int flags = 0;
	int device, range;

	if (kauth_authorize_machdep(kauth_cred_get(), KAUTH_MACHDEP_UNMANAGEDMEM,
	    NULL, NULL, NULL, NULL) != 0) {
		return -1;
	}
	/*
	 * Since we allow mapping of the entire bus, we
	 * take the offset to be the address on the bus,
	 * and pass 0 as the offset into that range.
	 *
	 * XXX Need a way to deal with linear/etc.
	 *
	 * XXX we rely on MD mmap() methods to enforce limits since these
	 * are hidden in *_tag_t structs if they exist at all 
	 */

#ifdef PCI_MAGIC_IO_RANGE
	/* 
	 * first, check if someone's trying to map the IO range
	 * XXX this assumes 64kB IO space even though some machines can have
	 * significantly more than that - macppc's bandit host bridge allows
	 * 8MB IO space and sparc64 may have the entire 4GB available. The
	 * firmware on both tries to use the lower 64kB first though and
	 * exausting it is pretty difficult so we should be safe
	 */
	if ((offset >= PCI_MAGIC_IO_RANGE) &&
	    (offset < (PCI_MAGIC_IO_RANGE + 0x10000))) {
		return bus_space_mmap(sc->sc_iot, offset - PCI_MAGIC_IO_RANGE,
		    0, prot, 0);
	}
#endif /* PCI_MAGIC_IO_RANGE */

	for (device = 0; device < __arraycount(sc->sc_devices); device++) {
		c = &sc->sc_devices[device];
		if (c->c_dev == NULL)
			continue;
		for (range = 0; range < __arraycount(c->c_range); range++) {
			r = &c->c_range[range];
			if (r->r_size == 0)
				break;
			if (offset >= r->r_offset &&
			    offset < r->r_offset + r->r_size) {
				flags = r->r_flags;
				break;
			}
		}
	}

	return bus_space_mmap(sc->sc_memt, offset, 0, prot, flags);
}
Пример #3
0
static paddr_t
ofb_mmap(void *v, void *vs, off_t offset, int prot)
{
	struct vcons_data *vd = v;
	struct ofb_softc *sc = vd->cookie;
	struct rasops_info *ri;
	u_int32_t *ap = sc->sc_addrs;
	int i;

	if (vd->active == NULL) {
		printf("%s: no active screen.\n", device_xname(sc->sc_dev));
		return -1;
	}
	
	ri = &vd->active->scr_ri;
	
	/* framebuffer at offset 0 */
	if ((offset >= 0) && (offset < sc->sc_fbsize))
		return bus_space_mmap(sc->sc_memt, sc->sc_fbaddr, offset, prot,
		    BUS_SPACE_MAP_LINEAR);

	/*
	 * restrict all other mappings to processes with superuser privileges
	 * or the kernel itself
	 */
	if (kauth_authorize_machdep(kauth_cred_get(), KAUTH_MACHDEP_UNMANAGEDMEM,
	    NULL, NULL, NULL, NULL) != 0) {
		printf("%s: mmap() rejected.\n", device_xname(sc->sc_dev));
		return -1;
	}

	/* let them mmap() 0xa0000 - 0xbffff if it's not covered above */
#ifdef OFB_FAKE_VGA_FB
	if (offset >=0xa0000 && offset < 0xbffff)
		return sc->sc_fbaddr + offset - 0xa0000;
#endif

	/* allow to map our IO space */
	if ((offset >= 0xf2000000) && (offset < 0xf2800000)) {
		return bus_space_mmap(sc->sc_iot, offset-0xf2000000, 0, prot, 
		    BUS_SPACE_MAP_LINEAR);	
	}
	
	for (i = 0; i < 6; i++) {
		switch (ap[0] & OFW_PCI_PHYS_HI_SPACEMASK) {
		case OFW_PCI_PHYS_HI_SPACE_MEM32:
			if (offset >= ap[2] && offset < ap[2] + ap[4])
				return bus_space_mmap(sc->sc_memt, offset, 0, 
				    prot, BUS_SPACE_MAP_LINEAR);
		}
		ap += 5;
	}
	return -1;
}
Пример #4
0
/*
 * Return the address that would map the given device at the given
 * offset, allowing for the given protection, or return -1 for error.
 *
 * Since we're pretending to be a cg8, we put the main video RAM at the
 *  same place the cg8 does, at offset 256k.  The cg8 has an enable
 *  plane in the 256k space; our "enable" plane works differently.  We
 *  can't emulate the enable plane very well, but all X uses it for is
 *  to clear it at startup - so we map the first page of video RAM over
 *  and over to fill that 256k space.  We also map some other views of
 *  the video RAM space.
 *
 * Our memory map thus looks like
 *
 *	mmap range		space	base offset
 *	00000000-00040000	vram	0 (multi-mapped - see above)
 *	00040000-00434800	vram	00000000
 *	01000000-01400000	vram	01000000
 *	02000000-02200000	vram	02000000
 *	02800000-02a00000	vram	02800000
 *	03000000-03100000	vram	03000000
 *	03400000-03500000	vram	03400000
 *	03800000-03900000	vram	03800000
 *	03c00000-03d00000	vram	03c00000
 *	10000000-10010000	regs	00000000 (only if CG14_MAP_REGS)
 */
paddr_t
cgfourteenmmap(dev_t dev, off_t off, int prot)
{
	struct cgfourteen_softc *sc =
	    device_lookup_private(&cgfourteen_cd, minor(dev));

	if (off & PGOFSET)
		panic("cgfourteenmmap");

	if (off < 0)
		return (-1);

#if defined(CG14_MAP_REGS) /* XXX: security hole */
	/*
	 * Map the control registers into user space. Should only be
	 * used for debugging!
	 */
	if ((u_int)off >= 0x10000000 && (u_int)off < 0x10000000 + 16*4096) {
		off -= 0x10000000;
		return (bus_space_mmap(sc->sc_bustag,
			BUS_ADDR(sc->sc_physadr[CG14_CTL_IDX].sbr_slot,
				   sc->sc_physadr[CG14_CTL_IDX].sbr_offset),
			off, prot, BUS_SPACE_MAP_LINEAR));
	}
#endif

	if (off < COLOUR_OFFSET)
		off = 0;
	else if (off < COLOUR_OFFSET+(1152*900*4))
		off -= COLOUR_OFFSET;
	else {
		switch (off >> 20) {
			case 0x010: case 0x011: case 0x012: case 0x013:
			case 0x020: case 0x021:
			case 0x028: case 0x029:
			case 0x030:
			case 0x034:
			case 0x038:
			case 0x03c:
				break;
			default:
				return(-1);
		}
	}

	return (bus_space_mmap(sc->sc_bustag,
		BUS_ADDR(sc->sc_physadr[CG14_PXL_IDX].sbr_slot,
			   sc->sc_physadr[CG14_PXL_IDX].sbr_offset),
		off, prot, BUS_SPACE_MAP_LINEAR));
}
Пример #5
0
static void
nouveaufb_attach_task(struct nouveau_task *task)
{
	struct nouveaufb_softc *const sc = container_of(task,
	    struct nouveaufb_softc, sc_attach_task);
	const struct nouveaufb_attach_args *const nfa = &sc->sc_nfa;
	const struct drmfb_attach_args da = {
		.da_dev = sc->sc_dev,
		.da_fb_helper = nfa->nfa_fb_helper,
		.da_fb_sizes = &nfa->nfa_fb_sizes,
		.da_fb_vaddr = __UNVOLATILE(nfa->nfa_fb_ptr),
		.da_params = &nouveaufb_drmfb_params,
	};
	int error;

	error = drmfb_attach(&sc->sc_drmfb, &da);
	if (error) {
		aprint_error_dev(sc->sc_dev, "failed to attach drmfb: %d\n",
		    error);
		return;
	}

	if (!pmf_device_register1(sc->sc_dev, NULL, NULL, &nouveaufb_shutdown))
		aprint_error_dev(sc->sc_dev,
		    "failed to register shutdown handler\n");

	sc->sc_attached = true;
}

static bool
nouveaufb_shutdown(device_t self, int flags)
{
	struct nouveaufb_softc *const sc = device_private(self);

	return drmfb_shutdown(&sc->sc_drmfb, flags);
}

static paddr_t
nouveaufb_drmfb_mmapfb(struct drmfb_softc *drmfb, off_t offset, int prot)
{
	struct nouveaufb_softc *const sc = container_of(drmfb,
	    struct nouveaufb_softc, sc_drmfb);
	struct drm_fb_helper *const helper = sc->sc_nfa.nfa_fb_helper;
	struct nouveau_fbdev *const fbdev = container_of(helper,
	    struct nouveau_fbdev, helper);
	struct nouveau_bo *const nvbo = fbdev->nouveau_fb.nvbo;
	const unsigned num_pages __diagused = nvbo->bo.num_pages;
	int flags = 0;

	KASSERT(0 <= offset);
	KASSERT(offset < (num_pages << PAGE_SHIFT));

	if (ISSET(nvbo->bo.mem.placement, TTM_PL_FLAG_WC))
		flags |= BUS_SPACE_MAP_PREFETCHABLE;

	return bus_space_mmap(nvbo->bo.bdev->memt, nvbo->bo.mem.bus.base,
	    nvbo->bo.mem.bus.offset + offset, prot, flags);
}
Пример #6
0
paddr_t
gfxp_mmap(void *v, off_t off, int prot)
{
	struct gfxp_softc *sc = v;

	if (off & PGOFSET)
		return (-1);

	switch (sc->sc_mode) {
	case WSDISPLAYIO_MODE_MAPPED:
#ifdef APERTURE
		if (allowaperture == 0)
			return (-1);
#endif

		if (sc->sc_mmiosize == 0)
			return (-1);

		if (off >= sc->sc_membase_be &&
		    off < (sc->sc_membase_be + sc->sc_memsize_be))
			return (bus_space_mmap(sc->sc_memt,
			    sc->sc_membase_be, off - sc->sc_membase_be,
			    prot, BUS_SPACE_MAP_LINEAR));

		if (off >= sc->sc_mmiobase &&
		    off < (sc->sc_mmiobase + sc->sc_mmiosize))
			return (bus_space_mmap(sc->sc_mmiot,
			    sc->sc_mmiobase, off - sc->sc_mmiobase,
			    prot, BUS_SPACE_MAP_LINEAR));
		break;

	case WSDISPLAYIO_MODE_DUMBFB:
		if (off >= 0 && off < sc->sc_memsize_le)
			return (bus_space_mmap(sc->sc_memt, sc->sc_membase_le,
			    off, prot, BUS_SPACE_MAP_LINEAR));
		break;
	}

	return (-1);
}
Пример #7
0
static paddr_t
newport_mmap(void *v, void *vs, off_t offset, int prot)
{
	struct vcons_data *vd;
	struct newport_devconfig *dc;

	vd = (struct vcons_data *)v;
	dc = (struct newport_devconfig *)vd->cookie;

	if ( offset >= 0xfffff)
		return -1;

	return bus_space_mmap(dc->dc_st, dc->dc_addr, offset, prot, 0);
}
Пример #8
0
int
sparc_vme_mmap_cookie(vme_addr_t addr, vme_am_t mod, bus_space_handle_t *hp)
{
	struct sparcvme_softc *sc = sparcvme_sc;
	bus_addr_t paddr;
	int error;

	error = vmebus_translate(sc, mod, addr, &paddr);
	if (error != 0)
		return (error);

	return (bus_space_mmap(sc->sc_bustag, paddr, 0,
		0/*prot is ignored*/, 0));
}
Пример #9
0
static paddr_t
genfb_mmap_sbus(void *v, void *vs, off_t offset, int prot)
{
	struct genfb_sbus_softc *sc = v;

	/* regular fb mapping at 0 */
	if ((offset >= 0) && (offset < sc->sc_gen.sc_fbsize)) {

		return bus_space_mmap(sc->sc_tag, sc->sc_paddr,
		    sc->sc_gen.sc_fboffset + offset, prot,
		    BUS_SPACE_MAP_LINEAR);
	}

	return -1;
}
Пример #10
0
/*
 * Return the address that would map the given device at the given
 * offset, allowing for the given protection, or return -1 for error.
 */
paddr_t
bwtwommap(dev_t dev, off_t off, int prot)
{
	struct bwtwo_softc *sc = device_lookup_private(&bwtwo_cd, minor(dev));

	if (off & PGOFSET)
		panic("bwtwommap");

	if (off >= sc->sc_fb.fb_type.fb_size)
		return (-1);

	return (bus_space_mmap(sc->sc_bustag,
		sc->sc_paddr, sc->sc_pixeloffset + off,
		prot, BUS_SPACE_MAP_LINEAR));
}
Пример #11
0
paddr_t
rfx_mmap(void *v, off_t offset, int prot)
{
	struct rfx_softc *sc = v;

	if (offset & PGOFSET)
		return (-1);

	if (offset >= 0 && offset < sc->sc_sunfb.sf_fbsize) {
		return (bus_space_mmap(sc->sc_bustag, sc->sc_paddr,
		    RFX_VRAM_ADDR + offset, prot, BUS_SPACE_MAP_LINEAR));
	}

	return (-1);
}
Пример #12
0
static paddr_t
cg14_mmap(void *v, void *vs, off_t offset, int prot)
{
	struct vcons_data *vd = v;
	struct cgfourteen_softc *sc = vd->cookie;

	/* allow mmap()ing the full framebuffer, not just what we use */
	if (offset < sc->sc_vramsize)
		return bus_space_mmap(sc->sc_bustag,
		    BUS_ADDR(sc->sc_physadr[CG14_PXL_IDX].sbr_slot,
		      sc->sc_physadr[CG14_PXL_IDX].sbr_offset),
		    offset + CG14_FB_CBGR, prot, BUS_SPACE_MAP_LINEAR);

	return -1;
}
Пример #13
0
/*
 * Return the address that would map the given device at the given
 * offset, allowing for the given protection, or return -1 for error.
 */
paddr_t
zx_mmap(void *v, off_t offset, int prot)
{
	struct zx_softc *sc = v;

	if (offset & PGOFSET)
		return (-1);

	/* Allow mapping as a dumb framebuffer from offset 0 */
	if (offset >= 0 && offset < sc->sc_sunfb.sf_fbsize) {
		return (bus_space_mmap(sc->sc_bustag, sc->sc_paddr,
		    ZX_OFF_SS0 + offset, prot, BUS_SPACE_MAP_LINEAR));
	}

	return (-1);
}
Пример #14
0
/*
 * Return the address that would map the given device at the given
 * offset, allowing for the given protection, or return -1 for error.
 */
paddr_t
cgtwelve_mmap(void *v, off_t offset, int prot)
{
	struct cgtwelve_softc *sc = v;

	if (offset & PGOFSET || offset < 0)
		return (-1);

	/*
	 * Note that mmap() will invoke this function only if we are NOT
	 * in emulation mode, so we can assume 32 bit mode safely here.
	 */
	if (offset < sc->sc_sunfb.sf_fbsize * 32) {
		return (bus_space_mmap(sc->sc_bustag, sc->sc_paddr, offset,
		    prot, BUS_SPACE_MAP_LINEAR));
	}

	return (-1);
}
Пример #15
0
/*
 * Return the address that would map the given device at the given
 * offset, allowing for the given protection, or return -1 for error.
 *
 * The cg8 maps it's overlay plane at 0 for 128K, followed by the
 * enable plane for 128K, followed by the colour for as long as it
 * goes. Starting at 8MB, it maps the ramdac for PAGE_SIZE, then the p4
 * register for PAGE_SIZE, then the bootrom for 0x40000.
 */
paddr_t
cgeightmmap(dev_t dev, off_t off, int prot)
{
	struct cgeight_softc *sc = device_lookup_private(&cgeight_cd,
							 minor(dev));
	off_t poff;

#define START_ENABLE	(128*1024)
#define START_COLOR	((128*1024) + (128*1024))
#define COLOR_SIZE	(sc->sc_fb.fb_type.fb_width * \
			    sc->sc_fb.fb_type.fb_height * 3)
#define END_COLOR	(START_COLOR + COLOR_SIZE)
#define START_SPECIAL	0x800000
#define PROMSIZE	0x40000
#define NOOVERLAY	(0x04000000)

	if (off & PGOFSET)
		panic("cgeightmap");

	if (off < 0)
		return (-1);
	else if ((u_int)off >= NOOVERLAY) {
		off -= NOOVERLAY;

		/*
		 * X11 maps a huge chunk of the frame buffer; far more than
		 * there really is. We compensate by double-mapping the
		 * first page for as many other pages as it wants
		 */
		while ((u_int)off >= COLOR_SIZE)
			off -= COLOR_SIZE;	/* XXX thorpej ??? */

		poff = off + PFOUR_COLOR_OFF_COLOR;
	} else if ((u_int)off < START_ENABLE) {
		/*
		 * in overlay plane
		 */
		poff = PFOUR_COLOR_OFF_OVERLAY + off;
	} else if ((u_int)off < START_COLOR) {
		/*
		 * in enable plane
		 */
		poff = (off - START_ENABLE) + PFOUR_COLOR_OFF_ENABLE;
	} else if ((u_int)off < sc->sc_fb.fb_type.fb_size) {
		/*
		 * in colour plane
		 */
		poff = (off - START_COLOR) + PFOUR_COLOR_OFF_COLOR;
	} else if ((u_int)off < START_SPECIAL) {
		/*
		 * hole
		 */
		poff = 0;	/* XXX */
	} else if ((u_int)off == START_SPECIAL) {
		/*
		 * colour map (Brooktree)
		 */
		poff = PFOUR_COLOR_OFF_CMAP;
	} else if ((u_int)off == START_SPECIAL + PAGE_SIZE) {
		/*
		 * p4 register
		 */
		poff = 0;
	} else if ((u_int)off > (START_SPECIAL + (PAGE_SIZE * 2)) &&
	    (u_int) off < (START_SPECIAL + (PAGE_SIZE * 2) + PROMSIZE)) {
		/*
		 * rom
		 */
		poff = 0x8000 + (off - (START_SPECIAL + (PAGE_SIZE * 2)));
	} else
		return (-1);

	return (bus_space_mmap(sc->sc_bustag,
		sc->sc_paddr, poff,
		prot, BUS_SPACE_MAP_LINEAR));
}
Пример #16
0
static paddr_t
obio_bus_mmap(bus_space_tag_t t, bus_addr_t ba, off_t off, int prot, int flags)
{

	return (bus_space_mmap(t->parent, ba, off, prot, flags));
}
/*
 * MMap bus space for a user application.
 */
paddr_t
bs_through_bs_mmap(bus_space_tag_t t, bus_addr_t addr, off_t offset,
    int prot, int flags)
{
	return bus_space_mmap(t->bs_base, addr, offset, prot, flags);
}
Пример #18
0
static void
igmafb_attach(device_t parent, device_t self, void *aux)
{
    struct igmafb_softc *sc = device_private(self);
    struct igma_attach_args *iaa = (struct igma_attach_args *)aux;
    struct rasops_info *ri;
    prop_dictionary_t dict;
    bool is_console;
    unsigned long defattr;
    struct wsemuldisplaydev_attach_args waa;

    sc->sc_dev = self;

    aprint_normal("\n");

    dict = device_properties(self);
    prop_dictionary_get_bool(dict, "is_console", &is_console);
    if (iaa->iaa_console)
        is_console = true;

    sc->sc_chip = iaa->iaa_chip;

    sc->sc_fbaddr = bus_space_vaddr(sc->sc_chip.gmt, sc->sc_chip.gmh);
    sc->sc_fbsize = 16 * 1024 * 1024;

    igmafb_guess_size(sc, &sc->sc_width, &sc->sc_height);
    sc->sc_depth = 32;
    sc->sc_stride = (sc->sc_width*4 + 511)/512*512;

    aprint_normal("%s: %d x %d, %d bit, stride %d\n", device_xname(self),
                  sc->sc_width, sc->sc_height, sc->sc_depth, sc->sc_stride);

    aprint_normal("%s: %d MB video memory at 0x%p\n", device_xname(self),
                  (int)sc->sc_fbsize >> 20, (void *)sc->sc_chip.gmb);

    sc->sc_vga_save = kmem_alloc(256*1024, KM_SLEEP);

    igmafb_get_brightness(sc, &sc->sc_brightness);
    igmafb_get_brightness_max(sc, &sc->sc_brightness_max);
    sc->sc_backlight = sc->sc_brightness != 0;

    sc->sc_defaultscreen_descr = (struct wsscreen_descr) {
        "default",
        0, 0,
        NULL,
        8, 16,
        WSSCREEN_WSCOLORS | WSSCREEN_HILIT,
        NULL
    };
    sc->sc_screens[0] = &sc->sc_defaultscreen_descr;
    sc->sc_screenlist = (struct wsscreen_list) {
        1, sc->sc_screens
    };

    vcons_init(&sc->vd, sc, &sc->sc_defaultscreen_descr,
               &igmafb_accessops);
    sc->vd.init_screen = igmafb_init_screen;

    /* enable hardware display */
    igmafb_set_mode(sc, true);

    ri = &sc->sc_console_screen.scr_ri;

    if (is_console) {
        vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1,
                          &defattr);

        sc->sc_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC
                                           | VCONS_NO_COPYROWS | VCONS_NO_COPYCOLS;
        vcons_redraw_screen(&sc->sc_console_screen);

        sc->sc_defaultscreen_descr.textops = &ri->ri_ops;
        sc->sc_defaultscreen_descr.capabilities = ri->ri_caps;
        sc->sc_defaultscreen_descr.nrows = ri->ri_rows;
        sc->sc_defaultscreen_descr.ncols = ri->ri_cols;

        wsdisplay_cnattach(&sc->sc_defaultscreen_descr, ri, 0, 0,
                           defattr);
        vcons_replay_msgbuf(&sc->sc_console_screen);
    } else {
        if (sc->sc_console_screen.scr_ri.ri_rows == 0) {
            /* do some minimal setup to avoid weirdness later */
            vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1,
                              &defattr);
        } else
            (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
    }

    waa.console = is_console;
    waa.scrdata = &sc->sc_screenlist;
    waa.accessops = &igmafb_accessops;
    waa.accesscookie = &sc->vd;

    config_found(sc->sc_dev, &waa, wsemuldisplaydevprint);
}

/*
 * wsdisplay accessops
 */

static int
igmafb_ioctl(void *v, void *vs, u_long cmd, void *data, int flags,
             struct lwp *l)
{
    struct vcons_data *vd = v;
    struct igmafb_softc *sc = vd->cookie;
    struct wsdisplay_fbinfo *wdf;
    struct vcons_screen *ms = vd->active;
    struct wsdisplayio_fbinfo *fbi;
    struct wsdisplay_param *param;
    int val;

    switch (cmd) {
    case WSDISPLAYIO_GTYPE:
        *(u_int *)data = WSDISPLAY_TYPE_PCIMISC;
        return 0;
    case WSDISPLAYIO_GINFO:
        if (ms == NULL)
            return ENODEV;
        wdf = data;
        wdf->width  = ms->scr_ri.ri_width;
        wdf->height = ms->scr_ri.ri_height;
        wdf->depth  = ms->scr_ri.ri_depth;
        wdf->cmsize = 256; /* XXX */
        return 0;
    case WSDISPLAYIO_LINEBYTES:
        if (ms == NULL)
            return ENODEV;
        *(u_int *)data = ms->scr_ri.ri_stride;
        return 0;
    case WSDISPLAYIO_GET_FBINFO:
        fbi = data;
        return wsdisplayio_get_fbinfo(&ms->scr_ri, fbi);
    case WSDISPLAYIO_SVIDEO:
        val = (*(u_int *)data) != WSDISPLAYIO_VIDEO_OFF;
        sc->sc_backlight = val;
        if (val)
            igmafb_set_brightness(sc, sc->sc_brightness);
        else
            igmafb_set_brightness(sc, 0);
        return 0;
    case WSDISPLAYIO_GETPARAM:
        param = (struct wsdisplay_param *)data;
        switch (param->param) {
        case WSDISPLAYIO_PARAM_BRIGHTNESS:
            param->min = 0;
            param->max = 255;
            if (sc->sc_backlight)
                igmafb_get_brightness(sc, &val);
            else
                val = sc->sc_brightness;
            val = val * 255 / sc->sc_brightness_max;
            param->curval = val;
            return 0;
        case WSDISPLAYIO_PARAM_BACKLIGHT:
            param->min = 0;
            param->max = 1;
            param->curval = sc->sc_backlight;
            return 0;
        }
        return EPASSTHROUGH;
    case WSDISPLAYIO_SETPARAM:
        param = (struct wsdisplay_param *)data;
        switch (param->param) {
        case WSDISPLAYIO_PARAM_BRIGHTNESS:
            val = param->curval;
            if (val < 0)
                val = 0;
            if (val > 255)
                val = 255;
            val = val * sc->sc_brightness_max / 255;
            sc->sc_brightness = val;
            if (sc->sc_backlight)
                igmafb_set_brightness(sc, val);
            return 0;
        case WSDISPLAYIO_PARAM_BACKLIGHT:
            val = param->curval;
            sc->sc_backlight = val;
            if (val)
                igmafb_set_brightness(sc, sc->sc_brightness);
            else
                igmafb_set_brightness(sc, 0);
            return 0;
        }
        return EPASSTHROUGH;
    }

    return EPASSTHROUGH;
}

static paddr_t
igmafb_mmap(void *v, void *vs, off_t offset, int prot)
{
    struct vcons_data *vd = v;
    struct igmafb_softc *sc = vd->cookie;

    if ((offset & PAGE_MASK) != 0)
        return -1;

    if (offset < 0 || offset >= sc->sc_fbsize)
        return -1;

    return bus_space_mmap(sc->sc_chip.gmt, sc->sc_chip.gmb, offset, prot,
                          BUS_SPACE_MAP_LINEAR);
}

static void
igmafb_pollc(void *v, int on)
{
    struct vcons_data *vd = v;
    struct igmafb_softc *sc = vd->cookie;

    if (sc == NULL)
        return;
    if (sc->sc_console_screen.scr_vd == NULL)
        return;

    if (on)
        vcons_enable_polling(&sc->vd);
    else
        vcons_disable_polling(&sc->vd);
}

static void
igmafb_init_screen(void *cookie, struct vcons_screen *scr,
                   int existing, long *defattr)
{
    struct igmafb_softc *sc = cookie;
    struct rasops_info *ri = &scr->scr_ri;

    memset(ri, 0, sizeof(struct rasops_info));

    ri->ri_depth = sc->sc_depth;
    ri->ri_width = sc->sc_width;
    ri->ri_height = sc->sc_height;
    ri->ri_stride = sc->sc_stride;
    ri->ri_flg = RI_CENTER | RI_FULLCLEAR;

    ri->ri_bits = (char *)sc->sc_fbaddr;

    if (existing) {
        ri->ri_flg |= RI_CLEAR;
    }

    switch (sc->sc_depth) {
    case 32:
        ri->ri_rnum = 8;
        ri->ri_gnum = 8;
        ri->ri_bnum = 8;
        ri->ri_rpos = 16;
        ri->ri_gpos = 8;
        ri->ri_bpos = 0;
        break;
    }

    rasops_init(ri, 0, 0);
    ri->ri_caps = WSSCREEN_WSCOLORS;

    rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight,
                    sc->sc_width / ri->ri_font->fontwidth);

    ri->ri_hw = scr;
}

static void
igmafb_guess_size(struct igmafb_softc *sc, int *widthp, int *heightp)
{
    const struct igma_chip *cd = &sc->sc_chip;
    const struct igma_chip_ops *co = cd->ops;
    int pipe = cd->use_pipe;
    u_int32_t r;

    r = co->read_reg(cd, PIPE_HTOTAL(pipe));
    *widthp = PIPE_HTOTAL_GET_ACTIVE(r);
    r = co->read_reg(cd, PIPE_VTOTAL(pipe));
    *heightp = PIPE_VTOTAL_GET_ACTIVE(r);

    aprint_normal("%s: vga active size %d x %d\n",
                  device_xname(sc->sc_dev),
                  *widthp, *heightp);

    if (*widthp < 640 || *heightp < 400) {
        r = co->read_reg(cd, PF_WINSZ(pipe));
        *widthp  = PF_WINSZ_GET_WIDTH(r);
        *heightp = PF_WINSZ_GET_HEIGHT(r);

        aprint_normal("%s: window size %d x %d\n",
                      device_xname(sc->sc_dev),
                      *widthp, *heightp);
    }

    if (*widthp  < 640) *widthp  = 640;
    if (*heightp < 400) *heightp = 400;
}

static void
igmafb_set_mode(struct igmafb_softc *sc, bool enable)
{
    const struct igma_chip *cd = &sc->sc_chip;
    const struct igma_chip_ops *co = cd->ops;
    int pipe = cd->use_pipe;
    u_int32_t r;
    u_int8_t b;
    int i;

    if (enable) {
        /* disable VGA machinery */
        b = co->read_vga(cd, 0x01);
        co->write_vga(cd, 0x01, b | 0x20);

        /* disable VGA compatible display */
        r = co->read_reg(cd, sc->sc_chip.vga_cntrl);
        co->write_reg(cd, sc->sc_chip.vga_cntrl, r | VGA_CNTRL_DISABLE);

        /* save VGA memory */
        memcpy(sc->sc_vga_save, sc->sc_fbaddr, 256*1024);

        /* configure panel fitter */
        co->write_reg(cd, PF_WINPOS(pipe),
                      PF_WINPOS_VAL(0, 0));
        co->write_reg(cd, PF_WINSZ(pipe),
                      PF_WINSZ_VAL(sc->sc_width, sc->sc_height));

        /* pipe size */
        co->write_reg(cd, PIPE_SRCSZ(pipe),
                      PIPE_SRCSZ_VAL(sc->sc_width, sc->sc_height));

        /* enable pipe */
        co->write_reg(cd, PIPE_CONF(pipe),
                      PIPE_CONF_ENABLE | PIPE_CONF_8BPP);

        /* configure planes */
        r = co->read_reg(cd, PRI_CTRL(pipe));
        r &= ~(PRI_CTRL_PIXFMTMSK | PRI_CTRL_TILED);
        r |= PRI_CTRL_ENABLE | PRI_CTRL_BGR;
        co->write_reg(cd, PRI_CTRL(pipe), r | cd->pri_cntrl);
        co->write_reg(cd, PRI_LINOFF(pipe), 0);
        co->write_reg(cd, PRI_STRIDE(pipe), sc->sc_stride);
        co->write_reg(cd, PRI_SURF(pipe), 0);
        co->write_reg(cd, PRI_TILEOFF(pipe), 0);

        if (cd->quirks & IGMA_PLANESTART_QUIRK)
            igmafb_planestart_quirk(sc);

        if (cd->quirks & IGMA_PFITDISABLE_QUIRK)
            igmafb_pfitdisable_quirk(sc);
    } else {
        /* disable planes */
        co->write_reg(cd, PRI_CTRL(pipe), 0 | cd->pri_cntrl);
        co->write_reg(cd, PRI_LINOFF(pipe), 0);
        co->write_reg(cd, PRI_STRIDE(pipe), 2560);
        co->write_reg(cd, PRI_SURF(pipe), 0);
        co->write_reg(cd, PRI_TILEOFF(pipe), 0);

        /* pipe size */
        co->write_reg(cd, PIPE_SRCSZ(pipe),
                      PIPE_SRCSZ_VAL(720,400));

        /* disable pipe */
        co->write_reg(cd, PIPE_CONF(pipe), 0);
        for (i=0; i<10; ++i) {
            delay(10);
            if ((co->read_reg(cd, PIPE_CONF(pipe)) & PIPE_CONF_STATE) == 0)
                break;
        }

        /* workaround before enabling VGA */
        r = co->read_reg(cd, 0x42000);
        co->write_reg(cd, 0x42000, (r & 0x1fffffff) | 0xa0000000);
        r = co->read_reg(cd, 0x42004);
        co->write_reg(cd, 0x42004, (r & 0xfbffffff) | 0x00000000);

        /* configure panel fitter */
        co->write_reg(cd, PF_WINPOS(pipe),
                      PF_WINPOS_VAL(0, 0));
        co->write_reg(cd, PF_WINSZ(pipe),
                      PF_WINSZ_VAL(sc->sc_width, sc->sc_height));

        /* enable VGA compatible display */
        r = co->read_reg(cd, sc->sc_chip.vga_cntrl);
        co->write_reg(cd, sc->sc_chip.vga_cntrl, r & ~VGA_CNTRL_DISABLE);

        /* enable VGA machinery */
        b = co->read_vga(cd, 0x01);
        co->write_vga(cd, 0x01, b & ~0x20);

        /* restore VGA memory */
        memcpy(sc->sc_fbaddr, sc->sc_vga_save, 256*1024);

        /* enable pipe again */
        co->write_reg(cd, PIPE_CONF(pipe),
                      PIPE_CONF_ENABLE | PIPE_CONF_6BPP | PIPE_CONF_DITHER);
    }
}

static void
igmafb_planestart_quirk(struct igmafb_softc *sc)
{
    const struct igma_chip *cd = &sc->sc_chip;
    const struct igma_chip_ops *co = cd->ops;
    int pipe = cd->use_pipe;
    u_int32_t cntrl, fwbcl;

    /* disable self refresh */
    fwbcl = co->read_reg(cd, FW_BLC_SELF);
    co->write_reg(cd, FW_BLC_SELF, fwbcl & ~FW_BLC_SELF_EN);

    cntrl = co->read_reg(cd, CUR_CNTR(pipe));
    co->write_reg(cd, CUR_CNTR(pipe), 1<<5 | 0x07);

    /* "wait for vblank" */
    delay(40000);

    co->write_reg(cd, CUR_CNTR(pipe), cntrl);
    co->write_reg(cd, CUR_BASE(pipe),
                  co->read_reg(cd, CUR_BASE(pipe)));

    co->write_reg(cd, FW_BLC_SELF, fwbcl);
}

static void
igmafb_pfitdisable_quirk(struct igmafb_softc *sc)
{
    const struct igma_chip *cd = &sc->sc_chip;
    const struct igma_chip_ops *co = cd->ops;
    u_int32_t r;

    /* disable i965 panel fitter */
    r = co->read_reg(cd, PF_CTRL_I965);
    co->write_reg(cd, PF_CTRL_I965, r & ~PF_ENABLE);
}

static void
igmafb_get_brightness_max(struct igmafb_softc *sc, int *valp)
{
    const struct igma_chip *cd = &sc->sc_chip;
    const struct igma_chip_ops *co = cd->ops;
    u_int32_t r, f;

    r = co->read_reg(cd, cd->backlight_cntrl);
    f = BACKLIGHT_GET_FREQ(r);
    if (f == 0) {
        r = co->read_reg(cd, RAWCLK_FREQ);
        f = r * 1000000 / (200 * 128);
        if (f == 0 || f > 32767)
            f = 125 * 100000 / (200 * 128);
    }

    *valp = f;
}

static void
igmafb_get_brightness(struct igmafb_softc *sc, int *valp)
{
    const struct igma_chip *cd = &sc->sc_chip;
    const struct igma_chip_ops *co = cd->ops;
    u_int32_t r, v;

    r = co->read_reg(cd, cd->backlight_cntrl);
    v = BACKLIGHT_GET_CYCLE(r);
    *valp = v;
}

static void
igmafb_set_brightness(struct igmafb_softc *sc, int val)
{
    const struct igma_chip *cd = &sc->sc_chip;
    const struct igma_chip_ops *co = cd->ops;
    u_int32_t r, f, l;

    r = co->read_reg(cd, cd->backlight_cntrl);
    f = BACKLIGHT_GET_FREQ(r);
    l = BACKLIGHT_GET_LEGACY(r);

    co->write_reg(cd, cd->backlight_cntrl,
                  BACKLIGHT_VAL(f,l,val));
}