关于linux的fbframebuffer 设备驱动.docx
《关于linux的fbframebuffer 设备驱动.docx》由会员分享,可在线阅读,更多相关《关于linux的fbframebuffer 设备驱动.docx(56页珍藏版)》请在冰点文库上搜索。
关于linux的fbframebuffer设备驱动
草稿V2.4.0
1framebuffer设备即帧缓冲设备(简写fb)提供了显示接口的抽象描述。
他
同时代表着显示接口的存储区,应用程序通过定义好的函数访问,不需要知道底
层的任何操作。
Framebuffer驱动使用的设备节点,通常位于/dev目录,如/dev/fb*.从用
户角度看,fb设备和其他/dev下面的设备类似:
普通的字符设备,主设备号29,
次设备号定义fb的索引。
通常,使用如下方式(前面的数字表示次设备号)
0=/dev/fb0第一个fb设备
1=/dev/fb1第二个fb设备
考虑到向下兼容,可以创建符号链接:
/dev/fb0current->fb0
/dev/fb1current->fb1
fb也是一种普通的内存设备,可以读写其内容。
例如,屏幕抓屏:
cp/dev/fb0myfile
fb虽然可以像内存设备(/dev/mem)一样,对其read,write,seek以及mmap。
但区别在于fb使用的不是整个内存区,而是显存部分。
通过ioctl可以读取或设定fb设备参数,很重要的一点,颜色表(cmap)也
要通过Ioctl设定。
查看就知道有多少ioctl应用以及相关数据结
构。
这里给出摘要:
-你可以获取设备一些不变的信息,如设备名,屏幕的组织(平面,象素,...)
对应内存区的长度和起始地址。
-也可以获取能够改变的信息,例如位深,颜色格式,时序等。
如果你改变这
些值,驱动程序将对值进行优化,以满足设备特性(如果你的设定,设备不支持,
返回EINVAL)。
-你也可以获取或设定部分颜色表。
所有这些特性让应用程序十分容易的使用framebuffer设备。
Xserver可
以使用/dev/fb*而不需知道硬件的寄存器是如何组织的。
XF68_FBDev是一个用
于位映射(单色)Xserver,唯一要做的就是在应用程序在相应的位置设定是否
显示。
在新内核中,帧缓冲设备可以工作于模块中,允许动态加载。
这类驱动必须
调用register_framebuffer()在系统中注册。
之所以对视频模式进行介绍,因为在后面的一些数据结构中,会出现对视频
模式的参数描述。
CRT显示器用3个电子枪轰击磷粉完成颜色的显示。
电子枪必须完成从左到草稿V2.4.0
2右的水平扫描和从上至下的垂直扫描。
改变枪的电压,对应显示的颜色可以不同。
当电子枪完成一行扫描重新回到下一行的开始,被称为“水平折回”。
当一屏幕
全部扫描完毕,电子枪从底部回到左上角,被称为“垂直折回”。
在折回的途中
电子枪是关闭的。
电子枪打点的移动速度取决于点时钟。
如果点时钟是28.37516MHz,打一
个点需要35242ps。
1/(28.37516E6Hz)=35.242E-9s
如果屏幕分辨率是640x480,那么一行的时间是:
640*35.242E-9s=22.555E-6s
然而水平折回也是需要时间的,通常272个点时钟单位,因此扫描一行需要
的时间就是:
(640+272)*35.242E-9s=32.141E-6s
由此得到水平扫描的频率是31KHz:
1/(32.141E-6s)=31.113E3Hz
若屏幕有480行,加上垂直折回时间49个行时钟单位,刷新一屏所需时间:
(480+49)*32.141E-6s=17.002E-3s
由此得到垂直扫描的频率是59Hz:
1/(17.002E-3s)=58.815Hz
这意味着屏幕数据每秒钟刷新59次。
为了得到稳定的图像显示效果,VESA
标准规定垂直扫描频率不低于72Hz。
但也因人而异,有些人在50Hz时就感觉不
到闪烁,而另一些则要在80Hz以上才可。
由于显示器不知道何时开始新的一行扫描,因此需要为行扫描提供水平同步
信号。
类似的,也为每一帧显示提供垂直同步信号。
图像在屏幕上点的位置取决
于这些同步信号的发生时刻。
下图给出了所有时序的概要。
水平折回的时间就是左边空白+右边空白+水
平同步长度。
垂直折回的时间就是上空白+下空白+垂直同步长。
+----------+--------------------------------------------+----------+-------+
||^|||
|||upper_margin|||
||?
|||
+----------###############################################----------+-------+
|#^#||
|left#|#right|hsync|
|margin#|xres#margin|len|
|<-------->#<---------------+--------------------------->#<-------->|<----->|
|#|#||
|#|#||
|#|yres#||
|#|#||
|#|#||
|#|#||
|#?
#||草稿V2.4.0
3+----------###############################################----------+-------+
||^|||
|||lower_margin|||
||?
|||
+----------+---------------------------------------------+----------+-------+
||^|||
|||vsync_len|||
||?
|||
+----------+---------------------------------------------+----------+-------+把XFree86时序变成fb时序
典型的显示模式:
"800x600"508008569761040600637643666
DCFHRSH1SH2HFLVRSV1SV2VFL
而帧缓冲设备使用下面的参数:
-pixclock:
点时钟inps(picoseconds)
-left_margin:
timefromsynctopicture
-right_margin:
timefrompicturetosync
-upper_margin:
timefromsynctopicture
-lower_margin:
timefrompicturetosync
-hsync_len:
lengthofhorizontalsync
-vsync_len:
lengthofverticalsync
1)Pixelclock:
xfree:
inMHz
fb:
inpicoseconds(ps)
pixclock=1000000/DCF
2)horizontaltimings:
left_margin=HFL-SH2
right_margin=SH1-HR
hsync_len=SH2-SH1
3)verticaltimings:
upper_margin=VFL-SV2
lower_margin=SV1-VR
vsync_len=SV2-SV1
1.2
下面给出了一个framebuffer驱动例子,并添加详细注释。
通过阅读该例,
希望大家对framebuffer驱动初步了解。
后面我们将分析用到的数据结构,以及草稿V2.4.0
4其中成员变量和成员函数的功能和意义。
/*linux/drivers/video/anakinfb.c
*Copyright(C)2001AlephOneLtd.forAcuniaN.V.
*
*Thisprogramisfreesoftware;youcanredistributeitand/ormodify
*itunderthetermsoftheGNUGeneralPublicLicenseversion2as
*publishedbytheFreeSoftwareFoundation.
*Changelog:
23-Apr-2001TTCCreated
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
staticu16colreg[16];//颜色描述表,cmap的简化描述
staticintcurrcon=0;//当前的console索引
staticstructfb_infofb_info;
staticstructdisplaydisplay;
staticintanakinfb_getcolreg(u_intregno,u_int*red,u_int*green,
u_int*blue,u_int*transp,structfb_info*info)
{
if(regno>15)//共有16色,故索引不大于15
return1;
//颜色描述的位深16位,分别是R:
G:
B=5:
6:
5;后面的补齐操作采用了左移
低位补齐方式,只要和setcloreg运算相反即可,也可以使用高位补齐方式。
*red=colreg[regno]&0xf800;
*green=colreg[regno]&0x7e0<<5;//移到高字节,凑足16位
*blue=colreg[regno]&0x1f<<11;//移到高字节,凑足16位
*transp=0;//不支持透明度
return0;//成功返回0,参考fb_get_cmap实现,就知道这里为什么是0。
}
staticintanakinfb_setcolreg(u_intregno,u_intred,u_intgreen,u_int草稿V2.4.0
5blue,u_inttransp,structfb_info*info)
{
if(regno>15)
return1;
//根据索引,设置颜色表的颜色值
colreg[regno]=(red&0xf800)|(green&0xfc00>>5)|
(blue&0xf800>>11);
return0;
}
//从fb_info结构获取fb_fix_screeninfo信息。
由于我们在anakinfb_init
中并没有设置fb_info.fix的值,所以只有在此函数内通过常值赋予。
staticintanakinfb_get_fix(structfb_fix_screeninfo*fix,intcon,
structfb_info*info)
{
//fix全部为0
memset(fix,0,sizeof(structfb_fix_screeninfo));
//id作为字符串标识用
strcpy(fix->id,"AnakinFB");
//显存的起始物理地址
fix->smem_start=VGA_START;
//显存所占的字节数
fix->smem_len=VGA_SIZE;
//象素显示
fix->type=FB_TYPE_PACKED_PIXELS;
//下面的略,参考后面fb_fix_srceeninfo结构
fix->type_aux=0;
fix->visual=FB_VISUAL_TRUECOLOR;
fix->xpanstep=0;
fix->ypanstep=0;
fix->ywrapstep=0;
//每行所占字节数,xres=400
fix->line_length=400*2;
//显卡无硬件加速
fix->accel=FB_ACCEL_NONE;
return0;
}
staticintanakinfb_get_var(structfb_var_screeninfo*var,intcon,
structfb_info*info)
{
//var初始化为0
memset(var,0,sizeof(structfb_var_screeninfo));
//x方向分辨率草稿V2.4.0
6var->xres=400;
//y方向分辨率
var->yres=234;
//虚拟分辨率,不支持pan,故和实际分辨率一致
var->xres_virtual=400;
var->yres_virtual=234;
var->xoffset=0;
var->yoffset=0;
//色深16位,5:
6:
5结构
var->bits_per_pixel=16;
//彩色,非灰度,bpp<8,grayscale=1
var->grayscale=0;
//根据R:
G:
B=5:
6:
5得下面数据
var->red.offset=11;
var->red.length=5;
var->green.offset=5;
var->green.length=6;
var->blue.offset=0;
var->blue.length=5;
//不支持透明度
var->transp.offset=0;
var->transp.length=0;
var->nonstd=0;
var->activate=FB_ACTIVATE_NOW;
//下面解释略
var->height=-1;
var->width=-1;
var->pixclock=0;
var->left_margin=0;
var->right_margin=0;
var->upper_margin=0;
var->lower_margin=0;
var->hsync_len=0;
var->vsync_len=0;
var->sync=0;
var->vmode=FB_VMODE_NONINTERLACED;
return0;
}
//此函数直接返回,表明fb_var_screeninfo是不希望被修改的,这和显示器有
关。
若显示模式只有400*234*16一种,则set_var没有意义。
staticintanakinfb_set_var(structfb_var_screeninfo*var,intcon,
structfb_info*info)
{草稿V2.4.0
7return-EINVAL;
}
//获取颜色表
staticintanakinfb_get_cmap(structfb_cmap*cmap,intkspc,intcon,
structfb_info*info)
{
if(con==currcon)//通常会成立
returnfb_get_cmap(cmap,kspc,anakinfb_getcolreg,info);
elseif(fb_display[con].cmap.len)
fb_copy_cmap(&fb_display[con].cmap,cmap,kspc?
0:
2);
else
fb_copy_cmap(fb_default_cmap(16),cmap,kspc?
0:
2);
return0;
}
//设置颜色表
staticintanakinfb_set_cmap(structfb_cmap*cmap,intkspc,intcon,
structfb_info*info)
{
interr;
if(!
fb_display[con].cmap.len){
if((err=fb_alloc_cmap(&fb_display[con].cmap,16,0)))
returnerr;
}
if(con==currcon)//通常会成立
returnfb_set_cmap(cmap,kspc,anakinfb_setcolreg,info);
else
fb_copy_cmap(cmap,&fb_display[con].cmap,kspc?
0:
1);
return0;
}
//console切换
staticintanakinfb_switch_con(intcon,structfb_info*info)
{
currcon=con;
return0;
}
//通知console更新var
staticintanakinfb_updatevar(intcon,structfb_info*info)
{
return0;草稿V2.4.0
8}
//开关显示用
staticvoidanakinfb_blank(intblank,structfb_info*info)
{
/*
*TODO:
useI2Ctoblank/unblankthescreen
*/
}
//定义structfb_ops结构
staticstructfb_opsanakinfb_ops={
owner:
THIS_MODULE,
fb_get_fix:
anakinfb_get_fix,
fb_get_var:
anakinfb_get_var,
fb_set_var:
anakinfb_set_var,
fb_get_cmap:
anakinfb_get_cmap,
fb_set_cmap:
anakinfb_set_cmap,
};
//fb驱动初始化函数
int__initanakinfb_init(void)
{
//fb_info变量全部置0
memset(&fb_info,0,sizeof(structfb_info));
//对fb_info.modename赋值为”AnakinFB”
strcpy(fb_info.modename,"AnakinFB");
//fb_info.node=-1,后面调用register_framebuffer,会重新设该值为
/dev/fbx节点
fb_info.node=-1;
//fb_info.flags指明fb驱动的内核加载方式
fb_info.flags=FBINFO_FLAG_DEFAULT;
//定义fb_info的fops
fb_info.fbops=&anakinfb_ops;
//fb_info.disp是提供fbcon的基础
fb_info.disp=&display;
//fb_info.fontname表示fbcon采用的字体为VGA8X16
strcpy(fb_info.fontname,"VGA8x16");
fb_info.changevar=NULL;
//console切换时调用函数anakinfb_switch_con
fb_info.switch_con=&anakinfb_switch_con;
//下面2个函数没有操作,直接返回
fb_info.updatevar=&anakinfb_updatevar;
fb_info.blank=&anakinfb_blank;
//display初始化为0草稿V2.4.0
9memset(&display,0,sizeof(structdisplay));
//对display.var赋值,参考anakinfb_get_var函数
anakinfb_get_var(&display.var,0,&fb_info);
//显存的起始地址
display.screen_base=ioremap(VGA_START,VGA_SIZE);
//显示的颜色模式
display.visual=FB_VISUAL_TRUECOLOR;
//象素
display.type=FB_TYPE_PACKED_PIXELS;
display.type_aux=0;
display.ypanstep=0;
display.ywrapstep=0;
//每行字节数,每行400象素,16位色深,故400*2
display.line_length=400*2;
display.can_soft_blank=1;
//颜色反转显示标志
display.inverse=0;
#ifdefFBCON_HAS_CFB16//内核配置参数
//fbcon的底层操作函数
display.dispsw=&fbcon_cfb16;
//辅助数据,意义不大
display.dispsw_data=colreg;
#else//此情况基本不会发生
display.dispsw=&fbcon_dummy;
#endif
//注册framebuffer
if(register_framebuffer(&fb_info)<0)
return-EINVAL;
MOD_INC_USE_COUNT;
return0;
}
MODULE_AUTHOR("Tak-ShingChan");
MODULE_DESCRIPTION("Anakinframebufferdriver");
MODULE_SUPPORTED_DEVICE("fb");
Thefb_opsStructureThe
structureishowaframebufferdriversetsupthisconnection.Thestructure,defined
in,isacollectionoffunctionpointers.Eachopenfile(representedinternallybyafilestructure,whichwewillexamineshortly)isassociatedwithitsownsetoffunctions(by
includingafieldcalledfb_opthatpointstoafile_operationsstructure).Theoperationsare草稿V2.4.0
10
mostlyinchargeofimplementingthesystemcallsandaretherefore,namedopen,read,andsoon.
Wecanconsiderthefiletobean“object”andthefunctionsoperatingonittobeits“methods,”
usingobject-orientedprogrammingterminologytodenoteactionsdeclaredbyanobjecttoacton
itself.Thisisthefirstsignofobject-orientedprogrammingweseeintheLinuxkernel,and
we’llseemoreinlaterchapters.
Conventionally,afile_operationsstructureorapointertooneiscalledfbops(orsomevariation
thereof).Eachfieldinthestructuremustpointtothefunctioninthedriverthatimplements
aspecificoperation,orbeleftNULLforunsupportedoperations.
Theexactbehavioro