Linux LCD驱动中framebuffer的研究

Linux 本身实现了FrameBuffer驱动(字符驱动)便于应用用于层调用,实现的文件是/drivers/video/fbmem.c文件:

static const struct file_operations fb_fops = {
    .owner =    THIS_MODULE,
    .read =        fb_read,
    .write =    fb_write,
    .unlocked_ioctl = fb_ioctl,
#ifdef CONFIG_COMPAT
    .compat_ioctl = fb_compat_ioctl,
#endif
    .mmap =        fb_mmap,
    .open =        fb_open,
    .release =    fb_release,
#ifdef HAVE_ARCH_FB_UNMAPPED_AREA
    .get_unmapped_area = get_fb_unmapped_area,
#endif
#ifdef CONFIG_FB_DEFERRED_IO
    .fsync =    fb_deferred_io_fsync,
#endif
};

    上层应用程序通过这些函数实现对lcd各种参数的控制,修改等,这与以前编写字符设备驱动的模式一样,这些函数都是linux内核已经实现好的,不需要驱动工程师去编写.那驱动工程师的任务是什么呢?获取平台设备的相关信息,并初始化相关的硬件设备,注册中断,开辟帧缓冲内存,注册帧缓冲设备,这就是/drivers/video/s3c2440fb.c中的主要内容了.里面有一个重要的数据结构:

static struct fb_ops s3c2410fb_ops = {
    .owner        = THIS_MODULE,
    .fb_check_var    = s3c2410fb_check_var,
    .fb_set_par    = s3c2410fb_set_par,
    .fb_blank    = s3c2410fb_blank,
    .fb_setcolreg    = s3c2410fb_setcolreg,
    .fb_fillrect    = cfb_fillrect,
    .fb_copyarea    = cfb_copyarea,
    .fb_imageblit    = cfb_imageblit,
};

    这里的函数是真正对底层硬件进行操作的函数了,都是需要驱动工程师根据具体的硬件平台去填写.那么这些底层函数与上层应用程序的接口是怎样对接起来的呢?其实,是通过表征帧缓存设备的数据结构struct fb_info来实现的,这个数据结构几乎包括了lcd控制器的所有信息:

struct fb_info {
        int                      node;
        int                      flags;
        struct fb_var_screeninfo var;  
        struct fb_fix_screeninfo fix;
        struct fb_monspecs       monspecs;
        struct work_struct       queue;
        struct fb_pixmap         pixmap;
        struct fb_pixmap         sprite;
        struct fb_cmap           cmap;   
        struct list_head         modelist;
        struct fb_videomode      *mode;  

#ifdef CONFIG_FB_BACKLIGHT
        struct backlight_device *bl_dev;
        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;            // = &s3c2410fb_ops
        struct device           *device;
        struct device           *dev;
        int                     class_flag;    
#ifdef CONFIG_FB_TILEBLITTING
        struct fb_tile_ops      *tileops;
#endif
        char __iomem            *screen_base;
        unsigned long           screen_size;
        void *pseudo_palette;   
#define FBINFO_STATE_RUNNING    0
#define FBINFO_STATE_SUSPENDED 1
        u32                     state;      
        void                    *fbcon_par;
        void                    *par;         // ---> struct s3c2410fb_info
};

其中有几个重要的成员.struct fb_var_screeninfo var表示的是lcd屏的可变参数,而struct fb_fix_screeninfo fix表示的是lcd屏的不变参数.struct fb_ops *fbops当然就是上面那个重要结构的指针了.char __iomem *screen_base是申请的帧缓存的首地址(虚拟地址),unsigned long screen_size是缓存的大小.还要关注一下void *par这个指针,在初始化中,它用来指向自定义的一个数据结构struct s3c2410fb_info,在以下的分析中会见到.
struct fb_info这个结构是怎样将上层的请求传递到下层的呢?其实就是static const struct file_operations fb_fops结构中的成员函数根据需要调用了struct fb_info结构中struct fb_ops *fbops成员(不要将两者混淆了)中的相关函数,从而实现对lcd的参数读取、修改等,而struct fb_info中包含了lcd屏的相关参数信息.struct fb_ops *fbops中的成员函数只是在系统初始化模块时注册到内核中去的,只是存在于内核当中,等待被上层调用而已.  整个的架构大致就是这样.用图表示出来就是:
 Linux LCD驱动中framebuffer的研究_第1张图片


    /drivers/video/s3c2440fb.c 的硬件驱动为平台驱动,需要获取设备的信息(内存、中断、资源等),平台设备的注册在arch/arm/mach-s3c2440/mach-smdk2440.c中被定义:

static struct s3c2410fb_display smdk2440_lcd_cfg __initdata = {
                .lcdcon5                = S3C2410_LCDCON5_FRM565 |
                                                    S3C2410_LCDCON5_INVVLINE |
                                                    S3C2410_LCDCON5_INVVFRAME |
                                                    S3C2410_LCDCON5_PWREN |
                                                    S3C2410_LCDCON5_HWSWP,
                .type                                = S3C2410_LCDCON1_TFT,
                .width                                = 320,
                .height                                = 240,
                .pixclock                = 156250,
                .xres                                = 320,
                .yres                                = 240,
                .bpp                                = 16,
                .left_margin                = 20,//or8,
                .right_margin                = 38,//or5,
                .hsync_len                = 30,//or63,
                .upper_margin                = 12,//or15,
                .lower_margin                = 15,//or3,
                .vsync_len                =3,//or5,

};
static struct s3c2410fb_mach_info smdk2440_fb_info __initdata = {
                .displays                = &smdk2440_lcd_cfg,
                .num_displays                = 1,//或者ARRAY_SIZE(smdk2440_lcd_cfg),
                .default_display = 0,
#if 0
                /* currently setup by downloader */
                .gpccon                                = 0xaa940659,
                .gpccon_mask                = 0xffffffff,
                .gpcup                                = 0x0000ffff,
                .gpcup_mask                = 0xffffffff,
                .gpdcon                                = 0xaa84aaa0,
                .gpdcon_mask                = 0xffffffff,
                .gpdup                                = 0x0000faff,
                .gpdup_mask                = 0xffffffff,
#endif   .lpcsel                                =0,//((0xCE6) & ~7) | 1<<4,
};


LCD 的参数设定是需要根据LCD 的手册来设定arch/arm/mach-s3c2440/mach-smdk2440.c 里面
的s3c2410fb_display smdk2440_lcd_cfg 结构体,FL2440中详细的设置见:

FL2440 Linux kernel + yaffs2根文件移植过程(一) http://blog.csdn.net/sharecode/article/details/8190692

你可能感兴趣的:(Linux LCD驱动中framebuffer的研究)