ARM9嵌入式Linux开发-FrameBuff和LCD驱动移植

FrameBuff

FrameBuffer介绍

  • FrameBuffer直译就是,帧缓冲。
    • Frame(帧):所看到的屏幕上的图像,或者在一个窗口中的图像,就叫一帧。
    • Buffer(缓冲):一段RAM,用来暂存图像数据,这些数据会被直接写入到显示设备。
  • 帧缓冲就相当于图形操作和图像输出中间的一个介质,将程序对图形数据的处理操作反馈到显示输出上。

ARM9嵌入式Linux开发-FrameBuff和LCD驱动移植_第1张图片

LCDC是将系统需要显示的数据经过处理后输出到LCD显示驱动器的液晶显示控制模块 ,在用户初始化配置后,LCDC将自动进行读取数据、缓存数据、处理数据以及输出符合时序要求的控制和数据信号等操作。

FrameBuffer是Linux内核为显示设备提供的一个接口。这种接口将显示设备抽象为帧缓冲区。用户可以将它看成是显示内存的一个映像,将其映射到进程地址空间之后,就可以直接进行读写操作,而写操作可以立即反应在屏幕上。 帧缓冲设备是字符设备,主设备号为29,次设备号为帧缓冲的个数(最多32个),对应的设备文件一般是 /dev/fb0、/dev/fb1 等等。假设现在的显示模式是1024x768-8 位色,则可以通过如下的命令清空屏幕

dd if=/dev/zero of=/dev/fb0 bs=1024 count=768

如果应用程序需要知道FrameBuffer设备的相关参数,必须通过ioctl()系统调用来完成。最常用的ioctl命令字是下面这两个: FBIOGET_FSCREENINFO:与FrameBuffer有关的固定的信息,比如图形硬件上实际的帧缓存空间的大小、能否硬件加速等信息 FBIOGET_VSCREENINFO:与FrameBuffer有关的可变信息,之所以可变,是因为对同样的图形硬件,可以工作在不同的模式下,简单来讲,一个支持 1024x768x24图形模式的硬件通常也能工作在800x600x16的图形模式下,可变的信息就是指FrameBuffer的长度、宽度以及颜色深度等信息。

ARM9嵌入式Linux开发-FrameBuff和LCD驱动移植_第2张图片

Framebuffer中驱动重要数据结构

struct fb_info

驱动最关键的结构体,包含了设备属性和操作的完整描述,包括设备的设置参数、状态以及对底层硬件操作的函数指针。在Linux中,每一个帧缓冲设备都必须对应一个fb_info,fb_info在/linux/fb.h中的定义如下 (只列出重要的一些) :

struct fb_info {
    int node; 
    int flags;
    struct fb_var_screeninfo var; /*LCD可变参数结构体*/ 
    struct fb_fix_screeninfo fix; /*LCD固定参数结构体*/ 
    struct fb_monspecs monspecs;  /*LCD显示器标准*/ 
    struct work_struct queue ;     /*帧缓冲事件队列*/ 
    struct fb_pixmap pixmap;      /*图像硬件mapper*/ 
    struct fb_pixmap sprite;      /*光标硬件mapper*/ 
    struct fb_cmap cmap;          /*当前的颜色表*/ 
    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; /*对底层硬件操作的函数指针*/ 
    struct device * device; 
    struct device * dev;    /*fb设备*/ 
    int class_flag;     
# ifdef CONFIG_FB_TILEBLITTING
    struct fb_tile_ops * tileops; /*图块Blitting*/ 
# endif 
    char __iomem * screen_base;    /*虚拟基地址*/ 
    unsigned long screen_size;    /*LCD IO映射的虚拟内存大小*/ 
    void * pseudo_palette;         /*伪16色颜色表*/ 
# define FBINFO_STATE_RUNNING    0
# define FBINFO_STATE_SUSPENDED  1
    u32 state;   /*LCD的挂起或恢复状态*/ 
    oid * fbcon_par; 
    void * par;     
} ; 

其中,比较重要的成员有struct fb_var_screeninfo var、 struct fb_fix_screeninfo fix和structfb_ops * fbops,它们也都是结构体,下面我们一个一个的来看。

struct fb_fix_screeninfo 填充用户不可修改的参数,比如屏幕缓冲区的物理地址和长度等。

