Linux驱动之Framebuffer子系统基础知识
1、Linux Framebuffer概述
Framebuffer驱动在Linux内核中用于子系统最重要的显示输出,以该驱动为基础,Linux设备才能向用户展现一个色彩斑斓的世界,对于PC而言,就是显卡驱动,对于嵌入式设备,就是显示控制器和LCD模组驱动。
Framebuffer设备是一个字符设备,在文件系统中的设备节点通常为/dev/fbX,当一个系统中有多个显示设备时,依次使用/de/fb0、/dev/fb1等来表示。在Android系统中,该类设备的主设备号是29,Framebuffer设备也叫做"帧缓冲设备"。
Frambuffer的显示框架如下所示:
2、Framebuffer数据结构
(1)fb_info结构体
fb_info结构体是最重要的结构体,它代表着Framebuffer驱动,该结构体的定义如下:
struct fb_info { atomic_t count; 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 union { char __iomem *screen_base; /* Virtual address */ char *screen_buffer; }; 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 similar 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; bool skip_vt_switch; /* no VT switch on suspend/resume required */ };
fb_info结构体记录了帧缓冲设备的全部信息,包括设备的设置参数、状态以及操作函数指针,对于每一个帧缓冲设备都必须对应一个fb_info结构体实例。
(2)fb_ops结构体
该结构体是fb_info结构体中的一个成员变量,指向显示操作的函数指针,这些函数需要驱动程序开发人去编写实现,该结构体的定义如下:
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); /* 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); /* called at KDB enter and leave time to prepare the console */ int (*fb_debug_enter)(struct fb_info *info); int (*fb_debug_leave)(struct fb_info *info); #ifdef CONFIG_ARCH_HISI_BVT #ifdef CONFIG_DMA_SHARED_BUFFER /* Export the frame buffer as a dmabuf object */ struct dma_buf *(*fb_dmabuf_export)(struct fb_info *info); #endif #endif };
(3)fb_var_screeninfo结构体
fb_var_screeninfo结构体也是fb_info结构体的成员变量,该结构体记录用户可修改的显示控制器参数,包括了屏幕的分辨率和每个像素点的比特数,该结构体的定义如下:
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 = color, 1 = grayscale, */ /* >1 = FOURCC */ 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 colorspace; /* colorspace for FOURCC-based modes */ __u32 reserved[4]; /* Reserved for future compatibility */ };
(4)fb_fix_screeninfo结构体
fb_fix_screeninfo结构体也是fb_info结构体的成员,该结构体中记录了用户不能修改的显示控制器的参数,比如说屏幕缓冲区的物理地址、长度等,当使用帧缓冲设备进行映射操作的时候,就是从fb_fix_screeninfo结构体中获取缓冲区物理地址,该结构体的定义如下:
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 capabilities; /* see FB_CAP_* */ __u16 reserved[2]; /* Reserved for future compatibility */ };
(5)fb_bitfield结构体
fb_bitfield结构体描述每一像素缓冲区的组织方式,包括域偏移、位域长度和MSB指示,该结构体的定义如下:
struct fb_bitfield { __u32 offset; /* beginning of bitfield */ __u32 length; /* length of bitfield */ __u32 msb_right; /* != 0 : Most significant bit is */ /* right */ };
(6)文件操作结构体
帧缓冲设备作为一种字符设备,文件操作结构体定义于/linux/drivers/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 .llseek = default_llseek, };
帧缓冲设备驱动的文件操作接口函数已经在fbmem.c中被统一实现了,一般不需要驱动工程师再编写。
3、Framebuffer驱动
Framebuffer驱动的程序结构如下所示:
Framebuffe的设备文件操作函数在fbmem.c中实现,而特定于帧缓冲设备fb_info结构体的注册、注销以及fb_info成员的维护,尤其是fb_ops成员函数的实现,则是在特定的xxxfb.c源码中去实现,其中,fb_ops中的成员函数最终会操作显示控制器以及LCD模组上的寄存器,进而实现对显示设备的控制以及数据的显示。
在嵌入式系统中,常在RAM中分配一块显示缓冲区,也就是常说的显存,用来存放要输出到显示设备上的显示数据,显示数据一般会采用DMA的方式来传输。
4、Android系统对Framebuffer的使用
Android系统上层应用要想使用Framebuffer子系统硬件,需要符合HAL架构的,Android显示子系统的架构如下:
显示子系统的HAL层有三个模板,其中Gralloc模块是显示子系统的主模块,主要负责往Framebuffer显存传送数据,Graphics driver模块是3D显示HAL模块,其负责调用3D引擎计算处理3D图像数据,Overlay HAL模块负责视频动态图像数据的处理。
在Android Framebuffer显示子系统中,有一个核心组件SurfaceFlinger,它是显示子系统的Service进程,它将各种应用程序的2D和3D surface进行组合、合并,最终得到一个main surface数据送入显存,简单来说,SurfaceFlinger就像是画布,它并不关心画上去的内容,只是执行合成功能,当然需要根据画的位置、大小以及效果等参数。
接下来,应了解Android显示子系统的Client/Server架构,服务端(SurfaceFlinger)负责surface的合成等处理工作,客户端根据SurfaceFlinger所提供的接口给上层各自操作surface,并向服务端发送消息完成实际显示工作,服务端主要由C++代码编写而成,客户端代码分成两部分,一部分由Java提供的供应用程序使用的API,另一部分则是由C++编写的底层实现,架构如下所示:
在架构图可以看到有一个Binder组件,其底层技术是Android系统专有的Binder驱动,是Android进程间通信机制,在这里,主要是负责调用显示功能的客户进程与SurfaceFlinger服务进程之间的通信。
参考:
《Android驱动开发权威指南》