如果我们的系统要用GUI(图形界面接口),这时LCD设备驱动程序就应该编写成frambuffer接口,而不是像之前那样只编写操作底层的LCD控制器接口。

什么是frambuffer设备?

frambuffer设备层是对图像设备的一种抽象,它代表了视频硬件的帧缓存,使得应用程序通过定义好的接口就可以访问硬件。所以应用程序不需要考虑底层的(寄存器级)的操作。应用程序对设备文件的访问一般在/dev目录,如 /dev/fb*。


内核中的frambuffer在drivers/video/fbmem.c(fb: frame buffer)

1.我们进入fbmem.c找到它的入口函数:

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))           //(1)创建字符设备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;
}

(1)创建字符设备"fb", FB_MAJOR=29,主设备号为29,我们cat /proc/devices 也能找到这个字符设备:

和我们之前的驱动程序一样,但是没有使用创建设备节点,为什么?

因为需要注册了LCD驱动后,才会有设备节点,所以这里的代码没有 ,后面会分析哪里有。

2.我们来看看注册的file_operations结构体fb_fops的.open函数和.read函数,应用层是如何打开驱动、读取驱动数据

2.1 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 (!(info = registered_fb[fbidx]))   //(1) info= registered_fb[fbidx],获取此设备号的lcd驱动信息try_to_load(fbidx);... ... if (info->fbops->fb_open) {          res = info->fbops->fb_open(info,1);  //调用registered_fb[fbidx]->fbops->fb_openif (res)module_put(info->fbops->owner);}return res;
}

(1) registered_fb[fbidx] 这个数组也是fb_info结构体,其中fbidx等于次设备号id,显然这个数组就是保存我们各个lcd驱动的信息

2.2 fb_read函数如下:

static ssize_t fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{unsigned long p = *ppos;struct inode *inode = file->f_path.dentry->d_inode; int fbidx = iminor(inode);                       //获取次设备号struct fb_info *info = registered_fb[fbidx];     //获取次设备号的lcd驱动的信息u32 *buffer, *dst;u32 __iomem *src;int c, i, cnt = 0, err = 0;unsigned long total_size;... ...if (info->fbops->fb_read)return info->fbops->fb_read(info, buf, count, ppos);total_size = info->screen_size;     //获取屏幕长度       ... ...buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count,GFP_KERNEL);    //分配缓冲区       if (!buffer)return -ENOMEM;src = (u32 __iomem *) (info->screen_base + p);         //获取显存物理基地址if (info->fbops->fb_sync)info->fbops->fb_sync(info); while (count) {c  = (count > PAGE_SIZE) ? PAGE_SIZE : count;   //获取页地址dst = buffer;         /*因为src是32位,一个src等于4个字节,所以页地址c >> 2*/for (i = c >> 2; i--; )                     *dst++ = fb_readl(src++);    //读取显存每个像素点数据,放到dst地址上if (c & 3) {u8 *dst8 = (u8 *) dst;u8 __iomem *src8 = (u8 __iomem *) src;for (i = c & 3; i--;)*dst8++ = fb_readb(src8++);src = (u32 __iomem *) src8;}if (copy_to_user(buf, buffer, c)) {  //上传数据,长度等于页地址大小err = -EFAULT;break;}*ppos += c;buf += c;cnt += c;count -= c;}kfree(buffer); return (err) ? err : cnt;
}

从.open和.write函数中可以发现,都依赖于fb_info帧缓冲信息结构体,它从registered_fb[fbidx]数组中得到,这个数组保存我们各个lcd驱动的信息

3.我们来找找这个数组在哪里被注册,位于register_framebuffer():

int register_framebuffer(struct fb_info *fb_info)
{... ...
for (i = 0 ; i < FB_MAX; i++)    //查找空的数组if (!registered_fb[i])break;fb_info->node = i;           ... .../*创建设备节点,名称为fdi,主设备号为29,次设备号为i   */
fb_info->dev = device_create(fb_class, fb_info->device,MKDEV(FB_MAJOR, i), "fb%d", i);... ...registered_fb[i] = fb_info;... ...
}

得出这个register_framebuffer()除了注册fb_info,还创建了设备节点

所以要注册驱动时就调用这个,如下图所示:

4.我们来看看/drivers/video/s3c2410fb.c 中又是怎么实现驱动的

4.1先找到入口出口函数:

int __devinit s3c2410fb_init(void)
{return platform_driver_register(&s3c2410fb_driver);
}static void __exit s3c2410fb_cleanup(void)
{platform_driver_unregister(&s3c2410fb_driver);
}

发现是注册、注销设备平台drv

4.2 来看看s3c2410fb_driver 如何定义的

static struct platform_driver s3c2410fb_driver = {.probe           = s3c2410fb_probe,        //检测函数,注册设备.remove         = s3c2410fb_remove,    //删除设备.suspend = s3c2410fb_suspend,          //休眠.resume          = s3c2410fb_resume,    //唤醒.driver            = {.name     = "s3c2410-lcd",           //drv名字.owner    = THIS_MODULE,},
};

和我们上节分析的platform机制一样,当与设备匹配成功,就进入probe函数,初始化驱动设备

4.3 来看看.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;     //获取LCD设备信息(长宽、类型等)if (mach_info == NULL) {dev_err(&pdev->dev,"no platform data for lcd, cannot attach\n");return -EINVAL;}mregs = &mach_info->regs;irq = platform_get_irq(pdev, 0);if (irq < 0) {dev_err(&pdev->dev, "no irq for device\n");return -ENOENT;}fbinfo = framebuffer_alloc(sizeof(struct s3c2410fb_info), &pdev->dev); //1.分配一个fb_info结构体if (!fbinfo) {return -ENOMEM;}/*2.设置fb_info*/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);                                  //使能时钟ret = s3c2410fb_map_video_memory(info);               //显存地址  ret = s3c2410fb_init_registers(info);                //设置寄存器,配置引脚... ...ret = register_framebuffer(fbinfo);        //4.注册一个fb_info结构体if (ret < 0) {printk(KERN_ERR "Failed to register framebuffer device: %d\n", ret);goto free_video_memory;}
... ...
return ret;
}

