1. 程式人生 > >《5.linux驅動開發-第7部分-5.7.framebuffer驅動詳解》

《5.linux驅動開發-第7部分-5.7.framebuffer驅動詳解》

《5.linux驅動開發-第7部分-5.7.framebuffer驅動詳解》

第一部分、章節目錄
5.7.1.framebuffer介紹
5.7.2.framebuffer應用程式設計實踐1
5.7.3.framebuffer應用程式設計實踐2
5.7.4.framebuffer應用程式設計實踐3
5.7.5.framebuffer驅動框架總覽
5.7.6.framebuffer驅動框架分析1

第二部分、章節介紹
5.7.1.framebuffer介紹
本節介紹framebuffer的概念和來源、設計思想,fb裝置的應用層介面等,為下節使用framebuffer應用程式設計打基礎。
5.7.2.framebuffer應用程式設計實踐1
本節基於framebuffer編寫應用程式進行顯示,主要是開啟裝置檔案及獲取裝置的關鍵硬體資訊、進行視訊記憶體對映等。
5.7.3.framebuffer應用程式設計實踐2
本節繼續framebuffer應用程式設計,使用framebuffer在LCD上顯示背景色.
5.7.4.framebuffer應用程式設計實踐3
本節繼續framebuffer應用程式設計,使用framebuffer更改解析度等操作,最後講述如何去寫字、畫圖等。
5.7.5.framebuffer驅動框架總覽
本節對核心的framebuffer驅動框架做整體介紹,各部分涉及哪些檔案,每個檔案是誰寫的,具體功能是什麼,詳細的程式碼分析在後面。
5.7.6.framebuffer驅動框架分析1

第三部分、隨堂記錄
5.7.1.framebuffer介紹
5.7.1.1、什麼是framebuffer
(1)裸機中如何操作LCD
(2)OS下操作LCD的難點
(3)framebuffer幀緩衝(簡稱fb)是linux核心中虛擬出的一個裝置
(4)framebuffer嚮應用層提供一個統一標準介面的顯示裝置
(5)從驅動來看,fb是一個典型的字元裝置,而且建立了一個類/sys/class/graphics
5.7.1.2、framebuffer的使用
(1)裝置檔案 /dev/fb0
(2)獲取裝置資訊 #include <linux/fb.h>
(3)mmap做對映
(4)填充framebuffer

5.7.2.framebuffer應用程式設計實踐1
5.7.2.1、開啟裝置
5.7.2.2、獲取裝置資訊
(1)不可變資訊FSCREENINFO,使用ioctl的FBIOGET_FSCREENINFO名
(2)可變資訊VSCREENINFO,使用ioctl的FBIOGET_VSCREENINFO名

5.7.3.framebuffer應用程式設計實踐2
5.7.3.1、mmap做對映
做完了mmap後fb在當前程序中就已經就緒了,隨時可以去讀寫LCD顯示器了。
5.7.3.2、fb顯示之刷背景

5.7.4.framebuffer應用程式設計實踐3
5.7.4.1、設定解析度
(1)實驗失敗,實驗結果是隻能修改虛擬解析度,不能修改可視解析度。原因要去驅動裡找。
(2)正確的做法是在驅動中去修改引數,然後重新編譯執行,才能解決。
5.7.4.2、寫字、畫線、圖片顯示等

#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		800	
//#define HEIGHT		480
// 新開發板
#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);

	
	// 修改驅動中螢幕的解析度
	vinfo.xres = 1024;
	vinfo.yres = 600;
	vinfo.xres_virtual = 1024;
	vinfo.yres_virtual = 1200;
	ret = ioctl(fd, FBIOPUT_VSCREENINFO, &vinfo);
	if (ret < 0)
	{
		perror("ioctl");
		return -1;
	}
	
	// 再次讀出來檢驗一下
	ret = ioctl(fd, FBIOGET_VSCREENINFO, &vinfo);
	if (ret < 0)
	{
		perror("ioctl");
		return -1;
	}
	printf("修改過之後的引數:\n");
	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;
	}
}

