注:我的博客都是我在学习时候为了增强我对一些内容的印象而写的,不喜勿喷
一、framebuffer驱动相关基础
1.驱动框架部分涉及的文件
(1)driver/video/fbmem.c
(2)driver/video/fbsys.c
(3)driver/video/fb_notify.c
2.相关的两个重要结构体。
(1)fb_fix_screeninfo结构体,framebuffer不可变参数的结构体
struct fb_fix_screeninfo {
char id[16]; /* identification string eg "TT Builtin" */
//显存的物理地址
unsigned long smem_start;
__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 reserved[3]; /* Reserved for future compatibility */
};
(2)fb_var_screeninfo结构体,framebuffer可变参数的结构体
struct fb_var_screeninfo {
//屏幕的可视分辨率
__u32 xres; /* visible resolution */
__u32 yres;
//屏幕的虚拟分辨率
__u32 xres_virtual; /* virtual resolution */
__u32 yres_virtual;
//x,y相对于虚拟分辨率的偏移量
__u32 xoffset; /* offset from virtual to visible */
__u32 yoffset; /* resolution */
//像素深度,bpp
__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 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 */
};
(3)写应用我们可以读取fb的可变信息和不可变信息。读取方法:
使用ioctl函数。传入命令FBIOGET_VSCREENINFO或者FBIOGET_FSCREENINFO宏定义。记得包括/linux/fb.h头文件。命令所带的参数就是传入相应的结构体变量地址。
例:ioctl(fd, FBIOGET_FSCREENINFO, &fbinfo_f);
fbinfo_f这个变量是我们自己定义的( struct fb_fix_screeninfo fbinfo_f = {0}; )
二、驱动框架分析
(1)fbmem_init函数分析(driver/video/fbmem.c)
static int __init fbmem_init(void)
{
//在proc目录下创建一个fb文件。
proc_create("fb", 0, NULL, &fb_proc_fops);
//注册一个字符设备,主设备号是FB_MAJOR(29),并且绑定了fb_fops文件操作方法。
if (register_chrdev(FB_MAJOR,"fb",&fb_fops))
printk("unable to get major %d for fb devs\n", FB_MAJOR);
//在/sys/class目录下创建一个类graphics
fb_class = class_create(THIS_MODULE, "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_ops操作方法结构体
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, //打开fb文件的操作方法
.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
};
(2)看一个fb_open具体的操作方法
1)首先得明白,内核是用一个数组来管理已经注册的framebuffer的。也就是registered_fb[fbidx]; fbidx最大值就是32.
2)struct fb_info *registered_fb[FB_MAX]; registered_fb是一个指针数组。最大能注册32个framebuffer设备。
3)int num_registered_fb; 也就是用来记录已经注册了多少个framebuffer设备
static int fb_open(struct inode *inode, struct file *file)
__acquires(&info->lock) __releases(&info->lock)
{
//inode就是我们打开的那个fb文件的文件节点,使用iminor宏得到次设备号
int fbidx = iminor(inode);
struct fb_info *info;
int res = 0;
if (fbidx >= FB_MAX)
return -ENODEV;
//得到得到次设备号,在去已经数组里面找到那个framebuffer设备
info = registered_fb[fbidx];
if (!info)
request_module("fb%d", fbidx);
info = registered_fb[fbidx];
if (!info)
return -ENODEV;
mutex_lock(&info->lock);
if (!try_module_get(info->fbops->owner)) {
res = -ENODEV;
goto out;
}
file->private_data = info;
//判断如果打开的framebuffer文件的fbops->fb_open不为空的话就执行info->fbops->fb_open(info,1);这个就是驱动工程师自己写的open函数(在注册时候放进去的那个结构体里面的fbops)
if (info->fbops->fb_open) {
res = info->fbops->fb_open(info,1);
if (res)
module_put(info->fbops->owner);
}
#ifdef CONFIG_FB_DEFERRED_IO
if (info->fbdefio)
fb_deferred_io_open(info, inode, file);
#endif
out:
mutex_unlock(&info->lock);
return res;
}
(3)register_framebuffer函数分析
int register_framebuffer(struct fb_info *fb_info)
{
int i;
struct fb_event event;
struct fb_videomode mode;
/****************判断fb_info的参数是否正确**************/
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));
/****************判断fb_info的参数是否正确**************/
//判断正确说明这个可以注册这个framebuffer设备,则 num_registered_fb++
num_registered_fb++;
//遍历registered_fb指针数组,如果registered_fb[i]为空,则记录下i的值
for (i = 0 ; i < FB_MAX; i++)
if (!registered_fb[i])
break;
//标记framebuffer里面的node
fb_info->node = i;
//初始化互斥锁
mutex_init(&fb_info->lock);
mutex_init(&fb_info->mm_lock);
//在/sys/class/graphics目录下创建要注册的device
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); //这个初始化函数比较重要。下面会分析
//下面这一坨pixmap不知道这个参数是干嘛的。
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_info里面的可变参数,并且填充mode
fb_var_to_videomode(&mode, &fb_info->var);
//把屏幕显示的模式注册到b_info->modelist链表中
fb_add_videomode(&mode, &fb_info->modelist);
//最佳之绝唱,一句话注册framebuffer设备
registered_fb[i] = fb_info;
//event不知道是干嘛的。
event.info = fb_info;
if (!lock_fb_info(fb_info))
return -ENODEV;
//内核设计的异步通知,告诉内核有framebuffer要注册了。
fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);
unlock_fb_info(fb_info);
return 0;
}
注:register_framebuffer函数就是驱动工程师在写lcd驱动注册时候要调用的函数。