前面几篇主要关注的是LCD驱动在6410平台上的实现,这一篇来说下linux帧缓冲设备驱动的上层建筑Fbmem.c文件。
1、先上第一道菜:
1.1、那我们现在来说Fbmem.c (linux2.6.28\drivers\video)文件中的应用程序访问帧缓冲设备的接口,大家对下面这些应该都不陌生吧。:
/**
* fbmem_init - init frame buffer subsystem
*
* Initialize the frame buffer subsystem.
*
* NOTE: This function is _only_ to be called by drivers/char/mem.c.
*
*/
static int __init
fbmem_init(void)
{
proc_create("fb", 0, NULL, &fb_proc_fops);看名字就知道与proc文件系统有关,其中fb_proc_fops是个file_operations的结构体,在同一个文件中定义。
static const struct file_operations fb_proc_fops = {
.owner = THIS_MODULE,
.open = proc_fb_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
对应的 open函数实例proc_fb_open源码如下:
static int proc_fb_open(struct inode *inode, struct file *file)
{
return seq_open(file, &proc_fb_seq_ops);
}
同样proc_fb_seq_ops是seq_operations类型的结构体实例。如下所示:
static const struct seq_operations proc_fb_seq_ops = {
.start = fb_seq_start,
.next = fb_seq_next,
.stop = fb_seq_stop,
.show = fb_seq_show,
};
这些函数都在这个文件中被定义,现在想想fbmem.c文件已经被我们去掉很多东西了。
if (register_chrdev(FB_MAJOR,"fb",&fb_fops))这个函数就太常见了,字符设备一出现,就肯定会出现,不过以前我们有时看到的是分开的那三个函数,现在把它们和在一起了。
其中fb_fops是file_operations结构体的实例,如下所示:
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
};
printk("unable to get major %d for fb devs\n", FB_MAJOR);
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;
}
module_init(fbmem_init);
static void __exit
fbmem_exit(void) 做和init函数相反的事。
{
remove_proc_entry("fb", NULL);
class_destroy(fb_class);
unregister_chrdev(FB_MAJOR, "fb");
}
module_exit(fbmem_exit);
2、在Fbmem.c (linux2.6.28\drivers\video)文件中还有很多函数是关于LOGO显示的,这个我们也不用关心,所以其实在这个文件中我们主要关心的就是struct file_operations fb_fops这个结构体中的函数。
2.1、简要分析几个struct file_operations fb_fops结构体中的函数:
先来看fb_read函数,源码如下:
static ssize_t
fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
unsigned long p = *ppos;
struct inode *inode = file->f_path.dentry->d_inode;
int fbidx = iminor(inode);这个函数看下面的源码,应该知道它的作用了:
static inline unsigned iminor(const struct inode *inode)
{
return MINOR(inode->i_rdev);
}
struct fb_info *info = registered_fb[fbidx];这个全局的结构数组,我们以前说过
u32 *buffer, *dst;
u32 __iomem *src;
int c, i, cnt = 0, err = 0;
unsigned long total_size;
if (!info || ! info->screen_base)
return -ENODEV;
if (info->state != FBINFO_STATE_RUNNING)
return -EPERM;
if (info->fbops->fb_read)如果定义了fb_read函数,就调用具体的read函数,也就是我们在前面说过的
fb_ops s3cfb_ops结构体中定义的函数。
return info->fbops->fb_read(info, buf, count, ppos);
struct fb_ops s3cfb_ops = {
.owner= THIS_MODULE,
.fb_check_var = s3cfb_check_var,
.fb_set_par = s3cfb_set_par,
.fb_blank = s3cfb_blank,
.fb_pan_display= s3cfb_pan_display,
.fb_setcolreg = s3cfb_setcolreg,
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
.fb_cursor = soft_cursor,
.fb_ioctl = s3cfb_ioctl,
};
total_size = info->screen_size;
if (total_size == 0)
total_size = info->fix.smem_len;
if (p >= total_size)
return 0;
if (count >= total_size)
count = total_size;
if (count + p > total_size)
count = total_size - p;
buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count,
GFP_KERNEL);
if (!buffer)
return -ENOMEM;
src = (u32 __iomem *) (info->screen_base + p);
if (info->fbops->fb_sync)
info->fbops->fb_sync(info);
while (count) {
c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
dst = buffer;
for (i = c >> 2; i--; )
*dst++ = fb_readl(src++);
if (c & 3) {
u8 *dst8 = (u8 *) dst;
u8 __iomem *src8 = (u8 __iomem *) src;
for (i = c & 3; i--;)
*dst8++ = fb_readb(src8++);
src = (u32 __iomem *) src8;
}
if(copy_to_user(buf, buffer, c)) {
err = -EFAULT;
break;
}
*ppos += c;
buf += c;
cnt += c;
count -= c;
}
kfree(buffer);
return (err) ? err : cnt;
}
2.2、fb_ioctl函数:源码如下:
static long fb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
__acquires(&info->lock)
__releases(&info->lock)
{
struct inode *inode = file->f_path.dentry->d_inode;
int fbidx = iminor(inode);
struct fb_info *info;
long ret;
info = registered_fb[fbidx];
mutex_lock(&info->lock);
ret = do_fb_ioctl(info, cmd, arg);
此函数源码如下:
static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
unsigned long arg)
{
struct fb_ops *fb;
struct fb_var_screeninfo var;
struct fb_fix_screeninfo fix;
struct fb_con2fbmap con2fb;
struct fb_cmap_user cmap;
struct fb_event event;
void __user *argp = (void __user *)arg;
long ret = 0;
fb = info->fbops;
if (!fb)
return -ENODEV;
switch (cmd) {
case FBIOGET_VSCREENINFO: 获得可变的屏幕参数
ret = copy_to_user(argp, &info->var,
sizeof(var)) ? -EFAULT : 0;
break;
case FBIOPUT_VSCREENINFO:设置可变的屏幕参数
if (copy_from_user(&var, argp, sizeof(var))) {
ret = -EFAULT;
break;
}
acquire_console_sem();
info->flags |= FBINFO_MISC_USEREVENT;
ret = fb_set_var(info, &var);
info->flags &= ~FBINFO_MISC_USEREVENT;
release_console_sem();
if (ret == 0 && copy_to_user(argp, &var, sizeof(var)))
ret = -EFAULT;
break;
case FBIOGET_FSCREENINFO:获得固定的屏幕参数设置
ret = copy_to_user(argp, &info->fix,
sizeof(fix)) ? -EFAULT : 0;
break;
case FBIOPUTCMAP:设置颜色表
if (copy_from_user(&cmap, argp, sizeof(cmap)))
ret = -EFAULT;
else
ret = fb_set_user_cmap(&cmap, info);
break;
case FBIOGETCMAP: 获得颜色表
if (copy_from_user(&cmap, argp, sizeof(cmap)))
ret = -EFAULT;
else
ret = fb_cmap_to_user(&info->cmap, &cmap);
break;
case FBIOPAN_DISPLAY:
if (copy_from_user(&var, argp, sizeof(var))) {
ret = -EFAULT;
break;
}
acquire_console_sem();
ret = fb_pan_display(info, &var);
release_console_sem();
if (ret == 0 && copy_to_user(argp, &var, sizeof(var)))
ret = -EFAULT;
break;
case FBIO_CURSOR:
ret = -EINVAL;
break;
case FBIOGET_CON2FBMAP:
if (copy_from_user(&con2fb, argp, sizeof(con2fb)))
ret = -EFAULT;
else if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)
ret = -EINVAL;
else {
con2fb.framebuffer = -1;
event.info = info;
event.data = &con2fb;
fb_notifier_call_chain(FB_EVENT_GET_CONSOLE_MAP,
&event);
ret = copy_to_user(argp, &con2fb,
sizeof(con2fb)) ? -EFAULT : 0;
}
break;
case FBIOPUT_CON2FBMAP:
if (copy_from_user(&con2fb, argp, sizeof(con2fb))) {
ret = -EFAULT;
break;
}
if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES) {
ret = -EINVAL;
break;
}
if (con2fb.framebuffer < 0 || con2fb.framebuffer >= FB_MAX) {
ret = -EINVAL;
break;
}
if (!registered_fb[con2fb.framebuffer])
request_module("fb%d", con2fb.framebuffer);
if (!registered_fb[con2fb.framebuffer]) {
ret = -EINVAL;
break;
}
event.info = info;
event.data = &con2fb;
ret = fb_notifier_call_chain(FB_EVENT_SET_CONSOLE_MAP,
&event);
break;
case FBIOBLANK:
acquire_console_sem();
info->flags |= FBINFO_MISC_USEREVENT;
ret = fb_blank(info, arg);
info->flags &= ~FBINFO_MISC_USEREVENT;
release_console_sem();
break;;
default:
if (fb->fb_ioctl == NULL)
ret = -ENOTTY;
else
ret = fb->fb_ioctl(info, cmd, arg);
}
return ret;
}
mutex_unlock(&info->lock);
return ret;
}
fb_mem.c文件分析到这里差不多也结束了,当然,我们还有很多没分析,只是分析了一小部分,但是这个文件的大致结构和作用我们应该清楚了。
在这个文件中其他重要的函数,我们都没有分析,如:fb_mmap、register_framebuffer、unregister_framebuffer函数等等,后面这两个函数,我们前面有涉及,所以,要走的路还有很长。