4 linux lcd驱动框架分析

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的代码。

  1. static?int?__init??
  2. fbmem_init(void)??
  3. {??
  4. ????create_proc_read_entry("fb",?0,?NULL,?fbmem_read_proc,?NULL);??
  5. ??
    ?
  6. ????if?(register_chrdev(FB_MAJOR,"fb",&fb_fops))??//注册一个字符设备
  7. ????????printk("unable?to?get?major?%d?for?fb?devs\n",?FB_MAJOR);??
  8. ??
    ?
  9. ????fb_class?=?class_create(THIS_MODULE,?"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. }??

从上述代码可以看到,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函数。

  1. static?int??
  2. fb_open(struct?inode?*inode,?struct?file?*file)??
  3. {??
  4. ????int?fbidx?=?iminor(inode);??//得到次设备号
  5. ????struct?fb_info?*info;?????? //定义一个fb_info类型的结构体指针
  6. ????int?res?=?0;??
  7. ??
    ?
  8. ????if?(fbidx?>=?FB_MAX)??
  9. ????????return?-ENODEV;??
  10. #ifdef?CONFIG_KMOD??
  11. ????if?(!(info?=?registered_fb[fbidx]))??
  12. ????????try_to_load(fbidx);??
  13. #endif?/*?CONFIG_KMOD?*/??
  14. ????if?(!(info?=?registered_fb[fbidx]))??//指针指向registered_fb[fbidx]
  15. ????????return?-ENODEV;??
  16. ????if?(!try_module_get(info->fbops->owner))??
  17. ????????return?-ENODEV;??
  18. ????file->private_data?=?info;??
  19. ????if?(info->fbops->fb_open)?{??
  20. ????????res?=?info->fbops->fb_open(info,1);??//调用registered_fb[fbidx]-> fbops->fb_open
  21. ????????if?(res)??
  22. ????????????module_put(info->fbops->owner);??
  23. ????}??
  24. ????return?res;??
  25. }??

    1. 代码第4行,得到设备的次设备号fbidx?。
    2. 代码第5行,定义一个fb_info类型的结构体指针。
    3. 代码第14行,将第5行定义的指针info指向以次设备号为索引的registered_fb[fbidx]数组成员。
    4. 代码第20行,调用registered_fb[fbidx]-> fbops->fb_open打开函数。

由上述代码分析可知,registered_fb[fbidx]才是最终被用户空间调用的接口函数。那么数组registered_fb[]又是被谁赋值的,在哪里赋值呢?猜测一下,因为registered_fb[]数组中存放的就是和硬件相关的接口函数,所以应该在驱动层会有相关的注册函数,将实际的硬件接口和registered_fb[]数组关联起来。

通过搜索registered_fb,发现在register_framebuffer函数中有关于该数组的赋值操作。接下来来看看函数register_framebuffer。

  1. int??
  2. register_framebuffer(struct?fb_info?*fb_info)??
  3. {??
  4. ????int?i;??
  5. ????struct?fb_event?event;??
  6. ????struct?fb_videomode?mode;??
  7. ??
    ?
  8. ????if?(num_registered_fb?==?FB_MAX)??
  9. ????????return?-ENXIO;??
  10. ????num_registered_fb++;??
  11. ????for?(i?=?0?;?i?<?FB_MAX;?i++)??
  12. ????????if?(!registered_fb[i])??
  13. ????????????break;??
  14. ????fb_info->node?=?i;??
  15. ??
    ?
  16. ????fb_info->dev?=?device_create(fb_class,?fb_info->device,??
  17. ?????????????????????MKDEV(FB_MAJOR,?i),?"fb%d",?i);??
  18. ????if?(IS_ERR(fb_info->dev))?{??
  19. ????????/*?Not?fatal?*/??
  20. ????????printk(KERN_WARNING?"Unable?to?create?device?for?framebuffer?%d;?errno?=?%ld\n",?i,?PTR_ERR(fb_info->dev));??
  21. ????????fb_info->dev?=?NULL;??
  22. ????}?else??
  23. ????????fb_init_device(fb_info);??
  24. ??
    ?
  25. ????if?(fb_info->pixmap.addr?==?NULL)?{??
  26. ????????fb_info->pixmap.addr?=?kmalloc(FBPIXMAPSIZE,?GFP_KERNEL);??
  27. ????????if?(fb_info->pixmap.addr)?{??
  28. ????????????fb_info->pixmap.size?=?FBPIXMAPSIZE;??
  29. ????????????fb_info->pixmap.buf_align?=?1;??
  30. ????????????fb_info->pixmap.scan_align?=?1;??
  31. ????????????fb_info->pixmap.access_align?=?32;??
  32. ????????????fb_info->pixmap.flags?=?FB_PIXMAP_DEFAULT;??
  33. ????????}??
  34. ????}?????
  35. ????fb_info->pixmap.offset?=?0;??
  36. ??
    ?
  37. ????if?(!fb_info->pixmap.blit_x)??
  38. ????????fb_info->pixmap.blit_x?=?~(u32)0;??
  39. ??
    ?
  40. ????if?(!fb_info->pixmap.blit_y)??
  41. ????????fb_info->pixmap.blit_y?=?~(u32)0;??
  42. ??
    ?
  43. ????if?(!fb_info->modelist.prev?||?!fb_info->modelist.next)??
  44. ????????INIT_LIST_HEAD(&fb_info->modelist);??
  45. ??
    ?
  46. ????fb_var_to_videomode(&mode,?&fb_info->var);??
  47. ????fb_add_videomode(&mode,?&fb_info->modelist);??
  48. ????registered_fb[i]?=?fb_info;??
  49. ??
    ?
  50. ????event.info?=?fb_info;??
  51. ????fb_notifier_call_chain(FB_EVENT_FB_REGISTERED,?&event);??
  52. ????return?0;??
  53. }??

首先我们来看一下结构体fb_info,他是linux内核中为实现framebuffer驱动框架定义的驱动层接口,在Fb.h文件中定义。它包含了许多底层函数,还包括了有关设备状态的数据。每一个framebuffer设备都与一个fb_info结构体相对应。其代码如下:

(1)node成员代表framebuffer设备的次设备号;

(2)fb_var_screeninfo结构体是用户可修改的显示控制器参数;

  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. ????......??
  18. };??

(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开始。

  1. int?__devinit?s3c2410fb_init(void)??
  2. {??
  3. ????return?platform_driver_register(&s3c2410fb_driver);??
  4. }??

入口函数中通过调用platform_driver_register函数注册平台驱动设备,说明该驱动时基于bus-drv-dev模型的,那么就将重点集中到probe函数上,即s3c2410fb_probe。

  1. static?int?__init?s3c2410fb_probe(struct?platform_device?*pdev)??
  2. {??
  3. ????struct?s3c2410fb_info?*info;??
  4. ????struct?fb_info?????*fbinfo;??
  5. ????struct?s3c2410fb_hw?*mregs;??
  6. ????int?ret;??
  7. ????int?irq;??
  8. ????int?i;??
  9. ????u32?lcdcon1;??
  10. ??//根据平台设备,获得某些硬件相关的信息
  11. ????mach_info?=?pdev->dev.platform_data;??
  12. ????mregs?=?&mach_info->regs;??
  13. ????irq?=?platform_get_irq(pdev,?0);??
  14. ?????//(1)申请一个?framebuffer空间
  15. ????fbinfo?=?framebuffer_alloc(sizeof(struct?s3c2410fb_info),?&pdev->dev);??
  16. ?????//(2)设置fbinfo
  17. ????info?=?fbinfo->par;??
  18. ????info->fb?=?fbinfo;??
  19. ????info->dev?=?&pdev->dev;??
  20. ????????.....??
  21. ??//(3)硬件相关的操作,设置中断,lcd时钟,显存地址,
  22. ????ret?=?request_irq(irq,?s3c2410fb_irq,?IRQF_DISABLED,?pdev->name,?info);??
  23. ????info->clk?=?clk_get(NULL,?"lcd");??
  24. ????clk_enable(info->clk);??
  25. ????msleep(1);??
  26. ??
    ?
  27. ????/*?Initialize?video?memory?*/??
  28. ????ret?=?s3c2410fb_map_video_memory(info);??
  29. ????ret?=?s3c2410fb_init_registers(info);??
  30. ????ret?=?s3c2410fb_check_var(&fbinfo->var,?fbinfo);??
  31. ??//(4)注册fbinfo结构体
  32. ????ret?=?register_framebuffer(fbinfo);??
  33. ????if?(ret?<?0)?{??
  34. ????????printk(KERN_ERR?"Failed?to?register?framebuffer?device:?%d\n",?ret);??
  35. ????????goto?free_video_memory;??
  36. ????}??
  37. ????/*?create?device?files?*/??
  38. ????device_create_file(&pdev->dev,?&dev_attr_debug);??
  39. ????return?0;??
  40. ???????.....??
  41. }??

分析s3c2410fb_probe函数,大致可以梳理出framebuffer驱动的编写流程:

  1. 申请一个fbinfo?结构体空间;
  2. 设置fbinfo?;
  3. 硬件相关的操作;
  4. 注册fbinfo?。

?

原文地址:https://www.cnblogs.com/beijiqie1104/p/11445225.html

时间: 2024-10-17 16:02:58

4 linux lcd驱动框架分析的相关文章

Linux USB驱动框架分析 【转】

转自:http://blog.chinaunix.net/uid-11848011-id-96188.html 初次接触与OS相关的设备驱动编写,感觉还挺有意思的,为了不至于忘掉看过的东西,笔记跟总结当然不可缺,更何况我决定为嵌入式卖命了.好,言归正传,我说一说这段时间的收获,跟大家分享一下Linux的驱动开发.但这次只先针对Linux的USB子系统作分析,因为周五研讨老板催货.当然,还会顺带提一下其他的驱动程序写法. 事实上,Linux的设备驱动都遵循一个惯例——表征驱动程序(用driver更

Linux USB驱动框架分析(2)【转】

转自:http://blog.chinaunix.net/uid-23046336-id-3243543.html 看了http://blog.chinaunix.net/uid-11848011-id-96188.html的驱动框架分析,感觉受益匪浅.对于一些内容,我自己查漏补缺. 首先我们按照顺序,看内核模块的注册以及释放函数如下: 点击(此处)折叠或打开 static int __init usb_skel_init(void) { int result; /* register this

7 Linux usb驱动框架分析

现象:将USB设备接入PC,PC右下角上会弹出"发现xx新设备",例如"发现andriod phone"若PC上没有安装该设备的驱动程序,则会弹出对话框提示"安装驱动程序". 问1:没有安装设备的驱动程序之前,为什么PC还能发现andriod phone设备呢? 答1:windows系统中已经安装了USB的"总线驱动程序",是"总线驱动程序"发现了新的设备,而提示我们安装的是"设备驱动程序&quo

Linux Framebuffer 驱动框架之一概念介绍及LCD硬件原理【转】

本文转载自:http://blog.csdn.net/liuxd3000/article/details/17464779 一.基本概念 帧缓冲(Framebuffer)是Linux系统为显示设备提供的一个接口,它将显示缓冲区抽象,屏蔽图像硬件的底层差异,允许上层应用程序在图形模式下直接对显示缓冲区进行读写操作.用户不必关心物理显示缓冲区的具体位置及存放方式,这些都是由帧缓冲设备驱动本身来完成.对于帧缓冲设备而言,只要在显示缓冲区与显示点对应的区域写入颜色值,对应的颜色会自动在屏幕上显示,下一小

Linux LCD驱动(四)--驱动的实现

目录(?)[-] 基本原理 写 framebuffer 驱动程序要做什么 LCD 模块 驱动程序 控制器 什么是 frame buffer 设备 Linux Frame Buffer 驱动程序层次结构 数据结构 接口 一个 LCD controller 驱动程序 分配系统内存作为显存 实现 fb_ops 结构 基本原理 通过 framebuffer ,应用程序用 mmap 把显存映射到应用程序虚拟地址空间,将要显示的数据写入这个内存空间就可以在屏幕上显示出来: 驱动程序分配系统内存作为显存:实现

MTK平台LCD驱动框架详解(一)

许多学习嵌入式的进入MTK开发平台,很多东西都会感到很陌生.在MTK平台上你可以简简单单几分钟就点亮一块屏.加上MTK快速开发的节奏,也很少有时间自己整理学习.如果不思进取,不加班加点学习.很容易就慢慢--.这也难怪有些人说MTK造就了一批懒人,毁掉了一批工程师.但其实都是基于linux开发,核心的东西都是一样一样的.我刚入行业,在迷茫之际,自己整理跟踪源码.想慢慢找回自己熟悉的感觉,掌握MTK的整体框架.也希望能给有需要的人带来些帮助.好吧!前话说到这,开始正题. 本文肯定有不少地方会出现错误

10. LCD驱动程序 ——框架分析

引言: 由LCD的硬件原理及操作(可参看韦哥博客:第017课 LCD原理详解及裸机程序分析) 我们知道只要LCD控制器的相关寄存器正确配置好,就可以在LCD面板上显示framebuffer中的内容. 若应用程序需要在LCD屏幕上显示文字或图像时,只需要把相应的显示内容以正确的格式写到Framebuffer中即可. (Framebuffer,中文名字是帧缓冲,这个帧也就是一副图像所需要的数据.因此,帧缓冲其实就是LCD设备的驱动程序) 一.LCD驱动程序框架 根据上述思路,Linux LCD 驱动

Linux LCD驱动(三)--图形显示

3.  BMP和JPEG图形显示程序3.1  在LCD上显示BMP或JPEG图片的主流程图首先,在程序开始前.要在nfs/dev目录下创建LCD的设备结点,设备名fb0,设备类型为字符设备,主设备号为29,次设备号为0.命令如下:mknod fb0 c 29 0在LCD上显示图象的主流程图如图3.1所示.程序一开始要调用open函数打开设备,然后调用ioctl获取设备相关信息,接下来就是读取图形文件数据,把图象的RGB值映射到显存中,这部分是图象显示的核心.对于JPEG格式的图片,要先经过JPE

Linux输入子系统框架分析(1)

在Linux下的输入设备键盘.触摸屏.鼠标等都可以用输入子系统来实现驱动.输入子系统分为三层,核心层和设备驱动层,事件层.核心层和事件层由Linux输入子系统本身实现,设备驱动层由我们实现.我们在设备驱动层将输入事件上报给核心层input.c,核心层找到匹配的事件层,将事件交给事件层处理,事件层处理完后传递到用户空间. 我们最终要搞清楚的是在用户空间调用open和read最终在内核中是怎样处理的,向内核上报的事件又是谁处理的,处理完后是怎样传递到用户空间的? 上面两个图是输入子系统的框架. 下面