4.4 显然要写个LCD驱动程序,需要以下4步:

1) 分配一个fb_info结构体: framebuffer_alloc();

2) 设置fb_info

3) 硬件相关的操作(设置中断,LCD时钟频率,显存地址, 配置引脚... ...)

4 注册fb_info: register_framebuffer()

下节就开始如何来写LCD驱动

(LCD驱动详解入口地址: http://www.cnblogs.com/lifexy/p/7604011.html)

转载于:https://www.cnblogs.com/lifexy/p/7603327.html

15.linux-LCD层次分析(详解)相关推荐

  1. Linux LCD设备驱动详解

    本文是基于mini2440开发板Linux版本号是linux-2.6.32.2的学习笔记 一. LCD device硬件信息 1.LCD控制器的寄存器地址从 0X4D000000开始 2.lcd de ...

  2. linux软件逆向分析,详解对ELF64之手动脱壳的逆向分析

    应一位朋友之邀,对"吾爱论坛'ELF64手脱upx壳实战'一文"进行了再重现,考虑到朋友他对原文过程理解不深,特抽空行文,着重对每个步骤.每个知识点进行了分解,现共享出来以回馈社会 ...

  3. 《linux设备驱动开发详解》笔记——15 linux i2c驱动

    <linux设备驱动开发详解>笔记--15 linux i2c驱动 15.1 总体结构 如下图,i2c驱动分为如下几个重要模块 核心层core,完成i2c总线.设备.驱动模型,对用户提供s ...

  4. 《Linux设备驱动开发详解(第2版)》隆重出版

    Linux设备驱动开发详解(第2版)(前一版狂销3万册,畅销书最新升级) [新品] 点击看大图     基本信息 * 作者: 宋宝华       * 出版社:人民邮电出版社     * ISBN:97 ...

  5. linux设备驱动总结,《Linux设备驱动开发详解(第3版)》海量更新总结

    本博实时更新<Linux设备驱动开发详解(第3版)>的最新进展. 2015.2.26 几乎完成初稿. [F]是修正或升级:[N]是新增知识点:[D]是删除的内容 第1章 <Linux ...

  6. 《Linux设备驱动开发详解(第3版)》(即《Linux设备驱动开发详解:基于最新的Linux 4.0内核》)进展同步更新

    本博实时更新<Linux设备驱动开发详解(第3版)>的最新进展. 目前已经完成稿件. 2015年8月9日,china-pub开始上线预售: http://product.china-pub ...

  7. 【转】Linux命令工具 top详解

    Linux命令工具 top详解 top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,类似于Windows的任务管理器.top是一个动态显示过程,即可以通过用户按键来不 ...

  8. Linux系统守护进程详解

    文中有不对或者有不清楚的地方,请大家告诉我,谢谢!   Linux系统守护进程详解 不要关闭下面这几个服务: acpid, haldaemon, messagebus, klogd, network, ...

  9. linux设备驱动开发详解源码,linux设备驱动开发详解光盘源码.rar

    压缩包 : linux设备驱动开发详解光盘源码.rar 列表 19/busybox源代码/busybox-1.2.1.tar.bz2 19/MTD工具/mtd-utils-1.0.0.tar.gz 1 ...

最新文章

  1. 问题-[VMware Workstation]断电后,重启电脑,之后就提示“内部错误”
  2. Bootstrap-table学习笔记(二)——前后端分页模糊查询
  3. FeignClient使用
  4. 从 Vue 1.x 迁移 — Vue.js
  5. java什么时候新建进程_创建名为“ {java}”的线程(即轻量级进程)是为了什么?...
  6. 基于 MaxCompute 的实时数据处理实践
  7. 有人说中文编辑是解决中国程序员编程效率的秘密武器,请问他是一个银弹吗?...
  8. Airflow 中文文档:数据分析
  9. springboot中使用@Value读取配置文件
  10. 编写程序也需要在实战中成长
  11. BizTalk Server 2010 - 使用 WCF Service [ 中篇 ]
  12. java 异常抛出_Java 如何抛出异常、自定义异常、手动或主动抛出异常
  13. 金蝶应收应付模块流程_金蝶财务软件里的应收应付模块核算哪些会生
  14. python怎么实现eemd_EEMD算法原理与python实现
  15. 白嫖亚马逊AWS服务器
  16. vue实现文件下载功能
  17. 一网打尽“小黄图”!手把手教你造一只AI鉴黄神器(内附代码及数据集)
  18. 常用的logo设计技巧
  19. r720服务器怎么查看硬盘性能,r720服务器如何看配置
  20. 微博2面:微信朋友圈是怎么实现的?

热门文章

  1. 配置Open***使用User/Pass方式验证登录
  2. Context-Based Access Control (CBAC) 基于上下文的访问控制 理论知识
  3. Exchange笔记之使用OWA加密访问邮箱
  4. 关于Java中各种修饰符与访问修饰符的说明
  5. mysql中leave和_MySQL数据库之Mysql存储过程使用LEAVE实现MSSQL存储过程中return语法
  6. 递归 尾递归_代码简报:递归,递归,递归
  7. 逻辑覆盖测试(六)--路径测试
  8. 小说站 章节内容 ajax,第17章 作业分析与异步编程原理——2019年5月14日22:00
  9. 找Java培训机构需要注意那些
  10. novaclient的api调用流程与开发