From 68e5e9d734503695915734e50e9427624cf8f3b2 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Tue, 16 Oct 2007 01:29:17 -0700 Subject: vfb: make virtual framebuffer mmapable Changed things: 1. vmalloc()/vfree() replaced with rvmalloc()/rvfree() (taken from drivers/media/video/se401.c) 2. mmap method implemented (mostly taken from drivers/media/video/se401.c) 3. smem_start and smem_len fields of struct fb_fix_screeninfo initialized. (smem_start initialized with virtual address, don't know if it is really bad...) [adaplas: sparse warning fix] Signed-off-by: Antonino Daplas Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/vfb.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 74 insertions(+), 4 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/vfb.c b/drivers/video/vfb.c index 02cfc6a..072638a 100644 --- a/drivers/video/vfb.c +++ b/drivers/video/vfb.c @@ -37,6 +37,48 @@ static void *videomemory; static u_long videomemorysize = VIDEOMEMSIZE; module_param(videomemorysize, ulong, 0); +/********************************************************************** + * + * Memory management + * + **********************************************************************/ +static void *rvmalloc(unsigned long size) +{ + void *mem; + unsigned long adr; + + size = PAGE_ALIGN(size); + mem = vmalloc_32(size); + if (!mem) + return NULL; + + memset(mem, 0, size); /* Clear the ram out, no junk to the user */ + adr = (unsigned long) mem; + while (size > 0) { + SetPageReserved(vmalloc_to_page((void *)adr)); + adr += PAGE_SIZE; + size -= PAGE_SIZE; + } + + return mem; +} + +static void rvfree(void *mem, unsigned long size) +{ + unsigned long adr; + + if (!mem) + return; + + adr = (unsigned long) mem; + while ((long) size > 0) { + ClearPageReserved(vmalloc_to_page((void *)adr)); + adr += PAGE_SIZE; + size -= PAGE_SIZE; + } + vfree(mem); +} + static struct fb_var_screeninfo vfb_default __initdata = { .xres = 640, .yres = 480, @@ -371,7 +413,33 @@ static int vfb_pan_display(struct fb_var_screeninfo *var, static int vfb_mmap(struct fb_info *info, struct vm_area_struct *vma) { - return -EINVAL; + unsigned long start = vma->vm_start; + unsigned long size = vma->vm_end - vma->vm_start; + unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; + unsigned long page, pos; + + if (offset + size > info->fix.smem_len) { + return -EINVAL; + } + + pos = (unsigned long)info->fix.smem_start + offset; + + while (size > 0) { + page = vmalloc_to_pfn((void *)pos); + if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { + return -EAGAIN; + } + start += PAGE_SIZE; + pos += PAGE_SIZE; + if (size > PAGE_SIZE) + size -= PAGE_SIZE; + else + size = 0; + } + + vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */ + return 0; + } #ifndef MODULE @@ -406,7 +474,7 @@ static int __init vfb_probe(struct platform_device *dev) /* * For real video cards we use ioremap. */ - if (!(videomemory = vmalloc(videomemorysize))) + if (!(videomemory = rvmalloc(videomemorysize))) return retval; /* @@ -429,6 +497,8 @@ static int __init vfb_probe(struct platform_device *dev) if (!retval || (retval == 4)) info->var = vfb_default; + vfb_fix.smem_start = (unsigned long) videomemory; + vfb_fix.smem_len = videomemorysize; info->fix = vfb_fix; info->pseudo_palette = info->par; info->par = NULL; @@ -452,7 +522,7 @@ err2: err1: framebuffer_release(info); err: - vfree(videomemory); + rvfree(videomemory, videomemorysize); return retval; } @@ -462,7 +532,7 @@ static int vfb_remove(struct platform_device *dev) if (info) { unregister_framebuffer(info); - vfree(videomemory); + rvfree(videomemory, videomemorysize); framebuffer_release(info); } return 0; -- cgit v1.1