Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/roland...
[pandora-kernel.git] / drivers / video / vfb.c
index d073ffb..93fe08d 100644 (file)
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/mm.h>
-#include <linux/tty.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 
-#include <asm/uaccess.h>
 #include <linux/fb.h>
 #include <linux/init.h>
 
@@ -39,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,
@@ -85,13 +125,15 @@ static int vfb_mmap(struct fb_info *info,
                    struct vm_area_struct *vma);
 
 static struct fb_ops vfb_ops = {
+       .fb_read        = fb_sys_read,
+       .fb_write       = fb_sys_write,
        .fb_check_var   = vfb_check_var,
        .fb_set_par     = vfb_set_par,
        .fb_setcolreg   = vfb_setcolreg,
        .fb_pan_display = vfb_pan_display,
-       .fb_fillrect    = cfb_fillrect,
-       .fb_copyarea    = cfb_copyarea,
-       .fb_imageblit   = cfb_imageblit,
+       .fb_fillrect    = sys_fillrect,
+       .fb_copyarea    = sys_copyarea,
+       .fb_imageblit   = sys_imageblit,
        .fb_mmap        = vfb_mmap,
 };
 
@@ -371,23 +413,59 @@ 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
+/*
+ * The virtual framebuffer driver is only enabled if explicitly
+ * requested by passing 'video=vfb:' (or any actual options).
+ */
 static int __init vfb_setup(char *options)
 {
        char *this_opt;
 
+       vfb_enable = 0;
+
+       if (!options)
+               return 1;
+
        vfb_enable = 1;
 
-       if (!options || !*options)
+       if (!*options)
                return 1;
 
        while ((this_opt = strsep(&options, ",")) != NULL) {
                if (!*this_opt)
                        continue;
-               if (!strncmp(this_opt, "disable", 7))
+               /* Test disable for backwards compatibility */
+               if (!strcmp(this_opt, "disable"))
                        vfb_enable = 0;
        }
        return 1;
@@ -406,7 +484,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 +507,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 +532,7 @@ err2:
 err1:
        framebuffer_release(info);
 err:
-       vfree(videomemory);
+       rvfree(videomemory, videomemorysize);
        return retval;
 }
 
@@ -462,7 +542,7 @@ static int vfb_remove(struct platform_device *dev)
 
        if (info) {
                unregister_framebuffer(info);
-               vfree(videomemory);
+               rvfree(videomemory, videomemorysize);
                framebuffer_release(info);
        }
        return 0;