struct fb_fix_screeninfo { 
    char id[ 16] ;                 /*字符串形式的标示符 */ 
    unsigned long smem_start;    /*fb缓存的开始位置 */ 
    __u32 smem_len;              /*fb缓存的长度 */ 
    __u32 type;                  /*看FB_TYPE_* */ 
    __u32 type_aux;              /*分界*/ 
    __u32 visual;                /*看FB_VISUAL_* */ 
    __u16 xpanstep;              /*如果没有硬件panning就赋值为0 */ 
    __u16 ypanstep;              /*如果没有硬件panning就赋值为0 */ 
    __u16 ywrapstep;             /*如果没有硬件ywrap就赋值为0 */ 
    __u32 line_length;           /*一行的字节数 */ 
    unsigned long mmio_start;    /*内存映射IO的开始位置*/ 
    __u32 mmio_len;              /*内存映射IO的长度*/ 
    __u32 accel; 
    __u16 reserved[ 3] ;         /*保留*/ 
} ;

struct fb_var_screeninfo 填充用户可以修改的参数,包括屏幕分辨率、每个像素的位宽、帧延时、行延时等

struct fb_var_screeninfo { 
    __u32 xres;                 /*可见屏幕一行有多少个像素点*/ 
    __u32 yres;                 /*可见屏幕一列有多少个像素点*/ 
    __u32 xres_virtual;         /*虚拟屏幕一行有多少个像素点*/         
    __u32 yres_virtual;         /*虚拟屏幕一列有多少个像素点*/ 
    __u32 xoffset;              /*虚拟到可见屏幕之间的行偏移*/ 
    __u32 yoffset;              /*虚拟到可见屏幕之间的列偏移*/ 
    __u32 bits_per_pixel;       /*每个像素的位数即BPP*/ 
    __u32 grayscale;            /*非0时,指的是灰度*/ 
    struct fb_bitfield red;     /*fb缓存的R位域*/ 
    struct fb_bitfield green;   /*fb缓存的G位域*/ 
    struct fb_bitfield blue;    /*fb缓存的B位域*/ 
    struct fb_bitfield transp;  /*透明度*/     
    __u32 nonstd;               /* != 0 非标准像素格式*/ 
    __u32 activate;                 
    __u32 height;               /*高度*/ 
    __u32 width;                /*宽度*/ 
    __u32 accel_flags; 

     /*定时:除了pixclock本身外,其他的都以像素时钟为单位*/ 
    __u32 pixclock;             /*像素时钟(皮秒)*/ 
    __u32 left_margin;          /*行切换,从同步到绘图之间的延迟*/ 
    __u32 right_margin;         /*行切换,从绘图到同步之间的延迟*/ 
    __u32 upper_margin;         /*帧切换,从同步到绘图之间的延迟*/ 
    __u32 lower_margin;         /*帧切换,从绘图到同步之间的延迟*/ 
    __u32 hsync_len;            /*水平同步的长度*/ 
    __u32 vsync_len;            /*垂直同步的长度*/ 
    __u32 sync; 
    __u32 vmode; 
    __u32 rotate ; 
    __u32 reserved[ 5] ;          /*保留*/ 
} ; 

struct fb_ops fb_info的成员变量fops为指向底层操作的函数指针,这些函数是驱动程序开发人员编写。

struct fb_ops { 
    struct module * owner; 
    
    //检查可变参数并进行设置 
    int ( * fb_check_var) ( struct fb_var_screeninfo * var, struct fb_info * info) ; 

    //根据设置的值进行更新,使之有效 
    int ( * fb_set_par) ( struct fb_info * info) ; 

    //设置颜色寄存器 
     int ( * fb_setcolreg) ( unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info * info) ; 

    //显示空白 
    int ( * fb_blank) ( int blank, struct fb_info * info) ; 

    //矩形填充 
    void ( * fb_fillrect) ( struct fb_info * info, const struct fb_fillrect * rect) ; 

    //复制数据 
    void ( * fb_copyarea) ( struct fb_info * info, const struct fb_copyarea * region) ;

    //图形填充 
    void ( * fb_imageblit) ( struct fb_info * info, const struct fb_image * image) ; 
} ;

struct file_operations fb_fops Framebuffer属于字符设备,用户通过fb_fops结构中定义的文件操作接口函数可以操作Framebuffer设备,文件接口函数统一由fbmem.c实现,一般不需要驱动编写人员再次编写。

