Framebuffer驱动程序框架
首先framebuffer是一个字符驱动设备,它分为上下两层:
- fbmem.c:中间承上启下
- 实现、注册file_operation结构体
- 把App的调用向下转发到具体的硬件驱动程序
- xxxx_fb.c:硬件相关的驱动程序
- 实现、注册fb_info结构体
- 实现硬件操作
在文件drivers/video/fbdev/core/fbmem.c中,有fbmem_init函数
static int __init
fbmem_init(void)
{
proc_create("fb", 0, NULL, &fb_proc_fops);
if (register_chrdev(FB_MAJOR,"fb",&fb_fops)) //注册fb设备,注册了fb_fops结构体
printk("unable to get major %d for fb devs\n", FB_MAJOR);
fb_class = class_create(THIS_MODULE, "graphics"); //创建了graphics类
if (IS_ERR(fb_class)) {
printk(KERN_WARNING "Unable to create fb class; errno = %ld\n", PTR_ERR(fb_class));
fb_class = NULL;
}
return 0;
}
其中这个fb_fops是这样的:
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,
};
所以对于App来说当他对/dev/fbx文件操作的时候,其实就是调用了fb_fops结构体的各类操作
看一下fb_open操作:
static int
fb_open(struct inode *inode, struct file *file)
__acquires(&info->lock)
__releases(&info->lock)
{
int fbidx = iminor(inode); //获取了次设备号
struct fb_info *info;
int res = 0;
info = get_fb_info(fbidx); //通过fbidx获取fb_info结构体,它来自registered_fb数组
if (!info) {
request_module("fb%d", fbidx);
info = get_fb_info(fbidx);
if (!info)
return -ENODEV;
}
//...
file->private_data = info;
if (info->fbops->fb_open) { //如果info->fbops->fb_open函数存在
res = info->fbops->fb_open(info,1); //就调用info->fbops->fb_open函数
if (res)
module_put(info->fbops->owner);
}
//...
}
再来看一下read函数:
static ssize_t
fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
unsigned long p = *ppos; //这里初始化了偏移量
struct fb_info *info = file_fb_info(file); //从文件中获得fb_info结构体
u8 *buffer, *dst;
u8 __iomem *src;
int c, cnt = 0, err = 0;
unsigned long total_size;
//...
if (info->fbops->fb_read) //如果fbops有fb_read,就直接调用并返回
return info->fbops->fb_read(info, buf, count, ppos);
total_size = info->screen_size;
//.....
buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count,
GFP_KERNEL); //分配buffer
if (!buffer)
return -ENOMEM;
src = (u8 __iomem *) (info->screen_base + p); //src是基地址加上p的偏移量
if (info->fbops->fb_sync)
info->fbops->fb_sync(info);
while (count) {
c = (count > PAGE_SIZE) ? PAGE_SIZE : count; //c是一个PAGE_SIZE或者count
dst = buffer;
fb_memcpy_fromfb(dst, src, c); //从src复制到dst中,dst
dst += c;
src += c;
if (copy_to_user(buf, buffer, c)) { //把数据发送到用户buffer
err = -EFAULT;
break;
}
*ppos += c;
buf += c;
cnt += c;
count -= c;
}
//.....
}
fb_info结构体
struct fb_info {
atomic_t count;
int node; //次设备号
int flags;
struct mutex lock; /* Lock for open/release/ioctl funcs 用于open、release、ioctrl功能的锁 */
struct mutex mm_lock; /* Lock for fb_mmap and smem_* fields */
struct fb_var_screeninfo var; /* Current var LCD可变参数 */
struct fb_fix_screeninfo fix; /* Current fix LCD固定参数 */
struct fb_monspecs monspecs; /* Current Monitor specs LCD显示器标准 */
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 当前的显示模式 */
#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 图块blitting */
#endif
union {
char __iomem *screen_base; /* Virtual address 虚拟地址 */
char *screen_buffer;
};
unsigned long screen_size; /* Amount of ioremapped VRAM or 0 LCD IO映射的虚拟内存大小 */
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 LCD挂起或复位的状态 */
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_var_screeninfo和fb_fix_screeninfo两个结构体跟LCD硬件属性相关
- fb_var_screeninfo代表可修改的LCD显示参数,如分辨率和像素比特数。
- fb_fix_screeninfo代表不可修改的LCD属性参数,如显示内存的物理地址和长度等。
- 另外一个重要成员是fb_ops,其是LCD底层硬件操作接口集。
如何编写Framebuffer驱动程序
分配fb_info
使用framebuffer_alloc分配fb_info
设置fb_info
设置fb_info的var、fbops、硬件相关的操作
注册fb_info
使用register_framebuffer