概述
编译进内核还是编译为模块
#ifdef MODULE module_init(fbmem_init); static void __exit fbmem_exit(void) { remove_proc_entry("fb", NULL); class_destroy(fb_class); unregister_chrdev(FB_MAJOR, "fb"); } module_exit(fbmem_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Framebuffer base"); #else subsys_initcall(fbmem_init); #endif
#ifdef MODULE。当定义了MODULE宏的时候,使用module_init,否则用subsys_initcall
fbmem_init函数
static int __init fbmem_init(void) { proc_create("fb", 0, NULL, &fb_proc_fops); if (register_chrdev(FB_MAJOR,"fb",&fb_fops)) printk("unable to get major %d for fb devsn", FB_MAJOR); fb_class = class_create(THIS_MODULE, "graphics"); if (IS_ERR(fb_class)) { printk(KERN_WARNING "Unable to create fb class; errno = %ldn", PTR_ERR(fb_class)); fb_class = NULL; } return 0; }
- proc_create创建fb设备在proc文件系统下的相关的东西
- register_chrdev注册fb设备,cat /proc/devices可以看到所有已经注册了的设备
- class_create创建graphics类,在/sys/class目录下会生成graphics文件夹
fb_proc_fops
static const struct file_operations fb_proc_fops = { .owner = THIS_MODULE, .open = proc_fb_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release, };
static int proc_fb_open(struct inode *inode, struct file *file) { return seq_open(file, &proc_fb_seq_ops); }
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, };
fb_proc_fops是fb在proc文件系统中的表现,cat /proc/fb可以查看内核中所有已经注册了的fb设备,实际就是执行了fb_seq_show函数
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 };
fb_read、fd_write等这些函数内部会通过函数指针的方式间接调用驱动编写者向框架注册的fb_info结构体中fb_ops类型的成员fbops中封装的函数,其本身并不直接操作硬件
registered_fb
struct fb_info *registered_fb[FB_MAX] __read_mostly;
#define FB_MAX 32 /* sufficient for now */
registered_fb指针数组就代表了内核中所有已经被注册了的fb设备的容器,最大支持32个fb设备。registered_fb数组的下表就代表了设备的设备号。
num_registered_fb
int num_registered_fb __read_mostly;
num_registered_fb表示内核中已经注册了的fb设备的个数。
struct fb_info
(1) 一个fb_info类型的变量就被抽象为一个fb设备,他里面包含了这个fb设备的所有信息
(2)成员
- int node; struct fb_info在registered_fb数组中的下标
- struct fb_var_screeninfo var; fb的可变信息
- struct fb_fix_screeninfo fix; fb的不可变信息
- struct list_head modelist; 所有支持的模式的链表
- struct fb_videomode *mode; 该fb当前的模式
- struct fb_ops *fbops; 该设备对应的操作方法(open、release、read、writr等)
- struct device *device; 父设备的device
- struct device *dev; 本设备的device
- char __iomem *screen_base; 显存的及地址
- unsigned long screen_size; 显存的字节大小
struct fb_var_screeninfo
(1)fb的可变信息结构体
(2)成员
- __u32 xres; 可视画面水平分辨率
- __u32 yres; 可视画面垂直分辨率
- __u32 xres_virtual; 虚拟缓冲区水平分辨率
- __u32 yres_virtual; 虚拟缓冲区垂直分辨率
- __u32 xoffset; 当前显存水平偏移量
- __u32 yoffset; 当前显存垂直偏移量
- __u32 bits_per_pixel; 像素深度,占多少个bit
- __u32 height; LCD的物理高度mm
- __u32 width; LCD的物理宽度mm
- /* Timing: All values in pixclocks, except pixclock (of course) */ LCD的时序参数
__u32 pixclock; /* 像素时钟 (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
(1) fb的不可变信息结构体
(2)成员
- unsigned long smem_start; LCD显存的物理起始地址
- __u32 smem_len; LCD显存的字节大小
- __u32 type; 类型
- __u32 line_length; LCD一行的长度,以字节为单位
struct fb_ops
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); ... }
该结构体中的函数指针会被上边注册字符设备时用到的struct file_operations类型的变量fb_fops中的函数指针所指向的函数直接调用
该结构体中的函数指针最终会指向驱动中实际的硬件操作函数
为什么要间接通过该结构体来实现与实际硬件操作函数的绑定呢?通过分析fb_fops中的函数指针所指向的函数可以发现,主要是为了调用实际硬件操作函数前进行一些错误判断
register_framebuffer
(1)fb驱动框架开放给驱动编写者的注册接口
(2)struct fb_videomode mode;显示模式
struct fb_videomode { const char *name; /* optional */ u32 refresh; /* optional */ u32 xres; u32 yres; u32 pixclock; u32 left_margin; u32 right_margin; u32 upper_margin; u32 lower_margin; u32 hsync_len; u32 vsync_len; u32 sync; u32 vmode; u32 flag; };
(3)fb_check_foreignness。大小端检查
(4)remove_conflicting_framebuffers。去除冲突的framebuffer
(5)num_registered_fb++;
(6)device_create
(7)fb_init_device。该函数定义在drivers/video/fbsysfs.c中,它实际是初始化fb在sysfs文件系统下的相关东西
device_create_file(fb_info->dev, &device_attrs[i]);在sysfs下创建一些文件,通过这些文件可以去访问设备
/* When cmap is added back in it should be a binary attribute * not a text one. Consideration should also be given to converting * fbdev to use configfs instead of sysfs */ static struct device_attribute device_attrs[] = { __ATTR(bits_per_pixel, S_IRUGO|S_IWUSR, show_bpp, store_bpp), __ATTR(blank, S_IRUGO|S_IWUSR, show_blank, store_blank), __ATTR(console, S_IRUGO|S_IWUSR, show_console, store_console), __ATTR(cursor, S_IRUGO|S_IWUSR, show_cursor, store_cursor), __ATTR(mode, S_IRUGO|S_IWUSR, show_mode, store_mode), __ATTR(modes, S_IRUGO|S_IWUSR, show_modes, store_modes), __ATTR(pan, S_IRUGO|S_IWUSR, show_pan, store_pan), __ATTR(virtual_size, S_IRUGO|S_IWUSR, show_virtual, store_virtual), __ATTR(name, S_IRUGO, show_name, NULL), __ATTR(stride, S_IRUGO, show_stride, NULL), __ATTR(rotate, S_IRUGO|S_IWUSR, show_rotate, store_rotate), __ATTR(state, S_IRUGO|S_IWUSR, show_fbstate, store_fbstate), #ifdef CONFIG_FB_BACKLIGHT __ATTR(bl_curve, S_IRUGO|S_IWUSR, show_bl_curve, store_bl_curve), #endif };
device_attrs数组里面的每一个__ATTR都代表/sys/class/graphics/fbx下的一个文件,并包含了它的show和store方法
(8)fb_var_to_videomode(&mode, &fb_info->var);该函数在drivers/video/modedb.c中,由struct fb_info中的struct fb_var_screeninfo可变信息中的数据填充得到显示模式
/* * Standard video mode definitions (taken from XFree86) */ static const struct fb_videomode modedb[] = { { /* 640x400 @ 70 Hz, 31.5 kHz hsync */ NULL, 70, 640, 400, 39721, 40, 24, 39, 9, 96, 2, 0, FB_VMODE_NONINTERLACED }, { /* 640x480 @ 60 Hz, 31.5 kHz hsync */ NULL, 60, 640, 480, 39721, 40, 24, 32, 11, 96, 2, 0, FB_VMODE_NONINTERLACED }, ... };
数组modedb中定义了一些标准的显示模式
(9)fb_add_videomode(&mode, &fb_info->modelist);将上面得到的显示模式mode添加到modelist链表中
(10)registered_fb[i] = fb_info;
(11)fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);该函数在drivers/video/fb_notify.c中,异步通知: 通知那些正在等待fb注册事件发生的进程
最后
以上就是热情紫菜为你收集整理的linux驱动开发扩展--framebuffer驱动框架详解的全部内容,希望文章能够帮你解决linux驱动开发扩展--framebuffer驱动框架详解所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复