0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

嵌入式驱动的构造分析总结

Q4MP_gh_c472c21 2018-03-03 09:23 次阅读

Linux系统上编写驱动程序,说简单也简单,说难也难。难在于对算法的编写和设备的控制方面,是比较让人头疼的;说它简单是因为在Linux下已经有一套驱动开发的模式,编写的时候只需要按照这个模式写就可以了,而这个模式就是它事先定义好的一些结构体,在驱动编写的时候,只要对这些结构体根据设备的需求进行适当的填充,就实现了驱动的编写。

首先在Linux下,视一切事物皆为文件,它同样把驱动设备也看成是文件,对于简单的文件操作,无非就是open/close/read/write,在Linux对于文件的操作有一个关键的数据结构:file_operation,它的定义在源码目录下的include/linux/fs.h中,内容如下:

[cpp]view plaincopy

1.structfile_operations{

2.structmodule*owner;

3.loff_t(*llseek)(structfile*,loff_t,int);

4.ssize_t(*read)(structfile*,char__user*,size_t,loff_t*);

5.ssize_t(*write)(structfile*,constchar__user*,size_t,loff_t*);

6.ssize_t(*aio_read)(structkiocb*,conststructiovec*,unsignedlong,loff_t);

7.ssize_t(*aio_write)(structkiocb*,conststructiovec*,unsignedlong,loff_t);

8.int(*readdir)(structfile*,void*,filldir_t);

9.unsignedint(*poll)(structfile*,structpoll_table_struct*);

10.int(*ioctl)(structinode*,structfile*,unsignedint,unsignedlong);

11.long(*unlocked_ioctl)(structfile*,unsignedint,unsignedlong);

12.long(*compat_ioctl)(structfile*,unsignedint,unsignedlong);

13.int(*mmap)(structfile*,structvm_area_struct*);

14.int(*open)(structinode*,structfile*);

15.int(*flush)(structfile*,fl_owner_tid);

16.int(*release)(structinode*,structfile*);

17.int(*fsync)(structfile*,intdatasync);

18.int(*aio_fsync)(structkiocb*,intdatasync);

19.int(*fasync)(int,structfile*,int);

20.int(*lock)(structfile*,int,structfile_lock*);

21.ssize_t(*sendpage)(structfile*,structpage*,int,size_t,loff_t*,int);

22.unsignedlong(*get_unmapped_area)(structfile*,unsignedlong,unsignedlong,unsignedlong,unsignedlong);

23.int(*check_flags)(int);

24.int(*flock)(structfile*,int,structfile_lock*);

25.ssize_t(*splice_write)(structpipe_inode_info*,structfile*,loff_t*,size_t,unsignedint);

26.ssize_t(*splice_read)(structfile*,loff_t*,structpipe_inode_info*,size_t,unsignedint);

27.int(*setlease)(structfile*,long,structfile_lock**);

28.};

对于这个结构体中的元素来说,大家可以看到每个函数名前都有一个“*”,所以它们都是指向函数的指针。目前我们只需要关心

ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);

ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);

int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);

int (*open) (struct inode *, struct file *);

int (*release) (struct inode *, struct file *);

这几条,因为这篇文章就叫简单驱动。就是读(read)、写(write)、控制(ioctl)、打开(open)、卸载(release)。这个结构体在驱动中的作用就是把系统调用和驱动程序关联起来,它本身就是一系列指针的集合,每一个都对应一个系统调用。

但是毕竟file_operation是针对文件定义的一个结构体,所以在写驱动时,其中有一些元素是用不到的,所以在2.6版本引入了一个针对驱动的结构体框架:platform,它是通过结构体platform_device来描述设备,用platform_driver描述设备驱动,它们都在源代码目录下的include/linux/platform_device.h中定义,内容如下:

[cpp]view plaincopy

1.structplatform_device{

2.constchar*name;

3.intid;

4.structdevicedev;

5.u32num_resources;

6.structresource*resource;

7.conststructplatform_device_id*id_entry;

8./*archspecificadditions*/

9.structpdev_archdataarchdata;

10.};

11.structplatform_driver{

12.int(*probe)(structplatform_device*);

13.int(*remove)(structplatform_device*);

14.void(*shutdown)(structplatform_device*);

15.int(*suspend)(structplatform_device*,pm_message_tstate);

16.int(*resume)(structplatform_device*);

17.structdevice_driverdriver;

18.conststructplatform_device_id*id_table;

19.};

