diff --git a/sys/dev/wsfb/files.wsfb b/sys/dev/wsfb/files.wsfb new file mode 100644 index 000000000000..b60d2d965cee --- /dev/null +++ b/sys/dev/wsfb/files.wsfb @@ -0,0 +1,22 @@ +# $NetBSD: files.wsfb,v 1.1 2007/04/07 03:41:26 macallan Exp $ + +# +# wsdisplay framebuffer drivers +# + +# some generic flags that drivers may or may not honour +defflag opt_wsfb.h WSFB_FAKE_VGA_FB # allow mmap(0xa0000) +defflag opt_wsfb.h WSFB_ALLOW_OTHERS # allow to mmap() foreign ranges + +# a generic framebuffer console +device genfb: wsemuldisplaydev, rasops8, vcons, drm +file dev/wsfb/genfb.c genfb +defflag opt_genfb.h GENFB_DEBUG + +# a PCI frontend for genfb +attach genfb at pci with pci_genfb +file dev/wsfb/pci_genfb.c genfb + +# an SBus frontend for genfb +#attach genfb at sbus with sbus_genfb +#file dev/wsfb/sbus_genfb.c genfb diff --git a/sys/dev/wsfb/genfb.c b/sys/dev/wsfb/genfb.c new file mode 100644 index 000000000000..653c7e07274f --- /dev/null +++ b/sys/dev/wsfb/genfb.c @@ -0,0 +1,360 @@ +/* $NetBSD: genfb.c,v 1.1 2007/04/07 03:41:26 macallan Exp $ */ + +/*- + * Copyright (c) 2007 Michael Lorenz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: genfb.c,v 1.1 2007/04/07 03:41:26 macallan Exp $"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include + +#include "opt_genfb.h" +#include "opt_wsfb.h" + +static int genfb_ioctl(void *, void *, u_long, void *, int, struct lwp *); +static paddr_t genfb_mmap(void *, void *, off_t, int); +static void genfb_init_screen(void *, struct vcons_screen *, int, long *); + +static int genfb_putcmap(struct genfb_softc *, struct wsdisplay_cmap *); +static int genfb_getcmap(struct genfb_softc *, struct wsdisplay_cmap *); +static void genfb_restore_palette(struct genfb_softc *); +static int genfb_putpalreg(struct genfb_softc *, uint8_t, uint8_t, + uint8_t, uint8_t); + +extern const u_char rasops_cmap[768]; + +struct wsdisplay_accessops genfb_accessops = { + genfb_ioctl, + genfb_mmap, + NULL, /* load_font */ + NULL, /* polls */ + NULL, /* scroll */ +}; + +int genfb_attach(struct genfb_softc *sc, struct genfb_ops *ops) +{ + struct wsemuldisplaydev_attach_args aa; + prop_dictionary_t dict; + struct rasops_info *ri; + long defattr; + uint32_t fbaddr; + int console, i, j; + + sc->sc_defaultscreen_descr = (struct wsscreen_descr){ + "default", + 0, 0, + NULL, + 8, 16, + WSSCREEN_WSCOLORS | WSSCREEN_HILIT, + }; + sc->sc_screens[0] = &sc->sc_defaultscreen_descr; + sc->sc_screenlist = (struct wsscreen_list){1, sc->sc_screens}; + memcpy(&sc->sc_ops, ops, sizeof(struct genfb_ops)); + sc->sc_mode = WSDISPLAYIO_MODE_EMUL; + + dict = device_properties(&sc->sc_dev); +#ifdef GENFB_DEBUG + printf(prop_dictionary_externalize(dict)); +#endif + if (!prop_dictionary_get_uint32(dict, "width", &sc->sc_width)) + panic("no width property"); + if (!prop_dictionary_get_uint32(dict, "height", &sc->sc_height)) + panic("no height property"); + if (!prop_dictionary_get_uint32(dict, "depth", &sc->sc_depth)) + panic("no depth property"); + /* XXX */ + if (!prop_dictionary_get_uint32(dict, "address", &fbaddr)) + panic("no address property"); + sc->sc_fbaddr = fbaddr; + + sc->sc_fbsize = sc->sc_width * sc->sc_stride; + + if (!prop_dictionary_get_uint32(dict, "linebytes", &sc->sc_stride)) + sc->sc_stride = (sc->sc_width * sc->sc_depth) >> 3; + + prop_dictionary_get_bool(dict, "is_console", &console); + + vcons_init(&sc->vd, sc, &sc->sc_defaultscreen_descr, + &genfb_accessops); + sc->vd.init_screen = genfb_init_screen; + + ri = &sc->sc_console_screen.scr_ri; + + if (console) { + vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1, + &defattr); + sc->sc_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC; + + 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); + } else { + /* + * since we're not the console we can postpone the rest + * until someone actually allocates a screen for us + */ + } + + j = 0; + for (i = 0; i < 256; i++) { + genfb_putpalreg(sc, i, rasops_cmap[j], rasops_cmap[j + 1], + rasops_cmap[j + 2]); + j += 3; + } + + aa.console = console; + aa.scrdata = &sc->sc_screenlist; + aa.accessops = &genfb_accessops; + aa.accesscookie = &sc->vd; + + config_found(&sc->sc_dev, &aa, wsemuldisplaydevprint); + + return 0; +} + +static int +genfb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, + struct lwp *l) +{ + struct vcons_data *vd = v; + struct genfb_softc *sc = vd->cookie; + struct wsdisplay_fbinfo *wdf; + struct vcons_screen *ms = vd->active; + + switch (cmd) { + + case WSDISPLAYIO_GINFO: + wdf = (void *)data; + wdf->height = ms->scr_ri.ri_height; + wdf->width = ms->scr_ri.ri_width; + wdf->depth = ms->scr_ri.ri_depth; + wdf->cmsize = 256; + return 0; + + case WSDISPLAYIO_GETCMAP: + return genfb_getcmap(sc, + (struct wsdisplay_cmap *)data); + + case WSDISPLAYIO_PUTCMAP: + return genfb_putcmap(sc, + (struct wsdisplay_cmap *)data); + + case WSDISPLAYIO_SMODE: + { + int new_mode = *(int*)data; + if (new_mode != sc->sc_mode) { + sc->sc_mode = new_mode; + if(new_mode == WSDISPLAYIO_MODE_EMUL) { + genfb_restore_palette(sc); + vcons_redraw_screen(ms); + } + } + } + return 0; + default: + if (sc->sc_ops.genfb_ioctl) + return sc->sc_ops.genfb_ioctl(sc, vs, cmd, + data, flag, l); + } + return EPASSTHROUGH; +} + +static paddr_t +genfb_mmap(void *v, void *vs, off_t offset, int prot) +{ + struct vcons_data *vd = v; + struct genfb_softc *sc = vd->cookie; + struct lwp *me; + + /* 'regular' framebuffer mmap()ing */ + if (offset < sc->sc_fbsize) { + /* XXX */ + return sc->sc_fbaddr + offset; + } + + /* + * restrict all other mappings to processes with superuser privileges + * or the kernel itself + */ + me = curlwp; + if (me != NULL) { + if (kauth_authorize_generic(me->l_cred, KAUTH_GENERIC_ISSUSER, + NULL) != 0) { + aprint_normal("%s: mmap() rejected.\n", + sc->sc_dev.dv_xname); + return -1; + } + } + +#ifdef WSFB_FAKE_VGA_FB + if ((offset >= 0xa0000) && (offset < 0xbffff)) { + + /* XXX */ + return sc->sc_fbaddr - 0xa0000 + offset; + } +#endif + + if (sc->sc_ops.genfb_mmap) + return sc->sc_ops.genfb_mmap(sc, vs, offset, prot); + + return -1; +} + +static void +genfb_init_screen(void *cookie, struct vcons_screen *scr, + int existing, long *defattr) +{ + struct genfb_softc *sc = cookie; + struct rasops_info *ri = &scr->scr_ri; + + 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; + } + + rasops_init(ri, sc->sc_height / 8, sc->sc_width / 8); + 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 int +genfb_putcmap(struct genfb_softc *sc, struct wsdisplay_cmap *cm) +{ + u_char *r, *g, *b; + u_int index = cm->index; + u_int count = cm->count; + int i, error; + u_char rbuf[256], gbuf[256], bbuf[256]; + +#ifdef GENFB_DEBUG + aprint_debug("putcmap: %d %d\n",index, count); +#endif + if (cm->index >= 256 || cm->count > 256 || + (cm->index + cm->count) > 256) + return EINVAL; + error = copyin(cm->red, &rbuf[index], count); + if (error) + return error; + error = copyin(cm->green, &gbuf[index], count); + if (error) + return error; + error = copyin(cm->blue, &bbuf[index], count); + if (error) + return error; + + memcpy(&sc->sc_cmap_red[index], &rbuf[index], count); + memcpy(&sc->sc_cmap_green[index], &gbuf[index], count); + memcpy(&sc->sc_cmap_blue[index], &bbuf[index], count); + + r = &sc->sc_cmap_red[index]; + g = &sc->sc_cmap_green[index]; + b = &sc->sc_cmap_blue[index]; + + for (i = 0; i < count; i++) { + genfb_putpalreg(sc, index, *r, *g, *b); + index++; + r++, g++, b++; + } + return 0; +} + +static int +genfb_getcmap(struct genfb_softc *sc, struct wsdisplay_cmap *cm) +{ + u_int index = cm->index; + u_int count = cm->count; + int error; + + if (index >= 255 || count > 256 || index + count > 256) + 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; +} + +static void +genfb_restore_palette(struct genfb_softc *sc) +{ + int i; + + for (i = 0; i < 256; i++) { + genfb_putpalreg(sc, i, sc->sc_cmap_red[i], + sc->sc_cmap_green[i], sc->sc_cmap_blue[i]); + } +} + +static int +genfb_putpalreg(struct genfb_softc *sc, uint8_t idx, uint8_t r, uint8_t g, + uint8_t b) +{ + + return 0; +} + diff --git a/sys/dev/wsfb/genfbvar.h b/sys/dev/wsfb/genfbvar.h new file mode 100644 index 000000000000..e02b978f54a5 --- /dev/null +++ b/sys/dev/wsfb/genfbvar.h @@ -0,0 +1,73 @@ +/* $NetBSD: genfbvar.h,v 1.1 2007/04/07 03:41:26 macallan Exp $ */ + +/*- + * Copyright (c) 2007 Michael Lorenz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: genfbvar.h,v 1.1 2007/04/07 03:41:26 macallan Exp $"); + +#ifndef GENFBVAR_H +#define GENFBVAR_H + +#include +#include +#include +#include + +#include +#include +#include + +#include + +struct genfb_ops { + int (*genfb_ioctl)(void *, void *, u_long, void *, int, struct lwp *); + paddr_t (*genfb_mmap)(void *, void *, off_t, int); +}; + +struct genfb_softc { + struct device sc_dev; + struct vcons_data vd; + struct genfb_ops sc_ops; + struct vcons_screen sc_console_screen; + struct wsscreen_descr sc_defaultscreen_descr; + const struct wsscreen_descr *sc_screens[1]; + struct wsscreen_list sc_screenlist; + paddr_t sc_fbaddr; + int sc_width, sc_height, sc_stride, sc_depth; + size_t sc_fbsize; + int sc_mode; + u_char sc_cmap_red[256]; + u_char sc_cmap_green[256]; + u_char sc_cmap_blue[256]; +}; + +int genfb_attach(struct genfb_softc *, struct genfb_ops *); + +#endif /* GENFBVAR_H */ diff --git a/sys/dev/wsfb/pci_genfb.c b/sys/dev/wsfb/pci_genfb.c new file mode 100644 index 000000000000..cbad1e06ba31 --- /dev/null +++ b/sys/dev/wsfb/pci_genfb.c @@ -0,0 +1,186 @@ +/* $NetBSD: pci_genfb.c,v 1.1 2007/04/07 03:41:26 macallan Exp $ */ + +/*- + * Copyright (c) 2007 Michael Lorenz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: pci_genfb.c,v 1.1 2007/04/07 03:41:26 macallan Exp $"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "opt_wsfb.h" +#include "opt_genfb.h" + +struct range { + bus_addr_t offset; + bus_size_t size; + int flags; +}; + +struct pci_genfb_softc { + struct genfb_softc sc_gen; + + pci_chipset_tag_t sc_pc; + pcitag_t sc_pcitag; + bus_space_tag_t sc_memt; + bus_space_tag_t sc_iot; + struct range sc_ranges[8]; + int sc_ranges_used; +}; + +static int pci_genfb_match(struct device *, struct cfdata *, void *); +static void pci_genfb_attach(struct device *, struct device *, void *); +static int pci_genfb_ioctl(void *, void *, u_long, void *, int, + struct lwp *); +static paddr_t pci_genfb_mmap(void *, void *, off_t, int); + +CFATTACH_DECL(pci_genfb, sizeof(struct pci_genfb_softc), + pci_genfb_match, pci_genfb_attach, NULL, NULL); + +static int +pci_genfb_match(struct device *parent, struct cfdata *match, void *aux) +{ + struct pci_attach_args *pa = aux; + + if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_APPLE && + PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_CONTROL) + return 1; + + if (PCI_CLASS(pa->pa_class) == PCI_CLASS_DISPLAY) + return 1; + + return 0; +} + +static void +pci_genfb_attach(struct device *parent, struct device *self, void *aux) +{ + struct pci_genfb_softc *sc = (struct pci_genfb_softc *)self; + struct pci_attach_args *pa = aux; + struct genfb_ops ops; + int idx, bar, type; + char devinfo[256]; + + pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo, sizeof(devinfo)); + printf(": %s\n", devinfo); + printf(prop_dictionary_externalize(device_properties(self))); + + sc->sc_memt = pa->pa_memt; + sc->sc_iot = pa->pa_iot; + sc->sc_pc = pa->pa_pc; + sc->sc_pcitag = pa->pa_tag; + + /* mmap()able bus ranges */ + idx = 0; + bar = 0x10; + while (bar < 0x30) { + + type = pci_mapreg_type(sc->sc_pc, sc->sc_pcitag, bar); + if ((type == PCI_MAPREG_TYPE_MEM) || + (type == PCI_MAPREG_TYPE_ROM)) { + + pci_mapreg_info(sc->sc_pc, sc->sc_pcitag, bar, type, + &sc->sc_ranges[idx].offset, + &sc->sc_ranges[idx].size, + &sc->sc_ranges[idx].flags); + idx++; + } + bar += 4; + } + sc->sc_ranges_used = idx; + + ops.genfb_ioctl = pci_genfb_ioctl; + ops.genfb_mmap = pci_genfb_mmap; + + genfb_attach(&sc->sc_gen, &ops); +} + +static int +pci_genfb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, + struct lwp *l) +{ + struct pci_genfb_softc *sc = v; + + switch (cmd) { + case WSDISPLAYIO_GTYPE: + *(u_int *)data = WSDISPLAY_TYPE_PCIMISC; + return 0; + + /* PCI config read/write passthrough. */ + case PCI_IOC_CFGREAD: + case PCI_IOC_CFGWRITE: + return (pci_devioctl(sc->sc_pc, sc->sc_pcitag, + cmd, data, flag, l)); + } + + return EPASSTHROUGH; +} + +static paddr_t +pci_genfb_mmap(void *v, void *vs, off_t offset, int prot) +{ + struct pci_genfb_softc *sc = v; + struct range *r; + int i; + +#ifdef macppc + /* 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); + } +#endif + + /* allow to mmap() our BARs */ + for (i = 0; i < sc->sc_ranges_used; i++) { + + r = &sc->sc_ranges[i]; + if ((offset >= r->offset) && (offset < (r->offset + r->size))) { + return bus_space_mmap(sc->sc_memt, offset, 0, prot, + r->flags); + } + } + + return -1; +}