Module Name: src Committed By: jmcneill Date: Fri Dec 30 19:32:32 UTC 2011
Modified Files: src/sys/arch/usermode/dev: vncfb.c Log Message: add mmap support To generate a diff of this commit: cvs rdiff -u -r1.8 -r1.9 src/sys/arch/usermode/dev/vncfb.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/usermode/dev/vncfb.c diff -u src/sys/arch/usermode/dev/vncfb.c:1.8 src/sys/arch/usermode/dev/vncfb.c:1.9 --- src/sys/arch/usermode/dev/vncfb.c:1.8 Fri Dec 30 14:22:41 2011 +++ src/sys/arch/usermode/dev/vncfb.c Fri Dec 30 19:32:32 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: vncfb.c,v 1.8 2011/12/30 14:22:41 jmcneill Exp $ */ +/* $NetBSD: vncfb.c,v 1.9 2011/12/30 19:32:32 jmcneill Exp $ */ /*- * Copyright (c) 2011 Jared D. McNeill <jmcne...@invisible.ca> @@ -35,7 +35,7 @@ #include "opt_wsemul.h" #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: vncfb.c,v 1.8 2011/12/30 14:22:41 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: vncfb.c,v 1.9 2011/12/30 19:32:32 jmcneill Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -43,6 +43,8 @@ __KERNEL_RCSID(0, "$NetBSD: vncfb.c,v 1. #include <sys/device.h> #include <sys/kmem.h> +#include <uvm/uvm_extern.h> + #include <dev/wscons/wsconsio.h> #include <dev/wscons/wsdisplayvar.h> @@ -57,6 +59,8 @@ __KERNEL_RCSID(0, "$NetBSD: vncfb.c,v 1. #include <machine/mainbus.h> #include <machine/thunk.h> +#define VNCFB_REFRESH_INTERVAL 33 /* fb refresh interval when mapped */ + struct vncfb_fbops { void (*copycols)(void *, int, int, int, int); void (*erasecols)(void *, int, int, int, long); @@ -74,7 +78,10 @@ struct vncfb_softc { unsigned int sc_height; unsigned int sc_depth; int sc_mode; + uint8_t * sc_mem; + size_t sc_memsize; uint8_t * sc_framebuf; + size_t sc_framebufsize; struct vcons_data sc_vd; struct vncfb_fbops sc_ops; @@ -82,6 +89,9 @@ struct vncfb_softc { void *sc_ih; void *sc_sih; + + callout_t sc_callout; + void *sc_refresh_sih; }; static int vncfb_match(device_t, cfdata_t, void *); @@ -107,6 +117,8 @@ static void vncfb_copyrect(struct vncfb_ static void vncfb_fillrect(struct vncfb_softc *, int, int, int, int, uint32_t); static int vncfb_intr(void *); static void vncfb_softintr(void *); +static void vncfb_refresh(void *); +static void vncfb_softrefresh(void *); static int vncfb_kbd_enable(void *, int); static void vncfb_kbd_set_leds(void *, int); @@ -187,13 +199,17 @@ vncfb_attach(device_t parent, device_t s panic("couldn't open VNC socket"); #endif - sc->sc_framebuf = kmem_zalloc(sc->sc_width * sc->sc_height * - (sc->sc_depth / 8), KM_SLEEP); - KASSERT(sc->sc_framebuf != NULL); + sc->sc_framebufsize = sc->sc_width * sc->sc_height * (sc->sc_depth / 8); + sc->sc_memsize = sc->sc_framebufsize + PAGE_SIZE; + + sc->sc_mem = kmem_zalloc(sc->sc_memsize, KM_SLEEP); + sc->sc_framebuf = (void *)round_page((vaddr_t)sc->sc_mem); aprint_naive("\n"); aprint_normal(": %ux%u %ubpp (port %u)\n", sc->sc_width, sc->sc_height, sc->sc_depth, taa->u.vnc.port); + aprint_normal_dev(self, "mem @ %p\n", sc->sc_mem); + aprint_normal_dev(self, "fb @ %p\n", sc->sc_framebuf); sc->sc_rfb.width = sc->sc_width; sc->sc_rfb.height = sc->sc_height; @@ -210,6 +226,12 @@ vncfb_attach(device_t parent, device_t s sc->sc_sih = softint_establish(SOFTINT_SERIAL, vncfb_softintr, sc); sc->sc_ih = sigio_intr_establish(vncfb_intr, sc); + sc->sc_refresh_sih = softint_establish(SOFTINT_SERIAL, + vncfb_softrefresh, sc); + + callout_init(&sc->sc_callout, 0); + callout_setfunc(&sc->sc_callout, vncfb_refresh, sc); + vcons_init(&sc->sc_vd, sc, &vncfb_defaultscreen, &vncfb_accessops); sc->sc_vd.init_screen = vncfb_init_screen; @@ -438,12 +460,19 @@ vncfb_ioctl(void *v, void *vs, u_long cm wdf->depth = ms->scr_ri.ri_depth; wdf->cmsize = 256; return 0; + case WSDISPLAYIO_LINEBYTES: + *(u_int *)data = sc->sc_width * (sc->sc_depth / 8); + return 0; case WSDISPLAYIO_SMODE: new_mode = *(int *)data; if (sc->sc_mode != new_mode) { sc->sc_mode = new_mode; - if (new_mode == WSDISPLAYIO_MODE_EMUL) + if (new_mode == WSDISPLAYIO_MODE_EMUL) { + callout_halt(&sc->sc_callout, NULL); vcons_redraw_screen(ms); + } else { + callout_schedule(&sc->sc_callout, 1); + } } return 0; default: @@ -454,8 +483,26 @@ vncfb_ioctl(void *v, void *vs, u_long cm static paddr_t vncfb_mmap(void *v, void *vs, off_t offset, int prot) { - /* TODO */ - return -1; + struct vcons_data *vd = v; + struct vncfb_softc *sc = vd->cookie; + paddr_t pa; + vaddr_t va; + + if (offset < 0 || offset + PAGE_SIZE > sc->sc_framebufsize) { + device_printf(sc->sc_dev, "mmap: offset 0x%x, fbsize 0x%x" + " out of range!\n", + (unsigned int)offset, (unsigned int)sc->sc_framebufsize); + return -1; + } + + va = trunc_page((vaddr_t)sc->sc_framebuf + offset); + + if (pmap_extract(pmap_kernel(), va, &pa) == false) { + device_printf(sc->sc_dev, "mmap: pmap_extract failed!\n"); + return -1; + } + + return atop(pa); } static void @@ -514,6 +561,32 @@ vncfb_softintr(void *priv) } } +static void +vncfb_refresh(void *priv) +{ + struct vncfb_softc *sc = priv; + + softint_schedule(sc->sc_refresh_sih); +} + +static void +vncfb_softrefresh(void *priv) +{ + struct vncfb_softc *sc = priv; + + if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) + return; + + /* update the screen */ + vncfb_update(sc, 0, 0, sc->sc_width, sc->sc_height); + + /* flush the pending drawing op */ + while (thunk_rfb_poll(&sc->sc_rfb, NULL) > 0) + ; + + callout_schedule(&sc->sc_callout, mstohz(VNCFB_REFRESH_INTERVAL)); +} + static int vncfb_kbd_enable(void *priv, int on) {