对于第一个结构体来说,它的作用就是给一个设备进行登记作用,相当于设备的身份证,要有姓名,身份证号,还有你的住址,当然其他一些东西就直接从旧身份证上copy过来,这就是其中的struct device dev,这是传统设备的一个封装,基本就是copy的意思了。对于第二个结构体,因为Linux源代码都是C语言编写的,对于这里它是利用结构体和函数指针,来实现了C语言中没有的“类”这一种结构,使得驱动模型成为一个面向对象的结构。对于其中的struct device_driver driver,它是描述设备驱动的基本数据结构,它是在源代码目录下的include/linux/device.h中定义的,内容如下:

[cpp]view plaincopy

1.structdevice_driver{

2.constchar*name;

3.structbus_type*bus;

4.structmodule*owner;

5.constchar*mod_name;/*usedforbuilt-inmodules*/

6.boolsuppress_bind_attrs;/*disablesbind/unbindviasysfs*/

7.#ifdefined(CONFIG_OF)

8.conststructof_device_id*of_match_table;

9.#endif

10.int(*probe)(structdevice*dev);

11.int(*remove)(structdevice*dev);

12.void(*shutdown)(structdevice*dev);

13.int(*suspend)(structdevice*dev,pm_message_tstate);

14.int(*resume)(structdevice*dev);

15.conststructattribute_group**groups;

16.conststructdev_pm_ops*pm;

17.structdriver_private*p;

18.};

依然全部都是以指针的形式定义的所有元素,对于驱动这一块来说,每一项肯定都是需要一个函数来实现的,如果不把它们集合起来,是很难管理的,而且很容易找不到,而且对于不同的驱动设备,它的每一个功能的函数名必定是不一样的,那么我们在开发的时候,需要用到这些函数的时候,就会很不方便,不可能在使用的时候去查找对应的源代码吧,所以就要进行一个封装,对于函数的封装,在C语言中一个对好的办法就是在结构体中使用指向函数的指针,这种方法其实我们在平时的程序开发中也可以使用,原则就是体现出一个“类”的感觉,就是面向对象的思想。

在Linux系统中,设备可以大致分为3类:字符设备、块设备和网络设备,而每种设备中又分为不同的子系统,由于具有自身的一些特殊性质,所以有不能归到某个已经存在的子类中,所以可以说是便于管理,也可以说是为了达到同一种定义模式,所以linux系统把这些子系统归为一个新类:misc ,以结构体miscdevice描述,在源代码目录下的include/linux/miscdevice.h中定义,内容如下:

[cpp]view plaincopy

1.structmiscdevice{

2.intminor;

3.constchar*name;

4.conststructfile_operations*fops;

5.structlist_headlist;

6.structdevice*parent;

7.structdevice*this_device;

8.constchar*nodename;

9.mode_tmode;

10.};

对于这些设备,它们都拥有一个共同主设备号10,所以它们是以次设备号来区分的,对于它里面的元素,大应该很眼熟吧,而且还有一个我们更熟悉的list_head的元素,这里也可以应证我之前说的list_head就是一个桥梁的说法了。

其实对于上面介绍的结构体,里面的元素的作用基本可以见名思意了,所以不用赘述了。其实写一个驱动模块就是填充上述的结构体,根据设备的功能和用途写相应的函数,然后对应到结构体中的指针,然后再写一个入口一个出口(就是模块编程中的init和exit)就可以了,一般情况下入口程序就是在注册platform_device和platform_driver(当然,这样说是针对以platform模式编写驱动程序)。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 嵌入式
    +关注

    关注

    5051

    文章

    18879

    浏览量

    300323

原文标题:搞嵌入式Linux驱动说简单也简单,说难也难!嵌入式驱动的结构分析

