On Tue, Jul 31, 2018 at 03:05:11PM +0200, Mark Kettenis wrote:
> You might want to look at what the udl(4) driver does.  The kernel
> driver lives in sys/dev/usb/udl.c and implements a "damage" ioctl that
> updates a region of the actual framebuffer from the virtual
> framebuffer that lives in physical memory.  X supposedly keeps track
> of the "damage" and the xf86-video-wsudl driver uses that to transfer
> the appropriate pixels.  Maybe this mechanism could be generalized by
> implementing a wscons ioctl?
> 
> Your approach is a bit wasteful since you're doing work even when the
> display is completely static.  Another problem is that your timeout
> might run in the middle of an update of the virtual framebuffer.
> 
> Not sure how this would work with graphics stuff that doesn't go
> through X though.  Something that just draws into a mmap'ed virtual
> framebuffer and issues ioctls should work though.

That is very helpful indeed.  I have come up with a quick diff to test
it, and it makes X work rather smooth on that SPI-connected OLED.  I'm
rather surprised.

I guess I will have to come up with a diff to try and make this DAMAGE
ioctl more generic.

Patrick

diff --git a/sys/dev/fdt/ssdfb.c b/sys/dev/fdt/ssdfb.c
index 4c774855147..ea5e213076f 100644
--- a/sys/dev/fdt/ssdfb.c
+++ b/sys/dev/fdt/ssdfb.c
@@ -24,7 +24,10 @@
 #include <sys/timeout.h>
 #include <sys/task.h>
 
+#include <uvm/uvm_extern.h>
+
 #include <dev/spi/spivar.h>
+#include <dev/usb/udlio.h>
 
 #include <dev/ofw/openfirm.h>
 #include <dev/ofw/ofw_gpio.h>
@@ -72,6 +75,7 @@ struct ssdfb_softc {
        uint8_t                 *sc_fb;
        size_t                   sc_fbsize;
        struct rasops_info       sc_rinfo;
+       int                      sc_mode;
 
        uint8_t                  sc_column_range[2];
        uint8_t                  sc_page_range[2];
@@ -200,7 +204,8 @@ ssdfb_attach(struct device *parent, struct device *self, 
void *aux)
        sc->sc_fb = malloc(sc->sc_fbsize, M_DEVBUF, M_WAITOK | M_ZERO);
 
        ri = &sc->sc_rinfo;
-       ri->ri_bits = malloc(sc->sc_fbsize, M_DEVBUF, M_WAITOK | M_ZERO);
+       ri->ri_bits = malloc(roundup(sc->sc_fbsize, PAGE_SIZE),
+           M_DEVBUF, M_WAITOK | M_ZERO);
        ri->ri_bs = ssdfb_bs;
        ri->ri_flg = RI_CLEAR | RI_VCONS;
        ri->ri_depth = 1;
@@ -240,7 +245,7 @@ ssdfb_detach(struct device *self, int flags)
        struct rasops_info *ri = &sc->sc_rinfo;
        timeout_del(&sc->sc_to);
        task_del(systq, &sc->sc_task);
-       free(ri->ri_bits, M_DEVBUF, sc->sc_fbsize);
+       free(ri->ri_bits, M_DEVBUF, roundup(sc->sc_fbsize, PAGE_SIZE));
        free(sc->sc_fb, M_DEVBUF, sc->sc_fbsize);
        free(sc->sc_gpio, M_DEVBUF, sc->sc_gpiolen);
        return 0;
@@ -417,13 +422,15 @@ ssdfb_ioctl(void *v, u_long cmd, caddr_t data, int flag, 
struct proc *p)
        struct ssdfb_softc      *sc = v;
        struct rasops_info      *ri = &sc->sc_rinfo;
        struct wsdisplay_fbinfo *wdf;
+       struct udl_ioctl_damage *d;
+       int                      mode;
 
        switch (cmd) {
        case WSDISPLAYIO_GETPARAM:
        case WSDISPLAYIO_SETPARAM:
                return (-1);
        case WSDISPLAYIO_GTYPE:
-               *(u_int *)data = WSDISPLAY_TYPE_UNKNOWN;
+               *(u_int *)data = WSDISPLAY_TYPE_DL;
                break;
        case WSDISPLAYIO_GINFO:
                wdf = (struct wsdisplay_fbinfo *)data;
@@ -436,10 +443,38 @@ ssdfb_ioctl(void *v, u_long cmd, caddr_t data, int flag, 
struct proc *p)
                *(u_int *)data = ri->ri_stride;
                break;
        case WSDISPLAYIO_SMODE:
+               mode = *(u_int *)data;
+               switch (mode) {
+               case WSDISPLAYIO_MODE_EMUL:
+                       if (sc->sc_mode != WSDISPLAYIO_MODE_EMUL) {
+                               memset(ri->ri_bits, 0, roundup(sc->sc_fbsize,
+                                   PAGE_SIZE));
+                               ssdfb_update(sc);
+                               sc->sc_mode = mode;
+                       }
+                       break;
+               case WSDISPLAYIO_MODE_DUMBFB:
+                       if (sc->sc_mode != WSDISPLAYIO_MODE_DUMBFB) {
+                               memset(ri->ri_bits, 0, roundup(sc->sc_fbsize,
+                                   PAGE_SIZE));
+                               timeout_del(&sc->sc_to);
+                               task_del(systq, &sc->sc_task);
+                               sc->sc_mode = mode;
+                       }
+                       break;
+               case WSDISPLAYIO_MODE_MAPPED:
+               default:
+                       return (-1);
+               }
                break;
        case WSDISPLAYIO_GETSUPPORTEDDEPTH:
                *(u_int *)data = WSDISPLAYIO_DEPTH_1;
                break;
+       case UDLIO_DAMAGE:
+               d = (struct udl_ioctl_damage *)data;
+               d->status = UDLIO_STATUS_OK;
+               ssdfb_partial(sc, d->x1, d->x2, d->y1, d->y2);
+               break;
        default:
                return (-1);
        }
@@ -450,7 +485,17 @@ ssdfb_ioctl(void *v, u_long cmd, caddr_t data, int flag, 
struct proc *p)
 paddr_t
 ssdfb_mmap(void *v, off_t off, int prot)
 {
-       return -1;
+       struct ssdfb_softc      *sc = v;
+       struct rasops_info      *ri = &sc->sc_rinfo;
+       paddr_t                  pa;
+
+       if (off >= sc->sc_fbsize || off < 0)
+               return (-1);
+
+       if (!pmap_extract(pmap_kernel(), (vaddr_t)ri->ri_bits, &pa))
+               return (-1);
+
+       return (pa + off);
 }
 
 int

Reply via email to