? ? ? ? 本文主要探讨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 <jonghun.han@samsung.com>");
MODULE_AUTHOR("Jinsung, Yang <jsgood.yang@samsung.com>");
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 <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#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<height; y++)
{
for (x=0; x<width; x++)
{
*(pfb + y * WIDTH + x) = color;
}
}
}
void lcd_draw_line(unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2, unsigned int color)
{
int dx,dy,e;
dx=x2-x1;
dy=y2-y1;
if(dx>=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/