Linux驅動開發(9)------- framebuffer驅動詳解


一,framebuffer介紹


1、什麼是framebuffer
(1)很多人都會說操縱lcd顯示就是操縱framebuffer,表面上來看是這樣的。實際上是frambuffer就是linux內核驅動申請的一片內存空間,然後lcd內有一片sram,cpu內部有個lcd控制器,它有個單獨的dma用來將frambuffer中的數據拷貝到lcd的sram中去 拷貝到lcd的sram中的數據就會顯示在lcd上,LCD驅動和framebuffer驅動沒有必然的聯繫,它只是驅動LCD正常工作的,比如有信號傳過來,那麼LCD驅動負責把信號轉成顯示屏上的內容,至於什麼內容這就是應用層要處理的。
(2)framebuffer幀緩衝(簡稱fb)是linux內核中虛擬出的一個設備
(3)framebuffer嚮應用層提供一個統一標準接口的顯示設備
(4)從驅動來看,fb是一個典型的字符設備,而且創建了一個類/sys/class/graphics

2、幀緩衝設備驅動的結構
在這裏插入圖片描述
3、framebuffer的使用步驟
(1)打開設備文件 /dev/fb0
(2)獲取當前設備信息 #include <linux/fb.h>
(3)mmap做映射
(4)填充framebuffer


二,framebuffer驅動源碼分析



1.framebuffer驅動框架總覽


1、驅動框架部分

  • drivers/video/fbmem.c主要任務:fbmen_init()函數負責創建graphics類、註冊FB的字符設備驅動、register_framebuffer()函數提供接口給具體framebuffer驅動編寫着來註冊fb設備。本文件相對於fb來說,地位和作用和misc.c文件相對於雜散類設備來說一樣的,結構和分析方法也是類似的。
  • drivers/video/fbsys.c這個文件是處理fb在/sys目錄下的一些屬性文件的
  • drivers/video/modedb.c這個文件是管理顯示模式(譬如VGA、720P等就是顯示模式)的。
  • drivers/video/fb_notify.c這個文件是frame buff用來管理相關通知的

2、驅動部分

  • drivers/video/samsung/s3cfb.c驅動主體
  • drivers/video/samsung/s3cfb_fimd6x.c裏面有很多LCD硬件操作的函數
  • arch/arm/mach-s5pv210/mach-x210.c負責提供platform_device的
  • arch/arm/plat-s5p/devs.c爲platform_device提供一些硬件描述信息的

3、如何分析
(1)經驗
(2)分析menuconfig、Makefile、Kconfig等
(3)內核編譯後檢查編譯結果中的.o文件


2.framebuffer驅動框架分析


1、fbmem_init函數
(1)#ifdef MODULE

在這裏插入圖片描述
(2)fb_proc_fops和fb在proc文件系統中的表現

在這裏插入圖片描述

(3)register_chrdev註冊fb設備
(4)class_create創建graphics類
(5)fbmem_exit的對應
在這裏插入圖片描述

2、fb_fops
(1)read/write/mmap/ioctl
(2)registered_fb和num_registered_fb
(3)struct fb_info
在這裏插入圖片描述

3、register_framebuffer和unregister_framebuffer

在這裏插入圖片描述


3.framebuffer驅動分析


1、s3cfb.c

在這裏插入圖片描述

2、s3c_device_fb

在這裏插入圖片描述

3、probe函數分析
(1)struct s3c_platform_fb這個結構體是fb的platform_data結構體,這個結構體變量就是platform設備的私有數據,這個數據在platform_device.device.platform_data中存儲。在mach文件中去準備並填充這些數據,在probe函數中通過傳參的platform_device指針取出來。
(2)struct s3cfb_global這個結構體主要作用是在驅動部分的2個文件(s3cfb.c和s3cfb_fimd6x.c)的函數中做數據傳遞用的
在這裏插入圖片描述

4、
在這裏插入圖片描述
在這裏插入圖片描述

5、

在這裏插入圖片描述

在這裏插入圖片描述
在這裏插入圖片描述

三,framebuffer應用編程實踐

實驗步驟

1、打開設備
2、獲取設備信息
(1)不可變信息FSCREENINFO,使用ioctl的FBIOGET_FSCREENINFO名
(2)可變信息VSCREENINFO,使用ioctl的FBIOGET_VSCREENINFO名

在這裏插入圖片描述

3、mmap做映射
做完了mmap後fb在當前進程中就已經就緒了,隨時可以去讀寫LCD顯示器了。

4、fb顯示之刷背景和畫橫線

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/ioctl.h>
#include <sys/mman.h>

// 宏定義
#define FBDEVICE	"/dev/fb0"
#define WIDTH		1024	
#define HEIGHT		600

#define WHITE		0xffffffff			// test ok
#define BLACK		0x00000000
#define RED			0xffff0000
#define GREEN		0xff00ff00			// test ok
#define BLUE		0xff0000ff			
#define GREENP		0x0000ff00			// 一樣,說明前2個ff透明位不起作用

// 函數聲明
void draw_back(unsigned int width, unsigned int height, unsigned int color);
void draw_line(unsigned int color);

// 全局變量
unsigned int *pfb = NULL;


int main(void)
{
	int fd = -1, ret = -1;
	
	
	struct fb_fix_screeninfo finfo = {0};
	struct fb_var_screeninfo vinfo = {0};
	
	// 第1步:打開設備
	fd = open(FBDEVICE, O_RDWR);
	if (fd < 0)
	{
		perror("open");
		return -1;
	}
	printf("open %s success.\n", FBDEVICE);
	
	// 第2步:獲取設備的硬件信息
	ret = ioctl(fd, FBIOGET_FSCREENINFO, &finfo);
	if (ret < 0)
	{
		perror("ioctl");
		return -1;
	}
	printf("smem_start = 0x%x, smem_len = %u.\n", finfo.smem_start, finfo.smem_len);
	
	ret = ioctl(fd, FBIOGET_VSCREENINFO, &vinfo);
	if (ret < 0)
	{
		perror("ioctl");
		return -1;
	}
	printf("xres = %u, yres = %u.\n", vinfo.xres, vinfo.yres);
	printf("xres_virtual = %u, yres_virtual = %u.\n", vinfo.xres_virtual, vinfo.yres_virtual);
	printf("bpp = %u.\n", vinfo.bits_per_pixel);

	
	// 第3步:進行mmap
	unsigned long len = vinfo.xres_virtual * vinfo.yres_virtual * vinfo.bits_per_pixel / 8;
	printf("len = %ld\n", len);
	pfb = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
	if (NULL == pfb)
	{
		perror("mmap");
		return -1;
	}
	printf("pfb = %p.\n", pfb);
	
	draw_back(WIDTH, HEIGHT, WHITE);
	draw_line(RED);
	

	close(fd);
	
	return 0;
}


//刷背景函數
void draw_back(unsigned int width, unsigned int height, unsigned int color)
{
	unsigned int x, y;
	
	for (y=0; y<height; y++)
	{
		for (x=0; x<width; x++)
		{
			*(pfb + y * WIDTH + x) = color;
		}
	}
}

//畫線函數
void draw_line(unsigned int color)
{
	unsigned int x, y;
	
	for (x=50; x<600; x++)
	{
		*(pfb + 200 * WIDTH + x) = color;
	}
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章