5.7.5.framebuffer驅動框架總覽
5.7.5.1、驅動框架部分
(1)drivers/video/fbmem.c。主要任務:1、建立graphics類、註冊FB的字元裝置驅動、提供register_framebuffer介面給具體framebuffer驅動編寫著來註冊fb裝置的。本檔案相對於fb來說,地位和作用和misc.c檔案相對於雜散類裝置來說一樣的,結構和分析方法也是類似的。
(2)drivers/video/fbsys.c。這個檔案是處理fb在/sys目錄下的一些屬性檔案的。
(3)drivers/video/modedb.c。這個檔案是管理顯示模式(譬如VGA、720P等就是顯示模式)的
(4)drivers/video/fb_notify.c
5.7.5.2、驅動部分
(1)drivers/video/samsung/s3cfb.c,驅動主體
(2)drivers/video/samsung/s3cfb_fimd6x.c,裡面有很多LCD硬體操作的函式
(2)arch/arm/mach-s5pv210/mach-x210.c,負責提供platform_device的
(3)arch/arm/plat-s5p/devs.c,為platform_device提供一些硬體描述資訊的
5.7.5.3、如何分析
(1)經驗
(2)分析menuconfig、Makefile、Kconfig等
(3)核心編譯後檢查編譯結果中的.o檔案

5.7.6.framebuffer驅動框架分析1
5.7.6.1、fbmem_init函式
(1)#ifdef MODULE
(2)fb_proc_fops和fb在proc檔案系統中的表現
(3)register_chrdev註冊fb裝置
(4)class_create建立graphics類
(5)fbmem_exit的對應
5.7.6.2、fb_fops
(1)read/write/mmap/ioctl
(2)registered_fb和num_registered_fb
(3)struct fb_info

5.7.7.framebuffer驅動框架分析2
5.7.7.1、register_framebuffer
(1)fb驅動框架開放給驅動編寫著的註冊介面
(2)fb_check_foreignness
(3)remove_conflicting_framebuffers
(4)device_create
(5)fb_init_device
5.7.7.2、fb在sysfs中的介面
(1)device_attrs
(2)dev_set_drvdata和dev_get_drvdata

5.7.8.framebuffer驅動框架分析3
5.7.8.1、fb的mode
(1)什麼是mode
(2)fb_var_to_videomode
(3)fb_add_videomode
5.7.8.2、註冊登記該fb裝置
(1)registered_fb[i] = fb_info;
(2)結合fb_read等函式中對fb_info的使用
(3)關鍵點:資料如何封裝、資料由誰準備由誰消費、資料如何傳遞
5.7.8.3、fb_notifier_call_chain

5.7.9.framebuffer驅動分析1
5.7.9.1、s3cfb.c
(1)注意目錄結構的組織
(2)s3cfb_driver
5.7.9.2、s3c_device_fb
(1)mach-x210.c中,被使用
(2)devs.c中
(3)resource的定義和作用

5.7.10.framebuffer驅動分析1
5.7.10.1、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)的函式中做資料傳遞用的。
(3)struct resource
(4)regulator
5.7.10.2、platform_data的傳遞過程
(1)to_fb_plat
(2)s3cfb_set_platdata
(3)smdkc110_machine_init

5.7.11.framebuffer驅動分析2
5.7.11.1、struct s3cfb_lcd
5.7.11.2、pdata->cfg_gpio
5.7.11.3、pdata->clk_on
5.7.11.4、resource的處理
(1)platform_device中提供resource結構體陣列
(2)probe中platform_get_resource取出resource並且按FLAG分頭處理

5.7.12.framebuffer驅動分析3
5.7.12.1、一些硬體操作
(1)s3cfb_set_vsync_interrupt
(2)s3cfb_set_global_interrupt
5.7.12.2、s3cfb_init_global
5.7.12.3、向框架註冊該fb裝置
(1)s3cfb_alloc_framebuffer
(2)s3cfb_register_framebuffer

5.7.13.framebuffer驅動分析4
5.7.13.1、一些硬體操作
(1)s3cfb_set_clock
(2)s3cfb_set_window
(3)s3cfb_display_on
5.7.13.2、驅動中處理中斷
(1)platform_get_irq
(2)request_irq
5.7.13.3、logo顯示
5.7.13.4、backlight點亮

5.7.14.應用層為何不能設定解析度
5.7.14.1、問題描述
(1)第4節時試圖在應用層設定解析度失敗了,原因何在?
(2)定位問題:肯定是驅動的事兒
(3)進一步驅動中定位:ioctl部分的事兒
5.7.14.2、fb的ioctl部分
(1)fb是典型的字元裝置驅動
(2)ioctl分為2部分,在驅動框架部分和驅動部分各有一半
(3)一路追蹤找問題

5.7.15.折騰核心的啟動logo
5.7.15.1、讓logo顯示在螢幕中央
5.7.15.2、自定義核心啟動logo