#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <machine/bus.h>
#include <dev/wscons/wsconsio.h>
#include <dev/wscons/wsdisplayvar.h>
#include <dev/rasops/rasops.h>
#include <dev/ofw/openfirm.h>
#include <macppc/macppc/ofw_machdep.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/vga_pcivar.h>
struct vgafb_softc {
struct device sc_dev;
int sc_node;
bus_addr_t sc_mem_addr, sc_mmio_addr;
bus_size_t sc_mem_size, sc_mmio_size;
struct rasops_info sc_ri;
uint8_t sc_cmap[256 * 3];
u_int sc_mode;
struct wsscreen_descr sc_wsd;
struct wsscreen_list sc_wsl;
struct wsscreen_descr *sc_scrlist[1];
int sc_backlight_on;
};
int vgafb_ioctl(void *, u_long, caddr_t, int, struct proc *);
paddr_t vgafb_mmap(void *, off_t, int);
int vgafb_alloc_screen(void *, const struct wsscreen_descr *, void **,
int *, int *, uint32_t *);
void vgafb_free_screen(void *, void *);
int vgafb_show_screen(void *, void *, int, void (*cb)(void *, int, int),
void *);
int vgafb_load_font(void *, void *, struct wsdisplay_font *);
int vgafb_list_font(void *, struct wsdisplay_font *);
void vgafb_burn(void *v, u_int , u_int);
void vgafb_restore_default_colors(struct vgafb_softc *);
int vgafb_is_console(int);
int vgafb_console_init(struct vgafb_softc *);
int vgafb_mapregs(struct vgafb_softc *, struct pci_attach_args *);
struct wsdisplay_accessops vgafb_accessops = {
.ioctl = vgafb_ioctl,
.mmap = vgafb_mmap,
.alloc_screen = vgafb_alloc_screen,
.free_screen = vgafb_free_screen,
.show_screen = vgafb_show_screen,
.load_font = vgafb_load_font,
.list_font = vgafb_list_font,
.burn_screen = vgafb_burn
};
int vgafb_getcmap(uint8_t *, struct wsdisplay_cmap *);
int vgafb_putcmap(uint8_t *, struct wsdisplay_cmap *);
int vgafb_match(struct device *, void *, void *);
void vgafb_attach(struct device *, struct device *, void *);
const struct cfattach vgafb_ca = {
sizeof(struct vgafb_softc), vgafb_match, vgafb_attach,
};
struct cfdriver vgafb_cd = {
NULL, "vgafb", DV_DULL,
};
#ifdef APERTURE
extern int allowaperture;
#endif
int
vgafb_match(struct device *parent, void *match, void *aux)
{
struct pci_attach_args *pa = aux;
int node;
if (DEVICE_IS_VGA_PCI(pa->pa_class) == 0) {
if (PCI_CLASS(pa->pa_class) != PCI_CLASS_DISPLAY ||
PCI_SUBCLASS(pa->pa_class) != PCI_SUBCLASS_DISPLAY_MISC)
return (0);
}
node = PCITAG_NODE(pa->pa_tag);
if (!vgafb_is_console(node))
return (0);
return (1);
}
void
vgafb_attach(struct device *parent, struct device *self, void *aux)
{
struct vgafb_softc *sc = (struct vgafb_softc *)self;
struct pci_attach_args *pa = aux;
struct wsemuldisplaydev_attach_args waa;
sc->sc_node = PCITAG_NODE(pa->pa_tag);
if (vgafb_mapregs(sc, pa))
return;
if (vgafb_console_init(sc))
return;
sc->sc_scrlist[0] = &sc->sc_wsd;
sc->sc_wsl.nscreens = 1;
sc->sc_wsl.screens = (const struct wsscreen_descr **)sc->sc_scrlist;
waa.console = 1;
waa.scrdata = &sc->sc_wsl;
waa.accessops = &vgafb_accessops;
waa.accesscookie = sc;
waa.defaultscreens = 0;
if (cons_backlight_available == 0)
vgafb_accessops.burn_screen = NULL;
else {
sc->sc_backlight_on = WSDISPLAYIO_VIDEO_OFF;
vgafb_burn(sc, WSDISPLAYIO_VIDEO_ON, 0);
}
#ifdef RAMDISK_HOOKS
if (vga_aperture_needed(pa))
printf("%s: aperture needed\n", sc->sc_dev.dv_xname);
#endif
config_found(self, &waa, wsemuldisplaydevprint);
}
int
vgafb_console_init(struct vgafb_softc *sc)
{
struct rasops_info *ri = &sc->sc_ri;
uint32_t defattr;
ri->ri_flg = RI_CENTER | RI_VCONS | RI_WRONLY;
ri->ri_hw = sc;
ofwconsswitch(ri);
rasops_init(ri, 160, 160);
strlcpy(sc->sc_wsd.name, "std", sizeof(sc->sc_wsd.name));
sc->sc_wsd.capabilities = ri->ri_caps;
sc->sc_wsd.nrows = ri->ri_rows;
sc->sc_wsd.ncols = ri->ri_cols;
sc->sc_wsd.textops = &ri->ri_ops;
sc->sc_wsd.fontwidth = ri->ri_font->fontwidth;
sc->sc_wsd.fontheight = ri->ri_font->fontheight;
ri->ri_ops.pack_attr(ri->ri_active, 0, 0, 0, &defattr);
wsdisplay_cnattach(&sc->sc_wsd, ri->ri_active, ri->ri_ccol, ri->ri_crow,
defattr);
return (0);
}
void
vgafb_restore_default_colors(struct vgafb_softc *sc)
{
bcopy(rasops_cmap, sc->sc_cmap, sizeof(sc->sc_cmap));
of_setcolors(sc->sc_cmap, 0, 256);
}
int
vgafb_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
{
struct vgafb_softc *sc = v;
struct rasops_info *ri = &sc->sc_ri;
struct wsdisplay_cmap *cm;
struct wsdisplay_fbinfo *wdf;
int rc;
switch (cmd) {
case WSDISPLAYIO_GTYPE:
*(u_int *)data = WSDISPLAY_TYPE_PCIVGA;
break;
case WSDISPLAYIO_GINFO:
wdf = (struct wsdisplay_fbinfo *)data;
wdf->width = ri->ri_width;
wdf->height = ri->ri_height;
wdf->depth = ri->ri_depth;
wdf->stride = ri->ri_stride;
wdf->offset = 0;
wdf->cmsize = 256;
break;
case WSDISPLAYIO_LINEBYTES:
*(uint *)data = ri->ri_stride;
break;
case WSDISPLAYIO_GETCMAP:
cm = (struct wsdisplay_cmap *)data;
rc = vgafb_getcmap(sc->sc_cmap, cm);
if (rc != 0)
return rc;
break;
case WSDISPLAYIO_PUTCMAP:
cm = (struct wsdisplay_cmap *)data;
rc = vgafb_putcmap(sc->sc_cmap, cm);
if (rc != 0)
return (rc);
if (ri->ri_depth == 8)
of_setcolors(sc->sc_cmap, cm->index, cm->count);
break;
case WSDISPLAYIO_SMODE:
sc->sc_mode = *(u_int *)data;
if (ri->ri_depth == 8)
vgafb_restore_default_colors(sc);
break;
case WSDISPLAYIO_GETPARAM:
{
struct wsdisplay_param *dp = (struct wsdisplay_param *)data;
switch (dp->param) {
case WSDISPLAYIO_PARAM_BRIGHTNESS:
if (cons_backlight_available != 0) {
dp->min = MIN_BRIGHTNESS;
dp->max = MAX_BRIGHTNESS;
dp->curval = cons_brightness;
return 0;
}
return -1;
case WSDISPLAYIO_PARAM_BACKLIGHT:
if (cons_backlight_available != 0) {
dp->min = 0;
dp->max = 1;
dp->curval = sc->sc_backlight_on;
return 0;
} else
return -1;
}
}
return -1;
case WSDISPLAYIO_SETPARAM:
{
struct wsdisplay_param *dp = (struct wsdisplay_param *)data;
switch (dp->param) {
case WSDISPLAYIO_PARAM_BRIGHTNESS:
if (cons_backlight_available == 1) {
of_setbrightness(dp->curval);
return 0;
} else
return -1;
case WSDISPLAYIO_PARAM_BACKLIGHT:
if (cons_backlight_available != 0) {
vgafb_burn(sc,
dp->curval ? WSDISPLAYIO_VIDEO_ON :
WSDISPLAYIO_VIDEO_OFF, 0);
return 0;
} else
return -1;
}
}
return -1;
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;
}
return (0);
}
paddr_t
vgafb_mmap(void *v, off_t off, int prot)
{
struct vgafb_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_mmio_size == 0)
return (-1);
if (off >= sc->sc_mem_addr &&
off < (sc->sc_mem_addr + sc->sc_mem_size))
return (off);
if (off >= sc->sc_mmio_addr &&
off < (sc->sc_mmio_addr + sc->sc_mmio_size))
return (off);
break;
case WSDISPLAYIO_MODE_DUMBFB:
if (off >= 0x00000 && off < sc->sc_mem_size)
return (sc->sc_mem_addr + off);
break;
}
return (-1);
}
int
vgafb_is_console(int node)
{
extern int fbnode;
return (fbnode == node);
}
int
vgafb_getcmap(uint8_t *cmap, struct wsdisplay_cmap *cm)
{
uint index = cm->index, count = cm->count, i;
uint8_t ramp[256], *dst, *src;
int rc;
if (index >= 256 || count > 256 - index)
return EINVAL;
index *= 3;
src = cmap + index;
dst = ramp;
for (i = 0; i < count; i++)
*dst++ = *src, src += 3;
rc = copyout(ramp, cm->red, count);
if (rc != 0)
return rc;
src = cmap + index + 1;
dst = ramp;
for (i = 0; i < count; i++)
*dst++ = *src, src += 3;
rc = copyout(ramp, cm->green, count);
if (rc != 0)
return rc;
src = cmap + index + 2;
dst = ramp;
for (i = 0; i < count; i++)
*dst++ = *src, src += 3;
rc = copyout(ramp, cm->blue, count);
if (rc != 0)
return rc;
return 0;
}
int
vgafb_putcmap(uint8_t *cmap, struct wsdisplay_cmap *cm)
{
uint index = cm->index, count = cm->count, i;
uint8_t ramp[256], *dst, *src;
int rc;
if (index >= 256 || count > 256 - index)
return EINVAL;
index *= 3;
rc = copyin(cm->red, ramp, count);
if (rc != 0)
return rc;
dst = cmap + index;
src = ramp;
for (i = 0; i < count; i++)
*dst = *src++, dst += 3;
rc = copyin(cm->green, ramp, count);
if (rc != 0)
return rc;
dst = cmap + index + 1;
src = ramp;
for (i = 0; i < count; i++)
*dst = *src++, dst += 3;
rc = copyin(cm->blue, ramp, count);
if (rc != 0)
return rc;
dst = cmap + index + 2;
src = ramp;
for (i = 0; i < count; i++)
*dst = *src++, dst += 3;
return 0;
}
void
vgafb_burn(void *v, u_int on, u_int flags)
{
struct vgafb_softc *sc = v;
if (sc->sc_backlight_on != on) {
of_setbacklight(on == WSDISPLAYIO_VIDEO_ON);
sc->sc_backlight_on = on;
}
}
int
vgafb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
int *curxp, int *curyp, uint32_t *attrp)
{
struct vgafb_softc *sc = v;
struct rasops_info *ri = &sc->sc_ri;
return rasops_alloc_screen(ri, cookiep, curxp, curyp, attrp);
}
void
vgafb_free_screen(void *v, void *cookie)
{
struct vgafb_softc *sc = v;
struct rasops_info *ri = &sc->sc_ri;
return rasops_free_screen(ri, cookie);
}
int
vgafb_show_screen(void *v, void *cookie, int waitok,
void (*cb)(void *, int, int), void *cbarg)
{
struct vgafb_softc *sc = v;
struct rasops_info *ri = &sc->sc_ri;
if (cookie == ri->ri_active)
return (0);
return rasops_show_screen(ri, cookie, waitok, cb, cbarg);
}
int
vgafb_load_font(void *v, void *emulcookie, struct wsdisplay_font *font)
{
struct vgafb_softc *sc = v;
struct rasops_info *ri = &sc->sc_ri;
return rasops_load_font(ri, emulcookie, font);
}
int
vgafb_list_font(void *v, struct wsdisplay_font *font)
{
struct vgafb_softc *sc = v;
struct rasops_info *ri = &sc->sc_ri;
return rasops_list_font(ri, font);
}
int
vgafb_mapregs(struct vgafb_softc *sc, struct pci_attach_args *pa)
{
bus_addr_t ba;
bus_size_t bs;
int hasmem = 0, hasmmio = 0;
uint32_t bar, cf;
int rv;
for (bar = PCI_MAPREG_START; bar <= PCI_MAPREG_PPB_END; bar += 4) {
cf = pci_conf_read(pa->pa_pc, pa->pa_tag, bar);
if (PCI_MAPREG_TYPE(cf) == PCI_MAPREG_TYPE_MEM) {
rv = pci_mapreg_info(pa->pa_pc, pa->pa_tag, bar,
_PCI_MAPREG_TYPEBITS(cf), &ba, &bs, NULL);
if (rv != 0)
continue;
if (bs == 0 ) {
} else if (hasmem == 0) {
sc->sc_mem_addr = ba;
sc->sc_mem_size = bs;
hasmem = 1;
} else {
if (sc->sc_mem_size >= bs) {
sc->sc_mmio_addr = ba;
sc->sc_mmio_size = bs;
hasmmio = 1;
} else {
sc->sc_mmio_addr = sc->sc_mem_addr;
sc->sc_mmio_size = sc->sc_mem_size;
sc->sc_mem_addr = ba;
sc->sc_mem_size = bs;
}
break;
}
if (PCI_MAPREG_MEM_TYPE(cf) ==
PCI_MAPREG_MEM_TYPE_64BIT)
bar += 4;
}
}
if (hasmem == 0) {
printf(": could not find memory space\n");
return (1);
}
if (hasmmio)
printf (", mmio");
printf("\n");
return (0);
}