From faa12b6a6158e9bc530916669fd9dd3544c7fe53 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Sat, 11 Aug 2012 11:32:55 +0200 Subject: [PATCH] uterm: fbdev: add udlfb workaround udlfb incorrectly reports framebuffer sizes. That is, if we request a framebuffer twice the size as the real framebuffer for double-bufferring, it will accept these values and report success. We can even map this virtual framebuffer successfully! However, the memory that is internally allocated is only the real smaller framebuffer and we will get segfaults. This might even leak internal kernel memory so we should fix this on kernel-side as soon as possible. Signed-off-by: David Herrmann --- src/uterm_video_fbdev.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/uterm_video_fbdev.c b/src/uterm_video_fbdev.c index d7068ac..d784330 100644 --- a/src/uterm_video_fbdev.c +++ b/src/uterm_video_fbdev.c @@ -116,6 +116,17 @@ static int display_activate_force(struct uterm_display *disp, log_info("activating display %s to %ux%u %u bpp", disp->fbdev.node, vinfo->xres, vinfo->yres, vinfo->bits_per_pixel); + disp->flags |= DISPLAY_DBUF; + + /* udlfb is broken as it reports the sizes of the virtual framebuffer + * (even mmap() accepts it) but the actual size that we can access + * without segfaults is the _real_ framebuffer. Therefore, disable + * double-buffering for it. + * TODO: fix this kernel-side! */ + if (!strcmp(finfo->id, "udlfb")) { + disp->flags &= ~DISPLAY_DBUF; + vinfo->yres_virtual = vinfo->yres; + } ret = ioctl(disp->fbdev.fd, FBIOPUT_VSCREENINFO, vinfo); if (ret) { @@ -123,16 +134,16 @@ static int display_activate_force(struct uterm_display *disp, vinfo->yres_virtual = vinfo->yres; ret = ioctl(disp->fbdev.fd, FBIOPUT_VSCREENINFO, vinfo); if (ret) { - log_err("cannot set vinfo (%d): %m", - errno); + log_debug("cannot reset fb offsets (%d): %m", errno); return -EFAULT; } - log_debug("disabling double buffering"); - } else { - disp->flags |= DISPLAY_DBUF; - log_debug("enabling double buffering"); } + if (disp->flags & DISPLAY_DBUF) + log_debug("enabling double buffering"); + else + log_debug("disabling double buffering"); + ret = refresh_info(disp); if (ret) return ret;