static struct file_operations fb_fops = {
   owner: THIS_MODULE,
   read: fb_read, // 读操作
   write: fb_write, // 写操作
   ioctl: fb_ioctl, // 控制操作
   mmap: fb_mmap, // 映射操作
 
   open: fb_open, // 打开操作
   release: fb_release, // 关闭操作
  #ifdef HAVE_ARCH_FB_UNMAPPED_AREA
   	get_unmapped_area: get_fb_unmapped_area,
  #endif
  };

应用程序层对帧缓冲设备的访问同对文件的访问操作类似。在应用程序中,对帧缓冲设备(dev/fb)的操作只需调用文件层的操作函数。首先打开/dev/fb设备文件;随后用ioctl操作取得屏幕的分辨率和bpp值,从而计算出屏幕缓冲区的大小,并将屏幕的缓冲区映射到用户空间;最后就可直接对屏幕缓冲区进行图片显示。对帧缓冲区的打开文件操作是由fb_open()完成等。 

Linux中Framebuffer的设备驱动结构

驱动文件:linux/drivers/video/目录

  • fbmem.c:提供LCD驱动的通用文件接口;
  • xxxfb.c:特定Framebuffer设备fb_info结构体的注册、注销以及其中成员的维护,尤其是fb_ops中成员函数的实现;
  • fb.h:定义了主要数据结构。

ARM9嵌入式Linux开发-FrameBuff和LCD驱动移植_第3张图片

Framebuffer设备的用户空间访问

ARM9嵌入式Linux开发-FrameBuff和LCD驱动移植_第4张图片

 

int main()
{     int framebuffer_device; int line_size,buffer_size, *i; 
       int *screen_memory; struct fb_var_screeninfo var_info; 
       framebuffer_device = open ( "/dev/fb0" , O_RDWR); 
       ioctl (framebuffer_device, FBIOGET_VSCREENINFO, &var_info); 	
       line_size = var_info.xres * var_info.bits_per_pixel / 8; 	// 计算一行字节数
       buffer_size = line_size * var_info.yres; 	// 计算显存缓冲区大小
       var_info.xoffset = 0;       var_info.yoffset = 0; 
        screen_memory = (char *) mmap (513, buffer_size, PROT_READ | PROT_WRITE, MAP_SHARED, framebuffer_device, 0); 
      for (i=0;i < buffer_size ; i++ ) 
         	*(screen_memory+i) = i%236; 
      sleep(2); 
      munmap(framebuffer_device, buffer_size);
      close(framebuffer_device);
      return 0; 
}

LCD驱动移植

修改内核源码 

2.6.30.4内核对LCD的支持已很完善,这里只做少许修改, 修改arch/arm/mach-s3c2440/mach-smdk2440.c的smdk2440_lcd_cfg函数和 smdk2440_fb_info函数,设置LCD参数:

static struct s3c2410fb_display smdk2440_lcd_cfg __initdata = {

	.lcdcon5	= S3C2410_LCDCON5_FRM565 |
			  S3C2410_LCDCON5_INVVCLK |
			  S3C2410_LCDCON5_INVVD |
			  S3C2410_LCDCON5_INVVDEN |
			  S3C2410_LCDCON5_PWREN |
			  S3C2410_LCDCON5_BSWP |
			  S3C2410_LCDCON5_HWSWP,
#if defined(CONFIG_FB_S3C24X0_PT320240)
	.type		= S3C2410_LCDCON1_TFT,

	.width		= 320,
	.height		= 240,

	.pixclock		= 80000, /* HCLK 100 MHz, divisor 3 */
	.setclkval		= 0x3,
	.xres		= 320,
	.yres		= 240,
	.bpp		= 16,
	.left_margin	= 11,	/* for HFPD*/
	.right_margin	= 70,	/* for HBPD*/
	.hsync_len	= 5,	/* for HSPW*/
	.upper_margin	= 12,	/* for VFPD*/
	.lower_margin	= 5,	/* for VBPD*/
	.vsync_len	= 5,	/* for VSPW*
#endif
};

static struct s3c2410fb_mach_info smdk2440_fb_info __initdata = {
	.displays	= &smdk2440_lcd_cfg,
	.num_displays	= 1,
	.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		= ((0xCE6) & ~7) | 1<<4,
};

配置内核选项

选上LCD支持和Logo图标。

ARM9嵌入式Linux开发-FrameBuff和LCD驱动移植_第5张图片

 

你可能感兴趣的:(ARM9嵌入式Linux开发)