文章出处:【微信号:gh_c472c2199c88,微信公众号:嵌入式微处理器】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    嵌入式Linux命令总结

    嵌入式Linux命令总结
    发表于 09-19 16:30 468次阅读

    如何构造运行良好的嵌入式设备的驱动程序?

    嵌入式系统需要支持的外部设备种类繁多,如何构造运行良好的嵌入式设备的驱动程序,对嵌入式操作系统的实际应用有重要意义。
    发表于 09-25 07:44

    嵌入式linux学习方法总结

    嵌入式linux学习方法总结 嵌入式linux的学习现在挺流行
    发表于 09-10 10:44 3511次阅读

    ARM嵌入式系统的问题总结分析

    摘要: 本文是作者关于嵌入式系统一些基本问题的思考和总结。主要是从嵌入式处理器与硬件、ARM处
    发表于 11-17 18:28 761次阅读

    精通嵌入式Linux编程—构造自己的GUI环境

    精通嵌入式Linux编程—构造自己的GUI环境
    发表于 10-30 09:04 16次下载
    精通<b class='flag-5'>嵌入式</b>Linux编程—<b class='flag-5'>构造</b>自己的GUI环境

    基于嵌入式Linux LCD设备驱动分析

    基于嵌入式Linux LCD设备驱动分析
    发表于 10-30 16:20 14次下载
    基于<b class='flag-5'>嵌入式</b>Linux LCD设备<b class='flag-5'>驱动</b><b class='flag-5'>分析</b>

    嵌入式Linux设备驱动程序开发基础知识总结免费下载

    本文档的主要内容详细介绍的是嵌入式Linux设备驱动程序开发基础知识总结免费下载 嵌入式Linux设备驱动程序分类静态加载的
    发表于 10-23 16:10 13次下载

    嵌入式系统论文总结

    嵌入式系统论文总结(嵌入式开发用什么编程语言)-该文档为嵌入式系统论文总结文档,是一份很不错的参考资料,具有较高参考价值,感兴趣的可以下载看
    发表于 07-30 10:19 8次下载
    <b class='flag-5'>嵌入式</b>系统论文<b class='flag-5'>总结</b>

    嵌入式知识点总结

    嵌入式知识点总结(arm嵌入式开发led过程)-嵌入式知识点总结                    
    发表于 07-30 14:20 23次下载
    <b class='flag-5'>嵌入式</b>知识点<b class='flag-5'>总结</b>

    arm嵌入式系统基础总结教程

    arm嵌入式系统基础总结教程(嵌入式开发板有哪些外设)-该文档为arm嵌入式系统基础总结教程文档,是一份很不错的参考资料,具有较高参考价值,
    发表于 08-04 11:15 6次下载
    arm<b class='flag-5'>嵌入式</b>系统基础<b class='flag-5'>总结</b>教程

    嵌入式】基于ARM的嵌入式Linux开发总结

    --arm-linux进程编程嵌入式知识点复习六 --arm-linux网络编程嵌入式知识点复习七 --linux字符型设备驱动初步嵌入式知识点复习一1、
    发表于 10-19 18:32 26次下载
    【<b class='flag-5'>嵌入式</b>】基于ARM的<b class='flag-5'>嵌入式</b>Linux开发<b class='flag-5'>总结</b>

    嵌入式驱动组成概论3.9

    嵌入式系统的组成:嵌入式设备的组成:硬件CPUi/o内存软件系统软件:应用软件:未来工作方向:硬件软件:1.嵌入式系统工程师:设计、开发嵌入式系统;
    发表于 10-19 18:33 3次下载
    <b class='flag-5'>嵌入式</b><b class='flag-5'>驱动</b>组成概论3.9

    三级嵌入式总结

    三级嵌入式总结嵌入式系统• 嵌入式系统上的软件具有结构精简,代码轻量化,占用存储资源少的特点。• 嵌入式系统和计算机操作系统的共同特征是:
    发表于 10-20 14:51 8次下载
    三级<b class='flag-5'>嵌入式</b><b class='flag-5'>总结</b>

    嵌入式分层概括总结

    最近重新进入嵌入式领域,有必要对嵌入式分层架构有一个清晰的理解。经过多方查阅以及个人的理解,本人对嵌入式分层架构概括总结如下:比较细的层次由下到上可分为:(硬件层) 硬件
    发表于 10-21 10:51 11次下载
    <b class='flag-5'>嵌入式</b>分层概括<b class='flag-5'>总结</b>

    嵌入式linux编译 ko,嵌入式linux:编译linux驱动模块

    嵌入式系统应用中,嵌入式linux是非常重要的一个方面,而linux驱动编译又是嵌入式linux中至关重要的一个环节。下面,本文将详细讲解如何编译linux
    发表于 11-01 16:31 9次下载
    <b class='flag-5'>嵌入式</b>linux编译 ko,<b class='flag-5'>嵌入式</b>linux:编译linux<b class='flag-5'>驱动</b>模块