linux驱动(五):framebuffer

发布时间:2024年01月14日

? ? ? ? 本文主要探讨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/
文章来源:https://blog.csdn.net/tyro_wzp/article/details/135581468
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。