Chinaunix首页 | 论坛 | 博客
  • 博客访问: 353507
  • 博文数量: 127
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 333
  • 用 户 组: 普通用户
  • 注册时间: 2013-03-27 14:44
个人简介

兴趣是最好的学习契机!

文章分类

全部博文(127)

文章存档

2017年(1)

2016年(3)

2015年(54)

2014年(58)

2013年(11)

我的朋友

分类: LINUX

2014-10-12 00:15:53

1linux内核模块简介:

在前一章节讲到了自己写的驱动可以通过修改KconfigMakefile等来加载到内核中,今天这里讲的是如何通过模块的方式把自己写的驱动加载到内核。

2,内核模块主要由如下几部分组成:

(1)           模块加载函数

(2)           模块卸载函数

(3)           模块许可证声明(常用的有Dual BSD/GPL,GPL,等)

(4)           模块参数(可选)它指的是模块被加载的时候可以传递给它的值,它本身对应模块内部的全局变量。例如P88页中讲到的一个带模块参数的例子:
insmod book.ko book_name=”GOOD BOOK” num=5000

(5)           模块导出符号(可选)导出的符号可以被其他模块使用,在使用之前只需声明一下。

(6)           模块作者等声明信息(可选)

以下是一个典型的内核模块:

  1. /*
  2.  * A kernel module: book
  3.  * This example is to introduce module params
  4.  *
  5.  * The initial developer of the original code is Baohua Song
  6.  * <author@linuxdriver.cn>. All Rights Reserved.
  7.  */

  8. #include <linux/init.h>
  9. #include <linux/module.h>

  10. static char *book_name = “dissecting Linux Device Driver”;
  11. static int num = 4000;

  12. static int book_init(void)
  13. {
  14.         printk(KERN_INFO “ book name:%s\n”,book_name);
  15.         printk(KERN_INFO “ book num:%d\n”,num);
  16.         return 0;
  17. }

  18. static void book_exit(void)
  19. {
  20.         printk(KERN_INFO “ Book module exit\n “);
  21. }

  22. module_init(book_init);
  23. module_exit(book_exit);
  24. module_param(num, int, S_IRUGO);
  25. module_param(book_name, charp, S_IRUGO);
  26. MODULE_AUTHOR(“Song Baohua, author@linuxdriver.cn”);
  27. MODULE_LICENSE(“Dual BSD/GPL”);
  28. MODULE_DESCRIPTION(“A simple Module for testing module params”);
  29. MODULE_VERSION(“V1.0”);

注意:标有__init的函数在链接的时候都放在.init.text段,在.initcall.init中还保存了一份函数指针,初始化的时候内核会通过这些函数指针调用__init函数,在初始化完成后释放init区段。

3,模块编译常用模版:

  1. KVERS = $(shell uname -r)
  2. # Kernel modules
  3. obj-m += book.o
  4. # Specify flags for the module compilation.
  5. #EXTRA_CFLAGS=-g -O0
  6. build: kernel_modules
  7. kernel_modules:
  8.         make -C /lib/modules/$(KVERS)/build M=$(CURDIR) modules

  9. clean:
  10.         make -C /lib/modules/$(KVERS)/build M=$(CURDIR) clean

注意要指明内核版本,并且内核版本要匹配——编译模块使用的内核版本要和模块欲加载到的那个内核版本要一致。

4,模块中经常使用的命令:

insmod,lsmod,rmmod

5,系统调用:

int open(const char *pathname,int flags,mode_t mode);

flag表示文件打开标志,如:O_RDONLY

mode表示文件访问权限,如:S_IRUSR(用户可读)S_IRWXG(组可以读、写、执行)

6C库文件操作

7linux文件系统与设备驱动的关系:

应用程序和VFS之间的接口是系统调用,而VFS与磁盘文件系统以及普通设备之间的接口是file_operation结构体成员函数。

8,两个重要的函数:

