1、framebuffer应用编程

    (1)打开设备文件

    (2)获取设备信息

    宏定义的命令在/linux/fb.h中

    不可变信息FSCREENINFO,使用ioctl参数有FBIOGET_FSCREENINFO宏名,表示用ioctl从驱动中获取lcd设备的不变的信息

    可变信息VSCREENINFO,使用ioctl参数有FBIOGET_VSCREENINFO宏名,表示用ioctl从驱动中获取lcd设备的可变信息

    fb的驱动框架将屏幕的所有硬件信息分为了两类,一类为不可变的,是通过软件不可更改的(比如屏幕尺寸,长短等)。一类是可以变的,比如分辨率是可以变的。

    内核中分别定义了两个结构体来表示lcd设备的可变信息和不可变信息,也在/include/linux/fb.h中。

    内核fb驱动框架提供的描述lcd屏幕的不可变信息的结构体。这部分不可变的信息和应用层的关系其实不大,应用层最多就是读出来看一下不可变信息。

struct fb_fix_screeninfo {
	char id[16];			/* identification string eg "TT Builtin" */
	unsigned long smem_start;	/* Start of frame buffer mem */    //fb在内存中的物理地址的起始地址
					/* (physical address) */
	__u32 smem_len;			/* Length of frame buffer mem */    /fb在内存中占用的物理地址的字节长度
	__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 */
};

    

    跟应用层有关系的结构体是关于fb驱动框架提供的lcd屏幕可变信息的结构体如下

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 */    //屏幕的参考点,就是fb的起始参考坐标。
	__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 结构体是用来描述颜色域的
	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	*/    //从这个到下面的六个是参数。 初始化lcd时序时的那几个参数。裸机中讲过
	__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 */
};

    什么是可视分辨率什么是虚拟分辨率呢?可视分辨率就是能看到的分辨率,比如你的屏幕是1024*468的,那么分辨率在1024*468范围内的东西你都可以看到。虚拟分辨率就是分辨率比实际的屏幕分辨率大,比如你的屏幕分辨率是800*480,但是你设置的分辨率是800*960,这就是虚拟分辨率。如果起始参考点是(0, 0),那么虚拟分辨率在屏幕实际分辨率部分的是可以看到的,虚拟分辨率不在屏幕分辨率部分的像素点是看不到的。

    有一种机制叫做双缓冲机制,也叫做乒乓结构。意思就是屏幕分辨率是800*480,虚拟分辨率是800*960,应用操作显示的时候,首先将起始参考点移动到(0, 0)的位置,然后应用刷一幅图进去,第二幅图片可以刷到(0, 480)的位置,这样显示第二幅图片的时候,应用只需要将起始参考点移动到(0, 480)的位置,那么第二幅图片就可以显示出来。

    fb的显存占用的内存字节数,可以用读出来的分辨率乘以位深度占用的字节来算出来,比如位深度是32位,那么位深度占用的就是4个字节,即一个像素点占用四个字节,虚拟分辨率是800*960,所以fb的显存部分占用的内存字节数就是800*960*4。

    2、截止目前为止分析的过程,然后编写的应用程序代码如下

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/ioctl.h>


// 宏定义
#define FBDEVICE	"/dev/fb0"

int main(void)
{
	int fd = -1, ret = -1;
	
	
	struct fb_fix_screeninfo finfo = {0};    //定义结构体变量,读取屏幕信息时用来记录屏幕不可变信息的
	struct fb_var_screeninfo vinfo = {0};    //定义结构体变量,读取屏幕信息时用来记录屏幕可变信息的
	
	// 第1步:打开设备
	fd = open(FBDEVICE, O_RDWR);
	if (fd < 0)
	{
		perror("open");
		return -1;
	}
	printf("open %s success.\n", FBDEVICE);
	
	// 第2步:获取设备的硬件信息
	ret = ioctl(fd, FBIOGET_FSCREENINFO, &finfo);    //传该命令进去,表示获取不可变的信息,记录到finfo结构体中。命令和结构体在linux/fb.h中。
	if (ret < 0)
	{
		perror("ioctl");
		return -1;
	}
	printf("smem_start = 0x%x, smem_len = %u.\n", finfo.smem_start, finfo.smem_len);    //fb占用显存的起始物理地址和使用的内存字节长度
	
	ret = ioctl(fd, FBIOGET_VSCREENINFO, &vinfo);    //传该命令进去,表示获取屏幕的可变信息,记录到vinfo中,命令和结构体在linux/fb.h中。
	if (ret < 0)
	{
		perror("ioctl");
		return -1;
	}
	printf("xres = %u, yres = %u.\n", vinfo.xres, vinfo.yres);   //可变信息,屏幕分辨率    800 480
	printf("xres_virtual = %u, yres_virtual = %u.\n", vinfo.xres_virtual, vinfo.yres_virtual);    //可变信息,虚拟分辨率  800 960  
	printf("bpp = %u.\n", vinfo.bits_per_pixel);    //可变信息,位深度 32
	
	return 0;
}