帧缓冲 framebuffer : 是linux系统为显示设备提供的一个接口。
帧缓冲是显示缓冲区的抽象,而不需要考虑底层硬件的差异,允许上层应用在图形模式下,直接对显示缓冲区进行读写操作。
屏幕上的显示点,与显示缓冲区一一对应,可以通过读写显示缓冲区的操作,来控制屏幕上的显示输出。、
帧缓冲设备为标准字符设备,主设备号29,对应于/dev/fb%d设备文件。
1. fb_info 结构体:
是帧缓冲设备最关键的一个数据结构体,简称“FBI”。
FBI中包括了关于帧缓冲设备属性和操作的完整描述,记录了帧缓冲设备的全部信息,包括设备的设置参数、状态以及操作函数指针。每一个帧缓冲设备都必须对应一个FBI。
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 */ //图像硬件mapper
struct fb_pixmap sprite; /* Cursor hardware mapper */ //光标硬件mapper
struct fb_cmap cmap; /* Current cmap */ //目前的颜色表
struct list_head modelist; /* mode list */
struct fb_videomode *mode; /* current mode */ //目前的video模式
#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; //fb_ops, 帧缓冲操作。指向底层操作的函数的指针
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 */ //图块blitting
#endif
char __iomem *screen_base; /* Virtual address */ //虚拟基地址
unsigned long screen_size; /* Amount of ioremapped VRAM or 0 */ //ioremapped的虚拟内存大小。
void *pseudo_palette; /* Fake palette of 16 colors */ //伪16色颜色表。
#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;
};
2. fb_ops 结构体:
FBI的成员变量 fbops 为 指向底层操作的行数的指针,这些函数是需要驱动程序开发人员编写的。
/*
* Frame buffer operations
*
* LOCKING NOTE: those functions must _ALL_ be called with the console
* semaphore held, this is the only suitable locking mechanism we have
* in 2.6. Some may be called at interrupt time at this point though.
*
* The exception to this is the debug related hooks. Putting the fb
* into a debug state (e.g. flipping to the kernel console) and restoring
* it must be done in a lock-free manner, so low level drivers should
* keep track of the initial console (if applicable) and may need to
* perform direct, unlocked hardware writes in these hooks.
*/
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);
//根据info->var设置video模式,使用户设置的参数在硬件上有效
/* set the video mode according to info->var */
int (*fb_set_par)(struct fb_info *info);
//设置 color 寄存器
/* set color register */
int (*fb_setcolreg)(unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp, struct fb_info *info);
//批量设置 color 寄存器。
/* 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 显示
/* 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); //等待blit空闲
/* perform fb specific ioctl (optional) */
int (*fb_ioctl)(struct fb_info *info, unsigned int cmd,
unsigned long arg); //fb特定的 ioctl
/* Handle 32bit compat ioctl (optional) */
int (*fb_compat_ioctl)(struct fb_info *info, unsigned cmd,
unsigned long arg); //32位的compat ioctl
/* perform fb specific mmap */
int (*fb_mmap)(struct fb_info *info, struct vm_area_struct *vma); //fb特定的mmap
/* 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);
};
3. fb_var_screeninfo 和 fb_fix_screeninfo 结构体
fb_var_screeninfo 记录用户可修改的显示控制器参数,包括屏幕分辨率和每个像素点的比特数。
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 */ //定义每个像素点用多少个bit表示
__u32 grayscale; /* != 0 Graylevels instead of colors */ //非零时指灰度
//fb 缓存的 R / G / B 值
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_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 */ // 1行的字节数
unsigned long mmio_start; /* Start of Memory Mapped I/O */ //内存映射I/O的开始位置
/* (physical address) */
__u32 mmio_len; /* Length of Memory Mapped I/O */ //内存映射I/O的长度
__u32 accel; /* Indicate to driver which */
/* specific chip/card we have */
__u16 reserved[3]; /* Reserved for future compatibility */ //保留
};
4. fb_bitfield 结构体:
用来表示 R, G, B 的位域,描述每一个像素显示缓冲区的组织方式,包含位域偏移,位于长度 和 MSB指示。
/* Interpretation of offset for color fields: All offsets are from the right,
* inside a "pixel" value, which is exactly 'bits_per_pixel' wide (means: you
* can use the offset as right argument to <<). A pixel afterwards is a bit
* stream and is written to video memory as that unmodified.
*
* For pseudocolor: offset and length should be the same for all color
* components. Offset specifies the position of the least significant bit
* of the pallette index in a pixel value. Length indicates the number
* of available palette entries (i.e. # of entries = 1 << length).
*/
struct fb_bitfield {
__u32 offset; /* beginning of bitfield */
__u32 length; /* length of bitfield */
__u32 msb_right; /* != 0 : Most significant bit is */
/* right */
};
5. fb_cmap 结构体:
记录设备无关的颜色表信息,用户空间可通过 ioctl() 的 FBIOGETCMAP 和 FBIOPUTCMAP 命令读取或设定颜色表。
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 */
};
6. 文件操作结构体 fb_fops :
定义于 linux/drivers/video/fbmem.c 文件中。 跟上面的 fb_ops 不同。
帧缓冲设备驱动的文件操作接口函数 统一在 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,
};
7. 注册和注销帧缓冲设备。
如果注册的帧缓冲设备数超过了 FB_MAX, 则返回 -ENXIO, 注册成功则返回0.
/**
* register_framebuffer - registers a frame buffer device
* @fb_info: frame buffer info structure
*
* Registers a frame buffer device @fb_info.
*
* Returns negative errno on error, or zero for success.
*
*/
int
register_framebuffer(struct fb_info *fb_info)
{
int i;
struct fb_event event;
struct fb_videomode mode;
if (num_registered_fb == FB_MAX)
return -ENXIO;
if (fb_check_foreignness(fb_info))
return -ENOSYS;
remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id,
fb_is_primary_device(fb_info));
num_registered_fb++;
for (i = 0 ; i < FB_MAX; i++)
if (!registered_fb[i])
break;
fb_info->node = i;
mutex_init(&fb_info->lock);
mutex_init(&fb_info->mm_lock);
fb_info->dev = device_create(fb_class, fb_info->device,
MKDEV(FB_MAJOR, i), NULL, "fb%d", i);
if (IS_ERR(fb_info->dev)) {
/* Not fatal */
printk(KERN_WARNING "Unable to create device for framebuffer %d; errno = %ld\n", i, PTR_ERR(fb_info->dev));
fb_info->dev = NULL;
} else
fb_init_device(fb_info);
if (fb_info->pixmap.addr == NULL) {
fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL);
if (fb_info->pixmap.addr) {
fb_info->pixmap.size = FBPIXMAPSIZE;
fb_info->pixmap.buf_align = 1;
fb_info->pixmap.scan_align = 1;
fb_info->pixmap.access_align = 32;
fb_info->pixmap.flags = FB_PIXMAP_DEFAULT;
}
}
fb_info->pixmap.offset = 0;
if (!fb_info->pixmap.blit_x)
fb_info->pixmap.blit_x = ~(u32)0;
if (!fb_info->pixmap.blit_y)
fb_info->pixmap.blit_y = ~(u32)0;
if (!fb_info->modelist.prev || !fb_info->modelist.next)
INIT_LIST_HEAD(&fb_info->modelist);
fb_var_to_videomode(&mode, &fb_info->var);
fb_add_videomode(&mode, &fb_info->modelist);
registered_fb[i] = fb_info;
event.info = fb_info;
if (!lock_fb_info(fb_info))
return -ENODEV;
fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);
unlock_fb_info(fb_info);
return 0;
}
/**
* unregister_framebuffer - releases a frame buffer device
* @fb_info: frame buffer info structure
*
* Unregisters a frame buffer device @fb_info.
*
* Returns negative errno on error, or zero for success.
*
* This function will also notify the framebuffer console
* to release the driver.
*
* This is meant to be called within a driver's module_exit()
* function. If this is called outside module_exit(), ensure
* that the driver implements fb_open() and fb_release() to
* check that no processes are using the device.
*/
int
unregister_framebuffer(struct fb_info *fb_info)
{
struct fb_event event;
int i, ret = 0;
i = fb_info->node;
if (!registered_fb[i]) {
ret = -EINVAL;
goto done;
}
if (!lock_fb_info(fb_info))
return -ENODEV;
event.info = fb_info;
ret = fb_notifier_call_chain(FB_EVENT_FB_UNBIND, &event);
unlock_fb_info(fb_info);
if (ret) {
ret = -EINVAL;
goto done;
}
if (fb_info->pixmap.addr &&
(fb_info->pixmap.flags & FB_PIXMAP_DEFAULT))
kfree(fb_info->pixmap.addr);
fb_destroy_modelist(&fb_info->modelist);
registered_fb[i]=NULL;
num_registered_fb--;
fb_cleanup_device(fb_info);
device_destroy(fb_class, MKDEV(FB_MAJOR, i));
event.info = fb_info;
fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event);
/* this may free fb info */
if (fb_info->fbops->fb_destroy)
fb_info->fbops->fb_destroy(fb_info);
done:
return ret;
}