How to mmap multiple pages?
Oliver Zander <[email protected]> Mon, 08 Oct 2007 16:00:04 +0200
| Newsgroups | gmane.linux.fbdev.user |
|---|---|
| Organization | COMO - Computer & Motion GmbH |
| Message-ID | <1191852004.5793.29.camel@oliver-linux> |
Hi all,
I wrote a framebuffer driver for an Atmel AVR32 microcontroller with a
simple monochrome LCD wired to GPIO. The fb uses system RAM.
My problem is that I need 8 PAGES of mem (256*64*16 bpp) and cannot find
code which is able to mmap more than 1 PAGE.
Here's my code:
-------------------------------------------------------------------------------
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.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>
#include <linux/types.h>
#define MEM_SIZE (256*64*2)
#define SCREEN_SIZE (256*64*2)
#define LINE_LEN (256*2)
u8 *lm6800_buffer;
EXPORT_SYMBOL_GPL(lm6800_buffer);
static struct fb_var_screeninfo meinfb_var __initdata = {
.xres = 256,
.yres = 64,
.xres_virtual = 256,
.yres_virtual = 64,
.bits_per_pixel = 16,
.red = { 11,5, 0 },
.green = { 5, 6, 0 },
.blue = { 0, 5, 0 },
.left_margin = 0,
.right_margin = 0,
.upper_margin = 0,
.lower_margin = 0,
.vmode = FB_VMODE_NONINTERLACED,
};
static struct fb_fix_screeninfo meinfb_fix __initdata = {
.id = "LM6800 COLOR FB",
.type = FB_TYPE_PACKED_PIXELS,
.smem_len = MEM_SIZE,
.visual = FB_VISUAL_TRUECOLOR,
.xpanstep = 0,
.ypanstep = 0,
.ywrapstep = 0,
.line_length = LINE_LEN,
.accel = FB_ACCEL_NONE,
};
//do I need this at all?
static int meinfb_setcolreg(unsigned regno, unsigned red, unsigned
green,
unsigned blue, unsigned transp,
struct fb_info *info)
{
info->cmap = *fb_default_cmap(16);
return 0;
}
static int meinfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
{
return vm_insert_page(vma, vma->vm_start,
virt_to_page(lm6800_buffer));
}
static struct fb_ops meinfb_ops = {
.owner = THIS_MODULE,
.fb_read = fb_sys_read,
.fb_write = fb_sys_write,
.fb_setcolreg = meinfb_setcolreg,
.fb_fillrect = sys_fillrect,
.fb_copyarea = sys_copyarea,
.fb_imageblit = sys_imageblit,
.fb_mmap = meinfb_mmap,
};
static int __init meinfb_probe(struct platform_device *dev)
{
struct fb_info *info;
int retval = -ENOMEM;
// allocate in lcd driver?
// PAGE_SIZE is 4096 so I need 8 pages (256*64*2 / 4096 = 8)
if (!(lm6800_buffer = (u8 *) __get_free_pages(GFP_KERNEL, 3)))
return retval;
memset(lm6800_buffer, 0, MEM_SIZE);
info = framebuffer_alloc(0, &dev->dev);
if (!info)
goto err;
info->screen_base = (char __iomem *)lm6800_buffer;
info->screen_size = SCREEN_SIZE;
info->fbops = &meinfb_ops;
info->var = meinfb_var;
info->fix = meinfb_fix;
info->pseudo_palette = NULL;
info->par = NULL;
info->flags = FBINFO_FLAG_DEFAULT;
fb_alloc_cmap(&info->cmap, 16, 0);
info->cmap = *fb_default_cmap(16);
retval = register_framebuffer(info);
if (retval < 0)
goto err1;
platform_set_drvdata(dev, info);
return 0;
err1:
framebuffer_release(info);
err:
free_pages((unsigned long) lm6800_buffer, 3);
return retval;
}
static int meinfb_remove(struct platform_device *dev)
{
struct fb_info *info = platform_get_drvdata(dev);
if (info) {
unregister_framebuffer(info);
free_pages((unsigned long) lm6800_buffer, 3);
framebuffer_release(info);
}
return 0;
}
static struct platform_driver meinfb_driver = {
.probe = meinfb_probe,
.remove = meinfb_remove,
.driver = {
.name = "meinfb",
},
};
static struct platform_device *meinfb_device;
static int __init meinfb_init(void)
{
int ret = 0;
ret = platform_driver_register(&meinfb_driver);
if (!ret) {
meinfb_device = platform_device_alloc("meinfb", 0);
if (meinfb_device)
ret = platform_device_add(meinfb_device);
else
ret = -ENOMEM;
if (ret) {
platform_device_put(meinfb_device);
platform_driver_unregister(&meinfb_driver);
}
}
return ret;
}
static void __exit meinfb_exit(void)
{
platform_device_unregister(meinfb_device);
platform_driver_unregister(&meinfb_driver);
}
module_init(meinfb_init);
module_exit(meinfb_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Oliver Zander");
MODULE_DESCRIPTION("LM6800 framebuffer driver with color support");
-------------------------------------------------------------------------------
I'm very new to Linux and driver development so please be forgiving :)
TIA
O.Zander
-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems? Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >> http://get.splunk.com/