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 <adaplas@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Ilya Yanok 2007-10-16 01:29:17 -07:00 committed by Linus Torvalds
parent 1ddc28d7e7
commit 68e5e9d734

View File

@ -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;