本文主要探讨210的framebuffer驱动知识。
frameBuffer
用户态进程直接调用显卡写屏,framebuffer接口是给用户态进程用于写屏
framebuffer设备文件为fbx
清屏:dd if=/dev/zero of=/dev/fbx
清屏:$ dd if=/dev/zero of=/dev/fb0 bs=1024 count=768
截屏:dd if=/dev/fb of=fbfile
fb.h
struct fb_var_screeninfo {
__u32 xres; /* visible resolution */
__u32 yres;
__u32 xres_virtual; /* virtual resolution */
__u32 yres_virtual;
__u32 xoffset; /* offset from virtual to visible */
__u32 yoffset; /* resolution */
__u32 bits_per_pixel; /* guess what */
__u32 grayscale; /* != 0 Graylevels instead of colors */
struct fb_bitfield red; /* bitfield in fb mem if true color, */
struct fb_bitfield green; /* else only length is significant */
struct fb_bitfield blue;
struct fb_bitfield transp; /* transparency */
__u32 nonstd; /* != 0 Non standard pixel format */
__u32 activate; /* see FB_ACTIVATE_* */
__u32 height; /* height of picture in mm */
__u32 width; /* width of picture in mm */
__u32 accel_flags; /* (OBSOLETE) see fb_info.flags */
/* Timing: All values in pixclocks, except pixclock (of course) */
__u32 pixclock; /* pixel clock in ps (pico seconds) */
__u32 left_margin; /* time from sync to picture */
__u32 right_margin; /* time from picture to sync */
__u32 upper_margin; /* time from sync to picture */
__u32 lower_margin;
__u32 hsync_len; /* length of horizontal sync */
__u32 vsync_len; /* length of vertical sync */
__u32 sync; /* see FB_SYNC_* */
__u32 vmode; /* see FB_VMODE_* */
__u32 rotate; /* angle we rotate counter clockwise */
__u32 reserved[5]; /* Reserved for future compatibility */
};
struct fb_cmap {
__u32 start; /* First entry */
__u32 len; /* Number of entries */
__u16 *red; /* Red values */
__u16 *green;
__u16 *blue;
__u16 *transp; /* transparency, can be NULL */
};
__u32 xres;__u32 yres;实际可视区域
__u32 xres_virtual;__u32 yres_virtual;显存可视区域
__u32 xoffset;__u32 yoffset;显存和可见可视区域偏移量
__u32 bits_per_pixel;像素
__u32 grayscale;黑白(0)
结构体参数为可变参数,用于获取和设置可变信息,通过ioctl设置获取(FBIOGET_VSCREENINFO获取,FBIOPUT_VSCREENINFO修改)
struct fb_fix_screeninfo {
char id[16]; /* identification string eg "TT Builtin" */
unsigned long smem_start; /* Start of frame buffer mem */
/* (physical address) */
__u32 smem_len; /* Length of frame buffer mem */
__u32 type; /* see FB_TYPE_* */
__u32 type_aux; /* Interleave for interleaved Planes */
__u32 visual; /* see FB_VISUAL_* */
__u16 xpanstep; /* zero if no hardware panning */
__u16 ypanstep; /* zero if no hardware panning */
__u16 ywrapstep; /* zero if no hardware ywrap */
__u32 line_length; /* length of a line in bytes */
unsigned long mmio_start; /* Start of Memory Mapped I/O */
/* (physical address) */
__u32 mmio_len; /* Length of Memory Mapped I/O */
__u32 accel; /* Indicate to driver which */
/* specific chip/card we have */
__u16 reserved[3]; /* Reserved for future compatibility */
};
char id[16];驱动名称
unsigned long smem_start;显存起始地址
__u32 smem_len;显存长度
unsigned long mmio_start;显示IO的起始地址
__u32 mmio_len;显示IO的长度
结构体参数为不可变参数,用于显示卡属性,用户态不能被修改
struct fb_cmap {
__u32 start; /* First entry */
__u32 len; /* Number of entries */
__u16 *red; /* Red values */
__u16 *green;
__u16 *blue;
__u16 *transp; /* transparency, can be NULL */
};
__u32 start;第一个元素的入口
__u16 *transp;透明度
描述设备颜色映射信息,ioctl(FBIOGETCMAP,FBIOPUTCMAP)对设定或获取颜色信息
struct fb_info {
int node;
int flags;
struct mutex lock; /* Lock for open/release/ioctl funcs */
struct mutex mm_lock; /* Lock for fb_mmap and smem_* fields */
struct fb_var_screeninfo var; /* Current var */
struct fb_fix_screeninfo fix; /* Current fix */
struct fb_monspecs monspecs; /* Current Monitor specs */
struct work_struct queue; /* Framebuffer event queue */
struct fb_pixmap pixmap; /* Image hardware mapper */
struct fb_pixmap sprite; /* Cursor hardware mapper */
struct fb_cmap cmap; /* Current cmap */
struct list_head modelist; /* mode list */
struct fb_videomode *mode; /* current mode */
#ifdef CONFIG_FB_BACKLIGHT
/* assigned backlight device */
/* set before framebuffer registration,
remove after unregister */
struct backlight_device *bl_dev;
/* Backlight level curve */
struct mutex bl_curve_mutex;
u8 bl_curve[FB_BACKLIGHT_LEVELS];
#endif
#ifdef CONFIG_FB_DEFERRED_IO
struct delayed_work deferred_work;
struct fb_deferred_io *fbdefio;
#endif
struct fb_ops *fbops;
struct device *device; /* This is the parent */
struct device *dev; /* This is this fb device */
int class_flag; /* private sysfs flags */
#ifdef CONFIG_FB_TILEBLITTING
struct fb_tile_ops *tileops; /* Tile Blitting */
#endif
char __iomem *screen_base; /* Virtual address */
unsigned long screen_size; /* Amount of ioremapped VRAM or 0 */
void *pseudo_palette; /* Fake palette of 16 colors */
#define FBINFO_STATE_RUNNING 0
#define FBINFO_STATE_SUSPENDED 1
u32 state; /* Hardware state i.e suspend */
void *fbcon_par; /* fbcon use-only private area */
/* From here on everything is device dependent */
void *par;
/* we need the PCI or similiar aperture base/size not
smem_start/size as smem_start may just be an object
allocated inside the aperture so may not actually overlap */
struct apertures_struct {
unsigned int count;
struct aperture {
resource_size_t base;
resource_size_t size;
} ranges[0];
} *apertures;
};
struct fb_var_screeninfo var;设备的可变参数
struct fb_fix_screeninfo fix;设备固定参数
char __iomem *screen_base;IO基地址
unsigned long screen_size;IO内存大小
struct backlight_device *bl_dev;背光调整
struct fb_ops *fbops;操作函数集
struct device *device;父设备
struct device *dev;fb设备
描述设备的属性和操作
struct fb_ops {
/* open/release and usage marking */
struct module *owner;
int (*fb_open)(struct fb_info *info, int user);
int (*fb_release)(struct fb_info *info, int user);
/* For framebuffers with strange non linear layouts or that do not
* work with normal memory mapped access
*/
ssize_t (*fb_read)(struct fb_info *info, char __user *buf,
size_t count, loff_t *ppos);
ssize_t (*fb_write)(struct fb_info *info, const char __user *buf,
size_t count, loff_t *ppos);
/* checks var and eventually tweaks it to something supported,
* DO NOT MODIFY PAR */
int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info);
/* set the video mode according to info->var */
int (*fb_set_par)(struct fb_info *info);
/* set color register */
int (*fb_setcolreg)(unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp, struct fb_info *info);
/* set color registers in batch */
int (*fb_setcmap)(struct fb_cmap *cmap, struct fb_info *info);
/* blank display */
int (*fb_blank)(int blank, struct fb_info *info);
/* pan display */
int (*fb_pan_display)(struct fb_var_screeninfo *var, struct fb_info *info);
/* Draws a rectangle */
void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect);
/* Copy data from area to another */
void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region);
/* Draws a image to the display */
void (*fb_imageblit) (struct fb_info *info, const struct fb_image *image);
/* Draws cursor */
int (*fb_cursor) (struct fb_info *info, struct fb_cursor *cursor);
/* Rotates the display */
void (*fb_rotate)(struct fb_info *info, int angle);
/* wait for blit idle, optional */
int (*fb_sync)(struct fb_info *info);
/* perform fb specific ioctl (optional) */
int (*fb_ioctl)(struct fb_info *info, unsigned int cmd,
unsigned long arg);
/* Handle 32bit compat ioctl (optional) */
int (*fb_compat_ioctl)(struct fb_info *info, unsigned cmd,
unsigned long arg);
/* perform fb specific mmap */
int (*fb_mmap)(struct fb_info *info, struct vm_area_struct *vma);
/* get capability given var */
void (*fb_get_caps)(struct fb_info *info, struct fb_blit_caps *caps,
struct fb_var_screeninfo *var);
/* teardown any resources to do with this framebuffer */
void (*fb_destroy)(struct fb_info *info);
};
int (*fb_open)(struct fb_info *info, int user);
int (*fb_release)(struct fb_info *info, int user);
ssize_t (*fb_read)(struct fb_info *info, char __user *buf,size_t count, loff_t *ppos);
ssize_t (*fb_write)(struct fb_info *info, const char __user *buf,size_t count, loff_t *ppos);
int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info);
int (*fb_ioctl)(struct fb_info *info, unsigned int cmd,unsigned long arg);
int (*fb_mmap)(struct fb_info *info, struct vm_area_struct *vma);
void (*fb_destroy)(struct fb_info *info);
void (*fb_save_state)(struct fb_info *info);保存硬件状态
void (*fb_restore_state)(struct fb_info *info);恢复被保存硬件状态
驱动框架
fbmem.c
#define FBPIXMAPSIZE (1024 * 8)
struct fb_info *registered_fb[FB_MAX] __read_mostly;
数组指针的每个成员对应一个fb_info结构体指针(每个设备的描述信息,#define FB_MAX 32),数组下标对应次设备号
int num_registered_fb __read_mostly;
已注册的设备数
module_init(fbmem_init);
static void __exit
fbmem_exit(void)
{
remove_proc_entry("fb", NULL);
class_destroy(fb_class);
unregister_chrdev(FB_MAJOR, "fb");
}
module_exit(fbmem_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Framebuffer base");
static int __init
fbmem_init(void)
{
proc_create("fb", 0, NULL, &fb_proc_fops);
if (register_chrdev(FB_MAJOR,"fb",&fb_fops))
printk("unable to get major %d for fb devs\n", FB_MAJOR);
fb_class = class_create(THIS_MODULE, "graphics");
if (IS_ERR(fb_class)) {
printk(KERN_WARNING "Unable to create fb class; errno = %ld\n", PTR_ERR(fb_class));
fb_class = NULL;
}
return 0;
}
static const struct file_operations fb_proc_fops = {
.owner = THIS_MODULE,
.open = proc_fb_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
fb_open(struct inode *inode, struct file *file)
__acquires(&info->lock)
__releases(&info->lock)
{
int fbidx = iminor(inode);
struct fb_info *info;
int res = 0;
if (fbidx >= FB_MAX)
return -ENODEV;
info = registered_fb[fbidx];
if (!info)
request_module("fb%d", fbidx);
info = registered_fb[fbidx];
if (!info)
return -ENODEV;
mutex_lock(&info->lock);
if (!try_module_get(info->fbops->owner)) {
res = -ENODEV;
goto out;
}
file->private_data = info;
if (info->fbops->fb_open) {
res = info->fbops->fb_open(info,1);
if (res)
module_put(info->fbops->owner);
}
#ifdef CONFIG_FB_DEFERRED_IO
if (info->fbdefio)
fb_deferred_io_open(info, inode, file);
#endif
out:
mutex_unlock(&info->lock);
return res;
}
创建/proc/fb(内容为次设备号,设备名),只读方法
创建/sys/class/graphics/设备类
注册设备驱动,主设备号FB_MAJOR(29)
fb_open:int fbidx = iminor(inode);获取次设备号(数组下标)
struct fb_info *info;
info = registered_fb[fbidx];依据数组下标获取对应设备信息
其他操作函数中用fb_open方法获取设备信息
ioctl命令:
FBIOGET_VSCREENINFO fb_get_var
FBIOPUT_VSCREENINFO fb_set_var
FBIOGET_FSCREENINFO fb_get_fix
FBIOPUTCMAP fb_set_cmap
FBIOGETCMAP fb_get_cmap
FBIOPAN_DISPLAY fb_pan_display
fbmem.c为上层应用程序提供驱动提供接口
fbsys.c/sys目录下的属性文件,modedb.c显示模式
fb_notify.c管理相关通知的,链表变动告知链表中成员
平台驱动(s3cfb.c)
module_init(s3cfb_register);
module_exit(s3cfb_unregister);
MODULE_AUTHOR("Jonghun, Han ");
MODULE_AUTHOR("Jinsung, Yang ");
MODULE_DESCRIPTION("Samsung Display Controller (FIMD) driver");
MODULE_LICENSE("GPL");
static int __init s3cfb_register(void)
{
platform_driver_register(&s3cfb_driver);
return 0;
}
static struct platform_driver s3cfb_driver = {
.probe = s3cfb_probe,
.remove = __devexit_p(s3cfb_remove),
.driver = {
.name = S3CFB_NAME,
.owner = THIS_MODULE,
},
};
int platform_driver_register(struct platform_driver *drv)
{
drv->driver.bus = &platform_bus_type;
if (drv->probe)
drv->driver.probe = platform_drv_probe;
if (drv->remove)
drv->driver.remove = platform_drv_remove;
if (drv->shutdown)
drv->driver.shutdown = platform_drv_shutdown;
return driver_register(&drv->driver);
}
struct bus_type platform_bus_type = {
.name = "platform",
.dev_attrs = platform_dev_attrs,
.match = platform_match,
.uevent = platform_uevent,
.pm = &platform_dev_pm_ops,
};
static int platform_drv_probe(struct device *_dev)
{
struct platform_driver *drv = to_platform_driver(_dev->driver);
struct platform_device *dev = to_platform_device(_dev);
return drv->probe(dev);
}
struct device {
struct device *parent;
struct device_private *p;
struct kobject kobj;
const char *init_name; /* initial name of the device */
struct device_type *type;
struct mutex mutex; /* mutex to synchronize calls to
* its driver.
*/
struct bus_type *bus; /* type of bus device is on */
struct device_driver *driver; /* which driver has allocated this
device */
void *platform_data; /* Platform specific data, device
core doesn't touch it */
struct dev_pm_info power;
#ifdef CONFIG_NUMA
int numa_node; /* NUMA node this device is close to */
#endif
u64 *dma_mask; /* dma mask (if dma'able device) */
u64 coherent_dma_mask;/* Like dma_mask, but for
alloc_coherent mappings as
not all hardware supports
64 bit addresses for consistent
allocations such descriptors. */
struct device_dma_parameters *dma_parms;
struct list_head dma_pools; /* dma pools (if dma'ble) */
struct dma_coherent_mem *dma_mem; /* internal for coherent mem
override */
/* arch specific additions */
struct dev_archdata archdata;
#ifdef CONFIG_OF
struct device_node *of_node;
#endif
dev_t devt; /* dev_t, creates the sysfs "dev" */
spinlock_t devres_lock;
struct list_head devres_head;
struct klist_node knode_class;
struct class *class;
const struct attribute_group **groups; /* optional groups */
void (*release)(struct device *dev);
};
#define to_platform_driver(drv) (container_of((drv), struct platform_driver,driver))
#define to_platform_device(x) container_of((x), struct platform_device, dev)
struct platform_driver {
int (*probe)(struct platform_device *);
int (*remove)(struct platform_device *);
void (*shutdown)(struct platform_device *);
int (*suspend)(struct platform_device *, pm_message_t state);
int (*resume)(struct platform_device *);
struct device_driver driver;
const struct platform_device_id *id_table;
};
struct platform_device {
const char * name;
int id;
struct device dev;
u32 num_resources;
struct resource * resource;
const struct platform_device_id *id_entry;
/* arch specific additions */
struct pdev_archdata archdata;
};
mach-smdk110.c
static struct platform_device *smdkc110_devices[] __initdata = {
...
#ifdef CONFIG_FB_S3C
&s3c_device_fb,
#endif
...
}
devs.c
static u64 fb_dma_mask = 0xffffffffUL;
struct platform_device s3c_device_fb = {
.name = "s3cfb",
.id = -1,
.num_resources = ARRAY_SIZE(s3cfb_resource),
.resource = s3cfb_resource,
.dev = {
.dma_mask = &fb_dma_mask,
.coherent_dma_mask = 0xffffffffUL
}
};
#if defined(CONFIG_S5P_DEV_FB)
static struct resource s3cfb_resource[] = {
[0] = {
.start = S5P_PA_LCD,
.end = S5P_PA_LCD + S5P_SZ_LCD - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_LCD1,
.end = IRQ_LCD1,
.flags = IORESOURCE_IRQ,
},
[2] = {
.start = IRQ_LCD0,
.end = IRQ_LCD0,
.flags = IORESOURCE_IRQ,
},
};
probe(register)
static int __devinit s3cfb_probe(struct platform_device *pdev)
{
//数据传递结构体
struct s3c_platform_fb *pdata;
struct s3cfb_global *fbdev;
struct resource *res;
int i, j, ret = 0;
//申请内存
fbdev = kzalloc(sizeof(struct s3cfb_global), GFP_KERNEL);
if (!fbdev) {
dev_err(&pdev->dev, "failed to allocate for "
"global fb structure\n");
ret = -ENOMEM;
goto err_global;
}
fbdev->dev = &pdev->dev;
//电源管理
fbdev->regulator = regulator_get(&pdev->dev, "pd");
if (!fbdev->regulator) {
dev_err(fbdev->dev, "failed to get regulator\n");
ret = -EINVAL;
goto err_regulator;
}
ret = regulator_enable(fbdev->regulator);
if (ret < 0) {
dev_err(fbdev->dev, "failed to enable regulator\n");
ret = -EINVAL;
goto err_regulator;
}
//从结构体变量获取platform设备私有数据
pdata = to_fb_plat(&pdev->dev);
if (!pdata) {
dev_err(fbdev->dev, "failed to get platform data\n");
ret = -EINVAL;
goto err_pdata;
}
//配置gpio
fbdev->lcd = (struct s3cfb_lcd *)pdata->lcd;
if (pdata->cfg_gpio)
pdata->cfg_gpio(pdev);
//配置时钟
if (pdata->clk_on)
pdata->clk_on(pdev, &fbdev->clock);
//获取寄存器资源
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(fbdev->dev, "failed to get io memory region\n");
ret = -EINVAL;
goto err_io;
}
/申请IO资源
res = request_mem_region(res->start,
res->end - res->start + 1, pdev->name);
if (!res) {
dev_err(fbdev->dev, "failed to request io memory region\n");
ret = -EINVAL;
goto err_io;
}
//虚拟地址(IO资源)映射
fbdev->regs = ioremap(res->start, res->end - res->start + 1);
if (!fbdev->regs) {
dev_err(fbdev->dev, "failed to remap io region\n");
ret = -EINVAL;
goto err_mem;
}
/设置中断
s3cfb_set_vsync_interrupt(fbdev, 1);
s3cfb_set_global_interrupt(fbdev, 1);
s3cfb_init_global(fbdev);
if (s3cfb_alloc_framebuffer(fbdev)) {
ret = -ENOMEM;
goto err_alloc;
}
//注册设备(device_create,registered_fb)
if (s3cfb_register_framebuffer(fbdev)) {
ret = -EINVAL;
goto err_register;
}
s3cfb_set_clock(fbdev);
s3cfb_set_window(fbdev, pdata->default_win, 1);
s3cfb_display_on(fbdev);
fbdev->irq = platform_get_irq(pdev, 0);
if (request_irq(fbdev->irq, s3cfb_irq_frame, IRQF_SHARED,
pdev->name, fbdev)) {
dev_err(fbdev->dev, "request_irq failed\n");
ret = -EINVAL;
goto err_irq;
}
#ifdef CONFIG_FB_S3C_LCD_INIT
if (pdata->backlight_on)
pdata->backlight_on(pdev);
if (!bootloaderfb && pdata->reset_lcd)
pdata->reset_lcd(pdev);
#endif
#ifdef CONFIG_HAS_EARLYSUSPEND
fbdev->early_suspend.suspend = s3cfb_early_suspend;
fbdev->early_suspend.resume = s3cfb_late_resume;
fbdev->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
register_early_suspend(&fbdev->early_suspend);
#endif
//创建设备文件
ret = device_create_file(&(pdev->dev), &dev_attr_win_power);
if (ret < 0)
dev_err(fbdev->dev, "failed to add sysfs entries\n");
dev_info(fbdev->dev, "registered successfully\n");
//logo
#if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO)
if (fb_prepare_logo( fbdev->fb[pdata->default_win], FB_ROTATE_UR)) {
printk("Start display and show logo\n");
/* Start display and show logo on boot */
fb_set_cmap(&fbdev->fb[pdata->default_win]->cmap, fbdev->fb[pdata->default_win]);
fb_show_logo(fbdev->fb[pdata->default_win], FB_ROTATE_UR);
}
#endif
mdelay(100);
if (pdata->backlight_on)
pdata->backlight_on(pdev);
return 0;
err_irq:
s3cfb_display_off(fbdev);
s3cfb_set_window(fbdev, pdata->default_win, 0);
for (i = pdata->default_win;
i < pdata->nr_wins + pdata->default_win; i++) {
j = i % pdata->nr_wins;
unregister_framebuffer(fbdev->fb[j]);
}
err_register:
for (i = 0; i < pdata->nr_wins; i++) {
if (i == pdata->default_win)
s3cfb_unmap_default_video_memory(fbdev->fb[i]);
framebuffer_release(fbdev->fb[i]);
}
kfree(fbdev->fb);
err_alloc:
iounmap(fbdev->regs);
err_mem:
release_mem_region(res->start,
res->end - res->start + 1);
err_io:
pdata->clk_off(pdev, &fbdev->clock);
err_pdata:
regulator_disable(fbdev->regulator);
err_regulator:
kfree(fbdev);
err_global:
return ret;
}
probe的三个传参结构体
struct s3c_platform_fb {
int hw_ver;
char clk_name[16];
int nr_wins;
int nr_buffers[5];
int default_win;
int swap;
phys_addr_t pmem_start; /* starting physical address of memory region */
size_t pmem_size; /* size of memory region */
void *lcd;
void (*cfg_gpio)(struct platform_device *dev);
int (*backlight_on)(struct platform_device *dev);
int (*backlight_onoff)(struct platform_device *dev, int onoff);
int (*reset_lcd)(struct platform_device *dev);
int (*clk_on)(struct platform_device *pdev, struct clk **s3cfb_clk);
int (*clk_off)(struct platform_device *pdev, struct clk **clk);
};
struct s3cfb_global {
/* general */
void __iomem *regs;
struct mutex lock;
struct device *dev;
struct clk *clock;
struct regulator *regulator;
int irq;
struct fb_info **fb;
struct completion fb_complete;
/* fimd */
int enabled;
int dsi;
int interlace;
enum s3cfb_output_t output;
enum s3cfb_rgb_mode_t rgb_mode;
struct s3cfb_lcd *lcd;
#ifdef CONFIG_HAS_WAKELOCK
struct early_suspend early_suspend;
struct wake_lock idle_lock;
#endif
#ifdef CONFIG_CPU_FREQ
struct notifier_block freq_transition;
struct notifier_block freq_policy;
#endif
};
struct resource {
resource_size_t start;
resource_size_t end;
const char *name;
unsigned long flags;
struct resource *parent, *sibling, *child;
};
struct s3c_platform_fb:结构体变量是platform设备私有数据(platform_device.device.platform_data)
struct s3cfb_global:s3cfb.c和s3cfb_fimd6x.c文件中函数传参
struct resource:包含fb的寄存器,中断
demo1:
获取fb恒参和变参信息,刷背景,划线程序
framebuffer.c
#include
#include
#include
#include
#include
#include
#include
#define DEV "/dev/fb0"
#define BLUE 0xFF0000FF
#define RED 0xFFFF0000
#define GREEN 0xFF00FF00
#define WHITE 0xFFFFFFFF
#define BLACK 0x00000000
#define WIDTH 1024
#define HEIGHT 600
unsigned int *pfb = NULL;
static void lcd_draw_pic_color(unsigned int x,unsigned int y,unsigned int color);
void draw_back(unsigned int width, unsigned int height, unsigned int color);
void lcd_draw_line(unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2, unsigned int color);
int main(void)
{
int fd = -1;
int ret = -1;
struct fb_fix_screeninfo fix_info = {0};
struct fb_var_screeninfo var_info = {0};
struct fb_cmap cmap_info = {0};
fd = open(DEV, O_RDWR);
if(fd < 0)
{
perror("open");
return -1;
}
printf("open %s success\n", DEV);
ret = ioctl(fd, FBIOGET_FSCREENINFO, &fix_info);
if(ret < 0)
{
perror("ioctl fix_screeninfo");
return -1;
}
printf("id : %s smem_start(physical address) : 0x%x , \
smem_len : %u mmio_start(IO start) : 0x%x mmio_len : %u\n", \
fix_info.id,fix_info.smem_start,fix_info.smem_len,fix_info.mmio_start,fix_info.mmio_len);
ret = ioctl(fd, FBIOGET_VSCREENINFO, &var_info);
if(ret < 0)
{
perror("ioctl var_screeninfo");
return -1;
}
printf("xres : %u yres : %u xres_virtual : %u yres_virtual : %u \
bits_per_pixel : %u grayscale : %u height : %u width : %u \n",\
var_info.xres,var_info.yres,var_info.xres_virtual,var_info.yres_virtual,\
var_info.bits_per_pixel,var_info.grayscale,var_info.height,var_info.width);
pfb = mmap(NULL, fix_info.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED,fd , 0);
if(pfb == NULL)
{
perror("mmap");
return -1;
}
draw_back(var_info.xres_virtual, var_info.yres_virtual, WHITE);
lcd_draw_line(0, 479, 799, 0, BLACK);
close(fd);
return 0;
}
static void lcd_draw_pic_color(unsigned int x,unsigned int y,unsigned int color)
{
*(pfb + WIDTH * y + x) = color;
}
void draw_back(unsigned int width, unsigned int height, unsigned int color)
{
unsigned int x, y;
for (y=0; y=0)
{
if(dy >= 0) // dy>=0
{
if(dx>=dy) // 1/8 octant
{
e=dy-dx/2;
while(x1<=x2)
{
lcd_draw_pic_color(x1,y1,color);
if(e>0){y1+=1;e-=dx;}
x1+=1;
e+=dy;
}
}
else // 2/8 octant
{
e=dx-dy/2;
while(y1<=y2)
{
lcd_draw_pic_color(x1,y1,color);
if(e>0){x1+=1;e-=dy;}
y1+=1;
e+=dx;
}
}
}
else // dy<0
{
dy=-dy; // dy=abs(dy)
if(dx>=dy) // 8/8 octant
{
e=dy-dx/2;
while(x1<=x2)
{
lcd_draw_pic_color(x1,y1,color);
if(e>0){y1-=1;e-=dx;}
x1+=1;
e+=dy;
}
}
else // 7/8 octant
{
e=dx-dy/2;
while(y1>=y2)
{
lcd_draw_pic_color(x1,y1,color);
if(e>0){x1+=1;e-=dy;}
y1-=1;
e+=dx;
}
}
}
}
else //dx<0
{
dx=-dx; //dx=abs(dx)
if(dy >= 0) // dy>=0
{
if(dx>=dy) // 4/8 octant
{
e=dy-dx/2;
while(x1>=x2)
{
lcd_draw_pic_color(x1,y1,color);
if(e>0){y1+=1;e-=dx;}
x1-=1;
e+=dy;
}
}
else // 3/8 octant
{
e=dx-dy/2;
while(y1<=y2)
{
lcd_draw_pic_color(x1,y1,color);
if(e>0){x1-=1;e-=dy;}
y1+=1;
e+=dx;
}
}
}
else // dy<0
{
dy=-dy; // dy=abs(dy)
if(dx>=dy) // 5/8 octant
{
e=dy-dx/2;
while(x1>=x2)
{
lcd_draw_pic_color(x1,y1,color);
if(e>0){y1-=1;e-=dx;}
x1-=1;
e+=dy;
}
}
else // 6/8 octant
{
e=dx-dy/2;
while(y1>=y2)
{
lcd_draw_pic_color(x1,y1,color);
if(e>0){x1-=1;e-=dy;}
y1-=1;
e+=dx;
}
}
}
}
}
Makefile
all:
arm-linux-gcc framebuffer.c -o framebuffer
cp:
cp framebuffer /root/rootfs/driver -f
clean:
rm -rf framebuffer
结果示例:
demo2:
修改logo(图片,位置)
sudo apt-get install netpbm -y
pngtopnm logo.png | ppmquant -fs 224 | pnmtoplainpnm > logo_linux_clut224.ppm
cd /root/kernel/drivers/video/logo/
cp logo_x210_clut224.ppm logo_x210_clut224.ppm_bak240114
cp logo_linux_clut224.ppm /root/kernel/drivers/video/logo/logo_x210_clut224.ppm -f
vim fbmem.c
//image.dx = 0;
//image.dy = y;
image.dx = (info->var.xres - logo->width) / 2;
image.dy = (info->var.yres - logo->height) / 2;
make -j8
cp -f arch/arm/boot/zImage ~/tftp/