1struct file结构体定义在/linux/include/linux/fs.h(Linux 2.6.11内核)中定义。文件结构体代表一个打开的文件,系统中每个打开的文件在内核空间都有一个关联的struct file。它由内核在打开文件时创建,并传递给在文件上进行操作的任何函数。在文件的所有实例都关闭后,内核释放这个数据结构。在内核创建和驱动源码中,struct file的指针通常被命名为filefilp

具体可参考:http://blog.chinaunix.net/space.php?uid=30226&do=blog&id=2441819

在驱动开发中,文件读/写模式mode、标志f_flags都是设备驱动关心的内容,而私有数据指针private_data在驱动中被广泛使用,大多被指向设备驱动自定义的用于描述设备的结构体。驱动程序中常用如下类似的代码来检测用户打开文件的读写方式:

  1. if (file->f_mode & FMODE_WRITE) //用户要求可写
  2. {
  3. }
  4. if (file->f_mode & FMODE_READ) //用户要求可读
  5. {
  6. }

下面的代码可用于判断以阻塞还是非阻塞方式打开设备文件:

  1. if (file->f_flags & O_NONBLOCK) //非阻塞
  2. pr_debug("open:non-blocking\n");
  3. else //阻塞
  4. pr_debug("open:blocking\n");

2struct inode结构体定义在linux/fs.h中,可参考:http://blog.chinaunix.net/space.php?uid=7699632&do=blog&id=2045707

9devfssysfsudev三者的关系:

1devfs

linux下有专门的文件系统用来对设备进行管理,devfssysfs就是其中两种。在2.4内核4一直使用的是devfsdevfs挂载于/dev目录下,提供了一种类似于文件的方法来管理位于/dev目录下的所有设备,我们知道/dev目录下的每一个文件都对应的是一个设备,至于当前该设备存在与否先且不论,而且这些特殊文件是位于根文件系统上的,在制作文件系统的时候我们就已经建立了这些设备文件,因此通过操作这些特殊文件,可以实现与内核进行交互。但是devfs文件系统有一些缺点,例如:不确定的设备映射,有时一个设备映射的设备文件可能不同,例如我的U盘可能对应sda有可能对应sdb;没有足够的主/次设备号,当设备过多的时候,显然这会成为一个问题;/dev目录下文件太多而且不能表示当前系统上的实际设备;命名不够灵活,不能任意指定等等。

2sysfs

正因为上述这些问题的存在,在linux2.6内核以后,引入了一个新的文件系统sysfs,它挂载于/sys目录下,跟devfs一样它也是一个虚拟文件系统,也是用来对系统的设备进行管理的,它把实际连接到系统上的设备和总线组织成一个分级的文件,用户空间的程序同样可以利用这些信息以实现和内核的交互,该文件系统是当前系统上实际设备树的一个直观反应,它是通过kobject子系统来建立这个信息的,当一个kobject被创建的时候,对应的文件和目录也就被创建了,位于/sys下的相关目录下,既然每个设备在sysfs中都有唯一对应的目录,那么也就可以被用户空间读写了。用户空间的工具udev就是利用了sysfs提供的信息来实现所有devfs的功能的,但不同的是udev运行在用户空间中,而devfs却运行在内核空间,而且udev不存在devfs那些先天的缺陷。

3udev

udev是一种工具,它能够根据系统中的硬件设备的状况动态更新设备文件,包括设备文件的创建,删除等。设备文件通常放在/dev目录下,使用udev,/dev下面只包含系统中真实存在的设备。它于硬件平台无关的,位于用户空间,需要内核sysfstmpfs的支持,sysfsudev提供设备入口和uevent通道,tmpfsudev设备文件提供存放空间。

参考:http://blog.csdn.net/aaronychen/article/details/2953345

10linux设备模型:

linux内核中,分别使用bus_type,device_driver,device来描述总线、驱动和设备,这3个结构体定义于include/linux/device.h头文件中。驱动和设备正是通过bus_type中的match()函数来配对的。

 

阅读(608) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~