一、什麼是framebuffer?node
(1)framebuffer幀緩衝(一屏幕數據)(簡稱fb)是linux內核中虛擬出的一個設備,framebuffer嚮應用層提供一個統一標準接口的顯示設備。幀緩衝(framebuffer)linux
是Linux爲顯示設備提供的一個接口,把顯存抽象後的一種設備,他容許上層應用程序在圖形模式下直接對顯示緩衝區進行讀寫操做。這種操做是抽象的,統一的。用數組
戶沒必要關心物理顯存的位置、換頁機制等等具體細節。這些都是由Framebuffer設備驅動來完成的。數據結構
(2)從驅動來看,fb是一個典型的字符設備,並且建立了一個類/sys/class/graphicsapp
(3)framebuffer的使用框架
1):打開framebuffer設備文件: /dev/fb0
異步
2):獲取framebuffer設備信息 #include <linux/fb.h>ide
3):mmap作映射函數
4):填充framebufferui
FB驅動框架相關代碼:drivers\video 這個目錄中
二、相關的數據結構
1 struct fb_info { // 用來描述一個fb設備的結構體 2 int node; // 用來表示該fb設備的次設備號 3 int flags; // 一個標誌位 4 struct mutex lock; /* Lock for open/release/ioctl funcs */ 5 struct mutex mm_lock; /* Lock for fb_mmap and smem_* fields */ 6 struct fb_var_screeninfo var; /* Current var */ // fb的可變參數 7 struct fb_fix_screeninfo fix; /* Current fix */ // fb的不可變參數 8 struct fb_monspecs monspecs; /* Current Monitor specs */ 9 struct work_struct queue; /* Framebuffer event queue */ 10 struct fb_pixmap pixmap; /* Image hardware mapper */ 11 struct fb_pixmap sprite; /* Cursor hardware mapper */ 12 struct fb_cmap cmap; /* Current cmap */ 13 struct list_head modelist; /* mode list */ 14 struct fb_videomode *mode; /* current mode */ 15 16 #ifdef CONFIG_FB_BACKLIGHT 17 /* assigned backlight device */ 18 /* set before framebuffer registration, 19 remove after unregister */ 20 struct backlight_device *bl_dev; 21 22 /* Backlight level curve */ 23 struct mutex bl_curve_mutex; 24 u8 bl_curve[FB_BACKLIGHT_LEVELS]; 25 #endif 26 #ifdef CONFIG_FB_DEFERRED_IO 27 struct delayed_work deferred_work; 28 struct fb_deferred_io *fbdefio; 29 #endif 30 31 struct fb_ops *fbops; // 該設備對應的操做方法 open write read ..... 32 struct device *device; /* This is the parent */ // fb設備的父設備 33 struct device *dev; /* This is this fb device */ // 本設備的device 34 int class_flag; /* private sysfs flags */ 35 #ifdef CONFIG_FB_TILEBLITTING 36 struct fb_tile_ops *tileops; /* Tile Blitting */ 37 #endif 38 char __iomem *screen_base; /* Virtual address */ // 這個就是咱們的LCD的顯存地址(虛擬地址) 39 unsigned long screen_size; /* Amount of ioremapped VRAM or 0 */ // LCD顯存的字節大小 40 void *pseudo_palette; /* Fake palette of 16 colors */ 41 #define FBINFO_STATE_RUNNING 0 42 #define FBINFO_STATE_SUSPENDED 1 43 u32 state; /* Hardware state i.e suspend */ 44 void *fbcon_par; /* fbcon use-only private area */ 45 /* From here on everything is device dependent */ 46 void *par; 47 /* we need the PCI or similiar aperture base/size not 48 smem_start/size as smem_start may just be an object 49 allocated inside the aperture so may not actually overlap */ 50 struct apertures_struct { 51 unsigned int count; 52 struct aperture { 53 resource_size_t base; 54 resource_size_t size; 55 } ranges[0]; 56 } *apertures; 57 };
1 struct fb_var_screeninfo { 2 __u32 xres; /* visible resolution */ // 水平分辨率 3 __u32 yres; // 垂直分辨率 4 __u32 xres_virtual; /* virtual resolution */ // 虛擬水平分辨率 5 __u32 yres_virtual; // 虛擬垂直分辨率 6 __u32 xoffset; /* offset from virtual to visible */// 當前顯存水平偏移量 7 __u32 yoffset; /* resolution */ // 當前顯存垂直偏移量 8 9 __u32 bits_per_pixel; /* guess what */ // 像素深度 10 __u32 grayscale; /* != 0 Graylevels instead of colors */ 11 12 struct fb_bitfield red; /* bitfield in fb mem if true color, */ 13 struct fb_bitfield green; /* else only length is significant */ 14 struct fb_bitfield blue; 15 struct fb_bitfield transp; /* transparency */ 16 17 __u32 nonstd; /* != 0 Non standard pixel format */ 18 19 __u32 activate; /* see FB_ACTIVATE_* */ 20 21 __u32 height; /* height of picture in mm */ // LCD的物理高度mm 22 __u32 width; /* width of picture in mm */ // LCD的物理寬度mm 23 24 __u32 accel_flags; /* (OBSOLETE) see fb_info.flags */ 25 26 /* Timing: All values in pixclocks, except pixclock (of course) */ 27 __u32 pixclock; /* pixel clock in ps (pico seconds) */ // 像素時鐘 28 29 // 下面這六個就是LCD的時序參數 30 __u32 left_margin; /* time from sync to picture */ 31 __u32 right_margin; /* time from picture to sync */ 32 __u32 upper_margin; /* time from sync to picture */ 33 __u32 lower_margin; 34 __u32 hsync_len; /* length of horizontal sync */ 35 __u32 vsync_len; /* length of vertical sync */ 36 ////////////////////////////////////////////////////// 37 38 __u32 sync; /* see FB_SYNC_* */ 39 __u32 vmode; /* see FB_VMODE_* */ 40 __u32 rotate; /* angle we rotate counter clockwise */ 41 __u32 reserved[5]; /* Reserved for future compatibility */ 42 };
1 struct fb_fix_screeninfo { 2 char id[16]; /* identification string eg "TT Builtin" */ 3 unsigned long smem_start; /* Start of frame buffer mem */ // LCD顯存的起始地址(物理地址) 4 /* (physical address) */ 5 __u32 smem_len; /* Length of frame buffer mem */ // LCD顯存的字節大小 6 __u32 type; /* see FB_TYPE_* */ // 類型 7 __u32 type_aux; /* Interleave for interleaved Planes */ 8 __u32 visual; /* see FB_VISUAL_* */ 9 __u16 xpanstep; /* zero if no hardware panning */ 10 __u16 ypanstep; /* zero if no hardware panning */ 11 __u16 ywrapstep; /* zero if no hardware ywrap */ 12 __u32 line_length; /* length of a line in bytes */ // LCD一行的長度 (以字節爲單位) 13 unsigned long mmio_start; /* Start of Memory Mapped I/O */ 14 /* (physical address) */ 15 __u32 mmio_len; /* Length of Memory Mapped I/O */ 16 __u32 accel; /* Indicate to driver which */ 17 /* specific chip/card we have */ 18 __u16 reserved[3]; /* Reserved for future compatibility */ 19 };
1 struct fb_pixmap { 2 u8 *addr; /* pointer to memory */ 3 u32 size; /* size of buffer in bytes */ 4 u32 offset; /* current offset to buffer */ 5 u32 buf_align; /* byte alignment of each bitmap */ 6 u32 scan_align; /* alignment per scanline */ 7 u32 access_align; /* alignment per read/write (bits) */ 8 u32 flags; /* see FB_PIXMAP_* */ 9 u32 blit_x; /* supported bit block dimensions (1-32)*/ 10 u32 blit_y; /* Format: blit_x = 1 << (width - 1) */ 11 /* blit_y = 1 << (height - 1) */ 12 /* if 0, will be set to 0xffffffff (all)*/ 13 /* access methods */ 14 void (*writeio)(struct fb_info *info, void __iomem *dst, void *src, unsigned int size); 15 void (*readio) (struct fb_info *info, void *dst, void __iomem *src, unsigned int size); 16 };
1 struct fb_videomode { 2 const char *name; /* optional */ 3 u32 refresh; /* optional */ 4 u32 xres; 5 u32 yres; 6 u32 pixclock; 7 u32 left_margin; 8 u32 right_margin; 9 u32 upper_margin; 10 u32 lower_margin; 11 u32 hsync_len; 12 u32 vsync_len; 13 u32 sync; 14 u32 vmode; 15 u32 flag; 16 };
1 struct fb_ops { // 這個fb_ops 就是咱們fb設備的使用的 fops 2 /* open/release and usage marking */ 3 struct module *owner; 4 int (*fb_open)(struct fb_info *info, int user); 5 int (*fb_release)(struct fb_info *info, int user); 6 7 /* For framebuffers with strange non linear layouts or that do not 8 * work with normal memory mapped access 9 */ 10 ssize_t (*fb_read)(struct fb_info *info, char __user *buf, 11 size_t count, loff_t *ppos); 12 ssize_t (*fb_write)(struct fb_info *info, const char __user *buf, 13 size_t count, loff_t *ppos); 14 15 /* checks var and eventually tweaks it to something supported, 16 * DO NOT MODIFY PAR */ 17 int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info); 18 19 /* set the video mode according to info->var */ 20 int (*fb_set_par)(struct fb_info *info); 21 22 /* set color register */ 23 int (*fb_setcolreg)(unsigned regno, unsigned red, unsigned green, 24 unsigned blue, unsigned transp, struct fb_info *info); 25 26 /* set color registers in batch */ 27 int (*fb_setcmap)(struct fb_cmap *cmap, struct fb_info *info); 28 29 /* blank display */ 30 int (*fb_blank)(int blank, struct fb_info *info); 31 32 /* pan display */ 33 int (*fb_pan_display)(struct fb_var_screeninfo *var, struct fb_info *info); 34 35 /* Draws a rectangle */ 36 void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect); 37 /* Copy data from area to another */ 38 void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region); 39 /* Draws a image to the display */ 40 void (*fb_imageblit) (struct fb_info *info, const struct fb_image *image); 41 42 /* Draws cursor */ 43 int (*fb_cursor) (struct fb_info *info, struct fb_cursor *cursor); 44 45 /* Rotates the display */ 46 void (*fb_rotate)(struct fb_info *info, int angle); 47 48 /* wait for blit idle, optional */ 49 int (*fb_sync)(struct fb_info *info); 50 51 /* perform fb specific ioctl (optional) */ 52 int (*fb_ioctl)(struct fb_info *info, unsigned int cmd, 53 unsigned long arg); 54 55 /* Handle 32bit compat ioctl (optional) */ 56 int (*fb_compat_ioctl)(struct fb_info *info, unsigned cmd, 57 unsigned long arg); 58 59 /* perform fb specific mmap */ 60 int (*fb_mmap)(struct fb_info *info, struct vm_area_struct *vma); 61 62 /* get capability given var */ 63 void (*fb_get_caps)(struct fb_info *info, struct fb_blit_caps *caps, 64 struct fb_var_screeninfo *var); 65 66 /* teardown any resources to do with this framebuffer */ 67 void (*fb_destroy)(struct fb_info *info); 68 };
二、framebuffer驅動框架的初始化函數:fbmem_init(drivers\video\fbmem.c)
framebuffer驅動框架部分的代碼與前面說的misc驅動框架和led驅動框架同樣,都是實現爲一個模塊的形式,能夠在內核配置的時候進行動態的加載和卸載,模塊的好處以前已經說過。
fbmem_init函數代碼分析:
1 static int __init 2 fbmem_init(void) 3 { 4 proc_create("fb", 0, NULL, &fb_proc_fops); // 在proc文件系統中創建一個名爲 fb 的目錄 5 6 if (register_chrdev(FB_MAJOR,"fb",&fb_fops)) // 註冊字符設備 fb 主設備號29 fb_fops 7 printk("unable to get major %d for fb devs\n", FB_MAJOR); 8 9 fb_class = class_create(THIS_MODULE, "graphics"); // 建立設備類 /sys/class/graphics 10 if (IS_ERR(fb_class)) { 11 printk(KERN_WARNING "Unable to create fb class; errno = %ld\n", PTR_ERR(fb_class)); 12 fb_class = NULL; 13 } 14 return 0; 15 }
(1)fb_fops變量
fb_fops是一個struct file_operations結構體類型的變量,這個結構體不是什麼新鮮玩樣了,framebuffer驅動框架中註冊的這個file_operations結構體內容以下:
(2)對fb_fops結構體中的fb_open函數分析:
fb_open(struct inode *inode, struct file *file) (如下層次爲函數的調用關係)
int fbidx = iminor(inode); // 經過inode指針獲取設備的次設備號
struct fb_info *info;
info = registered_fb[fbidx]; // 找到以次設備號爲下標的數組項
info->fbops->fb_open(info,1); // 調用info指向的fb_info結構體中的fb_ops結構體中的open函數(注意:fbops指針是一個fb_ops類型的結構體指針,上面說的fb_fops 是file_operations類型的結構體的變量)
1):注意:上面分析的只是open函數,那麼其餘的函數也是同樣的原理,最終都會調用到驅動編寫者向框架註冊的fb_info結構體中的fb_fops中封裝的函數。
2):從這裏能夠看出來fb的驅動框架註冊的file_operations與以前講的misc驅動框架中註冊file_operations有所不一樣,他們的不一樣主要兩個:
a、misc中註冊的file_operations結構體中只有open函數,都是經過這個open函數獲取設備的file_operations;而fb驅動框架中註冊的file_operations結構體中基本函數都實現了,
真正驅動中的不一樣的函數是經過這個結構體中對應的函數內部進行轉換的。
b、misc驅動框架下的具體驅動的操做函數也是封裝在一個file_operations結構體變量中,固然這個變量是在struct miscdevice結構體中包含的;而fb驅動框架下的具體的驅動的
操做函數是封裝在一個fb_ops類型的結構體變量中的,是包含在fb_info結構體中,隨着fb_info變量的註冊而向驅動框架註冊。
三、驅動框架留給驅動工程師的接口:register_framebuffer/unregister_framebuffer(drivers\video\fbmem.c)
驅動框架代碼是不涉及到具體的硬件操做的,主要是軟件邏輯,提供服務性的代碼。驅動工程師須要調用驅動框架提供的接口函數來向驅動框架註冊驅動、設備。
struct fb_info結構體是驅動編寫者利用fb驅動框架來編寫fb驅動時須要提供的一個結構體,內部封裝了不少的信息,包括LCd的硬件信息,像素、像素深度、尺寸大小等等。
其中重要的有struct fb_fix_screeninfo(可變參數)、struct fb_var_screeninfo(不可變參數)、struct fb_videomode(顯示模式:顯示分辨率、刷新率等的)、struct fb_ops(
這個結構體封裝了open、read、write....等應用層對應到驅動的函數)。
(2)register_framebuffer函數
1 int 2 register_framebuffer(struct fb_info *fb_info) 3 { 4 int i; 5 struct fb_event event; // 定義一個fb_event 變量 6 struct fb_videomode mode; // 定義一個fb_videomode 變量 7 8 if (num_registered_fb == FB_MAX) // 若是當前註冊的fb設備的數量已經滿了,則不能在進行註冊了 最大值32 9 return -ENXIO; 10 11 if (fb_check_foreignness(fb_info)) // 校驗 12 return -ENOSYS; 13 14 remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id, // 防衝突檢查 15 fb_is_primary_device(fb_info)); 16 17 num_registered_fb++; // 當前註冊的設備數量 + 1 18 for (i = 0 ; i < FB_MAX; i++) // registered_fb 是fb驅動框架維護的一個用來管理記錄fb設備的數組, 裏面的元素就是 fb_info 指針,一個fb_info就表明一個fb設備 19 if (!registered_fb[i]) // 找到一個最小的沒有被使用的次設備號 20 break; 21 fb_info->node = i; // 將次設備號存放在 fb_info->node 中 22 mutex_init(&fb_info->lock); 23 mutex_init(&fb_info->mm_lock); 24 25 fb_info->dev = device_create(fb_class, fb_info->device, // 建立設備 名字: fb+次設備號 26 MKDEV(FB_MAJOR, i), NULL, "fb%d", i); 27 if (IS_ERR(fb_info->dev)) { 28 /* Not fatal */ 29 printk(KERN_WARNING "Unable to create device for framebuffer %d; errno = %ld\n", i, PTR_ERR(fb_info->dev)); 30 fb_info->dev = NULL; 31 } else 32 fb_init_device(fb_info); // 初始化fb設備 33 34 if (fb_info->pixmap.addr == NULL) { // pixmap 相關的設置 35 fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL); 36 if (fb_info->pixmap.addr) { 37 fb_info->pixmap.size = FBPIXMAPSIZE; 38 fb_info->pixmap.buf_align = 1; 39 fb_info->pixmap.scan_align = 1; 40 fb_info->pixmap.access_align = 32; 41 fb_info->pixmap.flags = FB_PIXMAP_DEFAULT; 42 } 43 } 44 fb_info->pixmap.offset = 0; 45 46 if (!fb_info->pixmap.blit_x) 47 fb_info->pixmap.blit_x = ~(u32)0; 48 49 if (!fb_info->pixmap.blit_y) 50 fb_info->pixmap.blit_y = ~(u32)0; 51 52 if (!fb_info->modelist.prev || !fb_info->modelist.next) 53 INIT_LIST_HEAD(&fb_info->modelist); // 初始化鏈表 54 55 fb_var_to_videomode(&mode, &fb_info->var); // 從fb_info結構體中獲取顯示模式存放在mode變量中 56 fb_add_videomode(&mode, &fb_info->modelist); // 添加顯示模式: 先檢查須要添加的顯示模式是否在鏈表中已經存在,若是存在則沒有必要在進行添加 57 registered_fb[i] = fb_info; // 將fb_info 結構體存放到 registered_fb 駐足中去 58 59 event.info = fb_info; 60 if (!lock_fb_info(fb_info)) 61 return -ENODEV; 62 fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event); // 異步通知: 通知那些正在等待fb註冊事件發生的進程 63 unlock_fb_info(fb_info); 64 return 0; 65 }
a、registered_fb和num_registered_fb:
registered_fb是一個數組,是fb驅動框架用來管理全部註冊的fb設備的,跟misc設備中的misc_list鏈表的做用是同樣的;
num_registered_fb看名字就知道是一個計算值,是用來記錄當前系統中已經註冊了多少個fb設備;fb設備註冊的最大數量爲32,用FB_MAX宏來表示。
b、結合fb_open...等函數中對fb_info結構體的使用,理解的關鍵點:數據如何封裝、數據由誰準備由誰消費、數據如何傳遞
1):register_framebuffer 函數中的 fb_init_device函數分析:
1 int fb_init_device(struct fb_info *fb_info) 2 { 3 int i, error = 0; 4 5 dev_set_drvdata(fb_info->dev, fb_info); // 設置fb設備的私有數據中的設備驅動私有數據,也就是將 fb_info 存放在 dev->p->driver_data 6 7 fb_info->class_flag |= FB_SYSFS_FLAG_ATTR; // 設置標誌位 8 9 for (i = 0; i < ARRAY_SIZE(device_attrs); i++) { // 根據 device_attrs 這個device屬性數組來建立設備屬性文件 10 error = device_create_file(fb_info->dev, &device_attrs[i]); 11 12 if (error) 13 break; 14 } 15 16 if (error) { 17 while (--i >= 0) 18 device_remove_file(fb_info->dev, &device_attrs[i]); 19 fb_info->class_flag &= ~FB_SYSFS_FLAG_ATTR; 20 } 21 22 return 0; 23 }
2):設備屬性相關結構體以下所示:能夠在 /sys/class/graphics/fb0目錄下面看到這些屬性文件
四、總結:framebuffer驅動框架總覽
fb的驅動框架代碼主要涉及到如下的4個文件:
(1)drivers/video/fbmem.c。主要任務:一、建立graphics類、註冊FB的字符設備驅動、提供register_framebuffer接口給具體framebuffer驅動編寫着來註冊fb設備的。
本文件相對於fb來講,地位和做用和misc.c文件相對於雜散類設備來講同樣的,結構和分析方法也是相似的。
(2)drivers/video/fbsys.c。這個文件是處理fb在/sys目錄下的一些屬性文件的,例如register_framebuffer函數中fb_init_device函數就是存在這個文件中
(3)drivers/video/modedb.c。這個文件是管理顯示模式(譬如VGA、720P等就是顯示模式)的
(4)drivers/video/fb_notify.c。異步通知函數,例如fb_notifier_call_chain函數就在這個文件中