标签:技术 visible video phi v模型 int 包含 null oid
4 linux lcd驱动框架
Linux内核中lcd的驱动是基于帧缓冲framebuffer驱动框架设计的。帧缓冲framebuffer框架是在linux2.2.xx以后的版本中为显示设备提供的一种驱动程序接口,它将显示缓冲区framebuffer进行抽象,屏蔽掉硬件的底层差异,允许上层应用程序在图形模式下直接对显示缓冲区framebuffer进行读写和I/O控制操作。Framebuffer机制模仿显卡的功能,将显卡硬件抽象为一系列的数据结构,通过framebuffer的读写实现对显存的操作。用户可将他看成是显示内存的一个映像,将其映射到进程地址空间,就可以进行读写操作,而读写操作可反映到屏幕上。
framebuffer是个字符设备,主设备号是29,对应/dev/fb%d设备文件。
Linux内核中,framebuffer设备驱动的源码主要包含在\include\linux\Fb.h和drivers\video\Fbmem.h文件中。这两个文件是framebuffer设备驱动框架的中间层,为上层提供系统调用,为底层驱动提供接口。
下面就从这两个文件入手,开始分析framebuffer驱动程序的框架。
首先,从drivers\video\Fbmem.h的入口函数开始,module_init(fbmem_init)。分析fbmem_init的代码。
static?int?__init??
fbmem_init(void)??
{??
????create_proc_read_entry("fb",?0,?NULL,?fbmem_read_proc,?NULL);??
??
?
????if?(register_chrdev(FB_MAJOR,"fb",&fb_fops))??//注册一个字符设备
????????printk("unable?to?get?major?%d?for?fb?devs\n",?FB_MAJOR);??
??
?
????fb_class?=?class_create(THIS_MODULE,?"graphics");??//创建一个类
????if?(IS_ERR(fb_class))?{??
????????printk(KERN_WARNING?"Unable?to?create?fb?class;?errno?=?%ld\n",?PTR_ERR(fb_class));??
????????fb_class?=?NULL;??
????}??
????return?0;??
}??
从上述代码可以看到,fbmem_init函数实现的工作和之前编写驱动程序时入口函数的工作相同。其中,
(1)、代码第6行,调用register_chrdev注册设备。FB_MAJOR主设备号,在Fb.h文件中定义为29。"fb"为设备名称。fb_fops是定义的file_operations结构体,包含了read、write、ioctl等和硬件相关的接口函数。
(2)、代码第9行,创建一个名为"graphics"的类。
用户通过open 函数打开设备,这里就是调用fb_open函数,下面来分析fb_open函数。
static?int??
fb_open(struct?inode?*inode,?struct?file?*file)??
{??
????int?fbidx?=?iminor(inode);??//得到次设备号
????struct?fb_info?*info;?????? //定义一个fb_info类型的结构体指针
????int?res?=?0;??
??
?
????if?(fbidx?>=?FB_MAX)??
????????return?-ENODEV;??
#ifdef?CONFIG_KMOD??
????if?(!(info?=?registered_fb[fbidx]))??
????????try_to_load(fbidx);??
#endif?/*?CONFIG_KMOD?*/??
????if?(!(info?=?registered_fb[fbidx]))??//指针指向registered_fb[fbidx]
????????return?-ENODEV;??
????if?(!try_module_get(info->fbops->owner))??
????????return?-ENODEV;??
????file->private_data?=?info;??
????if?(info->fbops->fb_open)?{??
????????res?=?info->fbops->fb_open(info,1);??//调用registered_fb[fbidx]-> fbops->fb_open
????????if?(res)??
????????????module_put(info->fbops->owner);??
????}??
????return?res;??
}??
代码第4行,得到设备的次设备号fbidx?。
代码第5行,定义一个fb_info类型的结构体指针。
代码第14行,将第5行定义的指针info指向以次设备号为索引的registered_fb[fbidx]数组成员。
代码第20行,调用registered_fb[fbidx]-> fbops->fb_open打开函数。
由上述代码分析可知,registered_fb[fbidx]才是最终被用户空间调用的接口函数。那么数组registered_fb[]又是被谁赋值的,在哪里赋值呢?猜测一下,因为registered_fb[]数组中存放的就是和硬件相关的接口函数,所以应该在驱动层会有相关的注册函数,将实际的硬件接口和registered_fb[]数组关联起来。
通过搜索registered_fb,发现在register_framebuffer函数中有关于该数组的赋值操作。接下来来看看函数register_framebuffer。
int??
register_framebuffer(struct?fb_info?*fb_info)??
{??
????int?i;??
????struct?fb_event?event;??
????struct?fb_videomode?mode;??
??
?
????if?(num_registered_fb?==?FB_MAX)??
????????return?-ENXIO;??
????num_registered_fb++;??
????for?(i?=?0?;?i?<?FB_MAX;?i++)??
????????if?(!registered_fb[i])??
????????????break;??
????fb_info->node?=?i;??
??
?
????fb_info->dev?=?device_create(fb_class,?fb_info->device,??
?????????????????????MKDEV(FB_MAJOR,?i),?"fb%d",?i);??
????if?(IS_ERR(fb_info->dev))?{??
????????/*?Not?fatal?*/??
????????printk(KERN_WARNING?"Unable?to?create?device?for?framebuffer?%d;?errno?=?%ld\n",?i,?PTR_ERR(fb_info->dev));??
????????fb_info->dev?=?NULL;??
????}?else??
????????fb_init_device(fb_info);??
??
?
????if?(fb_info->pixmap.addr?==?NULL)?{??
????????fb_info->pixmap.addr?=?kmalloc(FBPIXMAPSIZE,?GFP_KERNEL);??
????????if?(fb_info->pixmap.addr)?{??
????????????fb_info->pixmap.size?=?FBPIXMAPSIZE;??
????????????fb_info->pixmap.buf_align?=?1;??
????????????fb_info->pixmap.scan_align?=?1;??
????????????fb_info->pixmap.access_align?=?32;??
????????????fb_info->pixmap.flags?=?FB_PIXMAP_DEFAULT;??
????????}??
????}?????
????fb_info->pixmap.offset?=?0;??
??
?
????if?(!fb_info->pixmap.blit_x)??
????????fb_info->pixmap.blit_x?=?~(u32)0;??
??
?
????if?(!fb_info->pixmap.blit_y)??
????????fb_info->pixmap.blit_y?=?~(u32)0;??
??
?
????if?(!fb_info->modelist.prev?||?!fb_info->modelist.next)??
????????INIT_LIST_HEAD(&fb_info->modelist);??
??
?
????fb_var_to_videomode(&mode,?&fb_info->var);??
????fb_add_videomode(&mode,?&fb_info->modelist);??
????registered_fb[i]?=?fb_info;??
??
?
????event.info?=?fb_info;??
????fb_notifier_call_chain(FB_EVENT_FB_REGISTERED,?&event);??
????return?0;??
}??
首先我们来看一下结构体fb_info,他是linux内核中为实现framebuffer驱动框架定义的驱动层接口,在Fb.h文件中定义。它包含了许多底层函数,还包括了有关设备状态的数据。每一个framebuffer设备都与一个fb_info结构体相对应。其代码如下:
(1)node成员代表framebuffer设备的次设备号;
(2)fb_var_screeninfo结构体是用户可修改的显示控制器参数;
struct?fb_var_screeninfo?{??
????__u32?xres;?????????/*?visible?resolution???????*/??
????__u32?yres;??
????__u32?xres_virtual;?????/*?virtual?resolution???????*/??
????__u32?yres_virtual;??
????__u32?xoffset;??????????/*?offset?from?virtual?to?visible?*/??
????__u32?yoffset;??????????/*?resolution???????????*/??
??
?
????__u32?bits_per_pixel;???????/*?guess?what???????????*/??
????__u32?grayscale;????????/*?!=?0?Graylevels?instead?of?colors?*/??
??
?
????struct?fb_bitfield?red;?????/*?bitfield?in?fb?mem?if?true?color,?*/??
????struct?fb_bitfield?green;???/*?else?only?length?is?significant?*/??
????struct?fb_bitfield?blue;??
????struct?fb_bitfield?transp;??/*?transparency?????????*/????
??
?
????......??
};??
(3)fb_fix_screeninfo成员主要记录用户不能修改的显示控制器参数;
(4)fbops结构体是提供给底层设备的一个接口,上面提到的open函数,就是该结构体的成员。编写字符设备驱动时就需要实现一个file_operations结构体,和这个结构体的作用类似。
(1)、代码第16行,在类下面创建一个设备;
(2)、代码第23行,初始化刚刚创建的设备;
(3)、代码第26行,申请一个framebuffer空间;
(4)、代码第27~47行,对申请的framebuffer空间进行配置;
(5)、代码第48行,将已经配置好的fb_info节点放到registered_fb[]数组中。
由上述分析可知,register_framebuffer函数主要用于生成一个新的fb_info节点,并将其存放到registered_fb[]数组中。那么该函数由谁调用呢?
搜索register_framebuffer函数,在s3c2410fb.c文件中,发现s3c2410fb_probe函数调用了注册函数。
那么这里就以s3c2410fb.c为例,来分析一下lcd驱动。
首先进入drivers/video/s3c2410fb.c文件中,从入口函数s3c2410fb_init开始。
int?__devinit?s3c2410fb_init(void)??
{??
????return?platform_driver_register(&s3c2410fb_driver);??
}??
入口函数中通过调用platform_driver_register函数注册平台驱动设备,说明该驱动时基于bus-drv-dev模型的,那么就将重点集中到probe函数上,即s3c2410fb_probe。
static?int?__init?s3c2410fb_probe(struct?platform_device?*pdev)??
{??
????struct?s3c2410fb_info?*info;??
????struct?fb_info?????*fbinfo;??
????struct?s3c2410fb_hw?*mregs;??
????int?ret;??
????int?irq;??
????int?i;??
????u32?lcdcon1;??
??//根据平台设备,获得某些硬件相关的信息
????mach_info?=?pdev->dev.platform_data;??
????mregs?=?&mach_info->regs;??
????irq?=?platform_get_irq(pdev,?0);??
?????//(1)申请一个?framebuffer空间
????fbinfo?=?framebuffer_alloc(sizeof(struct?s3c2410fb_info),?&pdev->dev);??
?????//(2)设置fbinfo
????info?=?fbinfo->par;??
????info->fb?=?fbinfo;??
????info->dev?=?&pdev->dev;??
????????.....??
??//(3)硬件相关的操作,设置中断,lcd时钟,显存地址,
????ret?=?request_irq(irq,?s3c2410fb_irq,?IRQF_DISABLED,?pdev->name,?info);??
????info->clk?=?clk_get(NULL,?"lcd");??
????clk_enable(info->clk);??
????msleep(1);??
??
?
????/*?Initialize?video?memory?*/??
????ret?=?s3c2410fb_map_video_memory(info);??
????ret?=?s3c2410fb_init_registers(info);??
????ret?=?s3c2410fb_check_var(&fbinfo->var,?fbinfo);??
??//(4)注册fbinfo结构体
????ret?=?register_framebuffer(fbinfo);??
????if?(ret?<?0)?{??
????????printk(KERN_ERR?"Failed?to?register?framebuffer?device:?%d\n",?ret);??
????????goto?free_video_memory;??
????}??
????/*?create?device?files?*/??
????device_create_file(&pdev->dev,?&dev_attr_debug);??
????return?0;??
???????.....??
}??
分析s3c2410fb_probe函数,大致可以梳理出framebuffer驱动的编写流程:
申请一个fbinfo?结构体空间;
设置fbinfo?;
硬件相关的操作;
注册fbinfo?。
?
4 linux lcd驱动框架分析
标签:技术 visible video phi v模型 int 包含 null oid
原文地址:https://www.cnblogs.com/beijiqie1104/p/11445225.html