From 8dfb7255afea9c0617ae865387b40fb4cd8551c7 Mon Sep 17 00:00:00 2001 From: bouyer Date: Sun, 26 Jan 2014 21:22:49 +0000 Subject: [PATCH] Complete WSDISPLAYIO_SMODE/WSDISPLAYIO_GMODE support. In sisfb_mmap(), allow mapping the framebuffer and mmio and io registers when in WSDISPLAYIO_MODE_MAPPED mode. This can be used by X11. --- sys/dev/pci/sisfb.c | 119 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 93 insertions(+), 26 deletions(-) diff --git a/sys/dev/pci/sisfb.c b/sys/dev/pci/sisfb.c index fa91d5136254..6906eecdef4c 100644 --- a/sys/dev/pci/sisfb.c +++ b/sys/dev/pci/sisfb.c @@ -24,12 +24,13 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: sisfb.c,v 1.4 2014/01/24 12:11:40 bouyer Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sisfb.c,v 1.5 2014/01/26 21:22:49 bouyer Exp $"); #include #include #include #include +#include #include @@ -66,9 +67,13 @@ struct sisfb { bus_space_tag_t mmiot; bus_space_handle_t mmioh; + bus_addr_t mmiobase; + bus_size_t mmiosize; bus_space_tag_t iot; bus_space_handle_t ioh; + bus_addr_t iobase; + bus_size_t iosize; struct vcons_screen vcs; struct wsscreen_descr wsd; @@ -225,7 +230,6 @@ sisfb_attach(device_t parent, device_t self, void *aux) struct pci_attach_args *pa = (struct pci_attach_args *)aux; struct rasops_info *ri; struct wsemuldisplaydev_attach_args waa; - bus_size_t mmiosize, iosize; struct sisfb *fb; int console; unsigned long defattr; @@ -258,14 +262,15 @@ sisfb_attach(device_t parent, device_t self, void *aux) return; } - if (pci_mapreg_map(pa, PCI_MAPREG_START + 4, PCI_MAPREG_TYPE_MEM, - 0, &fb->mmiot, &fb->mmioh, NULL, &mmiosize) != 0) { + if (pci_mapreg_map(pa, PCI_MAPREG_START + 4, + PCI_MAPREG_TYPE_MEM, 0, + &fb->mmiot, &fb->mmioh, &fb->mmiobase, &fb->mmiosize) != 0) { aprint_error_dev(self, ": can't map mmio area\n"); goto fail1; } if (pci_mapreg_map(pa, PCI_MAPREG_START + 8, PCI_MAPREG_TYPE_IO, - 0, &fb->iot, &fb->ioh, NULL, &iosize) != 0) { + 0, &fb->iot, &fb->ioh, &fb->iobase, &fb->iosize) != 0) { aprint_error_dev(self, ": can't map registers\n"); goto fail2; } @@ -278,7 +283,15 @@ sisfb_attach(device_t parent, device_t self, void *aux) } aprint_normal_dev(self, ": %dx%dx%d frame buffer\n", - fb->vcs.scr_ri.ri_width, fb->vcs.scr_ri.ri_height, fb->vcs.scr_ri.ri_depth); + fb->vcs.scr_ri.ri_width, fb->vcs.scr_ri.ri_height, + fb->vcs.scr_ri.ri_depth); + + aprint_debug_dev(self, ": fb 0x%" PRIxBUSSIZE "@0x%" PRIxBUSADDR + ", mmio 0x%" PRIxBUSSIZE "@0x%" PRIxBUSADDR + ", io 0x%" PRIxBUSSIZE "@0x%" PRIxBUSADDR "\n", + fb->fbsize, fb->fbbase, + fb->mmiosize, fb->mmiobase, + fb->iosize, fb->iobase); fb->wsd = (struct wsscreen_descr){ "default", @@ -323,9 +336,9 @@ sisfb_attach(device_t parent, device_t self, void *aux) return; fail3: - bus_space_unmap(fb->iot, fb->ioh, iosize); + bus_space_unmap(fb->iot, fb->ioh, fb->iosize); fail2: - bus_space_unmap(fb->mmiot, fb->mmioh, mmiosize); + bus_space_unmap(fb->mmiot, fb->mmioh, fb->mmiosize); fail1: bus_space_unmap(fb->fbt, fb->fbh, fb->fbsize); } @@ -402,7 +415,26 @@ sisfb_ioctl(void *v, void *vs, u_long cmd, void *data, int flags, sisfb_loadcmap(fb, cm->index, cm->count); return 0; case WSDISPLAYIO_SMODE: - /* XXX */ return 0; + sc->sc_mode = *(uint *)data; + aprint_debug_dev(sc->sc_dev, ": switching to "); + switch(sc->sc_mode) { + case WSDISPLAYIO_MODE_EMUL: + aprint_debug("WSDISPLAYIO_MODE_EMUL\n"); + break; + case WSDISPLAYIO_MODE_MAPPED: + aprint_debug("WSDISPLAYIO_MODE_MAPPED\n"); + break; + case WSDISPLAYIO_MODE_DUMBFB: + aprint_debug("WSDISPLAYIO_MODE_DUMBFB\n"); + break; + default: + aprint_debug("unknown mode %d\n", sc->sc_mode); + return EINVAL; + } + return 0; + case WSDISPLAYIO_GMODE: + *(uint *)data = sc->sc_mode; + return 0; case PCI_IOC_CFGREAD: case PCI_IOC_CFGWRITE: return pci_devioctl(sc->sc_pc, sc->sc_pt, cmd, data, flags, l); @@ -431,9 +463,35 @@ sisfb_mmap(void *v, void *vs, off_t offset, int prot) (uintptr_t)bus_space_vaddr(fb->fbt, fb->fbh) - (uintptr_t)fb->fb_addr; paddr_t pa; - if (offset >= 0 && offset < ri->ri_stride * ri->ri_height) { - pa = bus_space_mmap(fb->fbt, fb->fbbase, fb_offset + offset, - prot, BUS_SPACE_MAP_LINEAR); + if (sc->sc_mode != WSDISPLAYIO_MODE_MAPPED) { + if (offset >= 0 && offset < ri->ri_stride * ri->ri_height) { + pa = bus_space_mmap(fb->fbt, + fb->fbbase, fb_offset + offset, + prot, BUS_SPACE_MAP_LINEAR); + return pa; + } + return -1; + } + if (kauth_authorize_generic(kauth_cred_get(), KAUTH_GENERIC_ISSUSER, + NULL) != 0) { + return -1; + } + if (offset >= (fb->fbbase & ~PAGE_MASK) && + offset <= ((fb->fbbase + fb->fbsize + PAGE_SIZE - 1) & ~PAGE_MASK)) { + pa = bus_space_mmap(fb->fbt, fb->fbbase, offset - fb->fbbase, + prot, BUS_SPACE_MAP_LINEAR|BUS_SPACE_MAP_PREFETCHABLE); + return pa; + } + if (offset >= (fb->mmiobase & ~PAGE_MASK) && + offset <= ((fb->mmiobase + fb->mmiosize + PAGE_SIZE - 1) & ~PAGE_MASK)) { + pa = bus_space_mmap(fb->mmiot, fb->mmiobase, offset - fb->mmiobase, + prot, BUS_SPACE_MAP_LINEAR); + return pa; + } + if (offset >= (fb->iobase & ~PAGE_MASK) && + offset <= ((fb->iobase + fb->iosize + PAGE_SIZE - 1) & ~PAGE_MASK)) { + pa = bus_space_mmap(fb->iot, fb->iobase, offset - fb->iobase, + prot, BUS_SPACE_MAP_LINEAR); return pa; } return -1; @@ -705,10 +763,9 @@ sisfb_cnattach(bus_space_tag_t memt, bus_space_tag_t iot, { long defattr; struct rasops_info * const ri = &sisfbcn.vcs.scr_ri; - pcireg_t bar; + int flags; int rc; - /* filter out unrecognized devices */ switch (id) { default: @@ -717,11 +774,15 @@ sisfb_cnattach(bus_space_tag_t memt, bus_space_tag_t iot, break; } - bar = pci_conf_read(pc, tag, PCI_MAPREG_START); - if (PCI_MAPREG_TYPE(bar) != PCI_MAPREG_TYPE_MEM) - return EINVAL; + if (pci_mapreg_info(pc, tag, PCI_MAPREG_START, + PCI_MAPREG_TYPE_MEM, + &sisfbcn.fbbase, &sisfbcn.fbsize, &flags)) { + printf("sisfb can't map frame buffer\n"); + return ENODEV; + } + sisfbcn.fbt = memt; - rc = bus_space_map(memt, PCI_MAPREG_MEM_ADDR(bar), 1 /* XXX */, + rc = bus_space_map(memt, sisfbcn.fbbase, sisfbcn.fbsize, BUS_SPACE_MAP_LINEAR, &sisfbcn.fbh); #ifdef SIS_DEBUG printf("sisfb_cnattach(memt, 0x%x rc %d\n", PCI_MAPREG_MEM_ADDR(bar), rc); @@ -729,11 +790,14 @@ sisfb_cnattach(bus_space_tag_t memt, bus_space_tag_t iot, if (rc != 0) return rc; - bar = pci_conf_read(pc, tag, PCI_MAPREG_START + 4); - if (PCI_MAPREG_TYPE(bar) != PCI_MAPREG_TYPE_MEM) - return EINVAL; + if (pci_mapreg_info(pc, tag, PCI_MAPREG_START + 4, + PCI_MAPREG_TYPE_MEM, + &sisfbcn.mmiobase, &sisfbcn.mmiosize, &flags)) { + printf("sisfb can't map mem space\n"); + return ENODEV; + } sisfbcn.mmiot = memt; - rc = bus_space_map(memt, PCI_MAPREG_MEM_ADDR(bar), 1 /* XXX */, + rc = bus_space_map(memt, sisfbcn.mmiobase, sisfbcn.mmiosize, BUS_SPACE_MAP_LINEAR, &sisfbcn.mmioh); #ifdef SIS_DEBUG printf("sisfb_cnattach(memt2, 0x%x rc %d\n", PCI_MAPREG_MEM_ADDR(bar), rc); @@ -741,11 +805,14 @@ sisfb_cnattach(bus_space_tag_t memt, bus_space_tag_t iot, if (rc != 0) return rc; - bar = pci_conf_read(pc, tag, PCI_MAPREG_START + 8); - if (PCI_MAPREG_TYPE(bar) != PCI_MAPREG_TYPE_IO) - return EINVAL; + if (pci_mapreg_info(pc, tag, PCI_MAPREG_START + 8, + PCI_MAPREG_TYPE_IO, + &sisfbcn.iobase, &sisfbcn.iosize, &flags)) { + printf("sisfb can't map mem space\n"); + return ENODEV; + } sisfbcn.iot = iot; - rc = bus_space_map(iot, PCI_MAPREG_MEM_ADDR(bar), 1 /* XXX */, + rc = bus_space_map(iot, sisfbcn.iobase, sisfbcn.iosize, 0, &sisfbcn.ioh); #ifdef SIS_DEBUG printf("sisfb_cnattach(iot, 0x%x rc %d\n", PCI_MAPREG_MEM_ADDR(bar), rc);