日期:2014-05-16  浏览次数:20858 次

Linux驱动开发学习归纳-1

【驱动模块的组成】

1. 头文件:两个必须包含的

 #include<linux/module.h>

#include<linux/init.h>

2.模块加载函数(必须):module_init(xxxxxx);

3.模块卸载函数(必须):module_exit(xxxxxx);

4.模块许可声明(必须):MODULE_LICENSE("GPL");

5.模块参数(可选):module_param( var,  type, flag);、模块功能函数(可选)、其他。

【编译内核模块的条件】

1.使用正确版本的编译工具、模块工具等。

2.一份内核源码。

3.内核源码至少编译过一次。

【模块文件格式】

| ELF Header | .text | .data | 其他 | Section Table | .symtab | 其他 |

其中.symtab 表示符号表:一种映射函数到真实内存地址的数据结构。

【将模块加入内核】

内核源码的组合是通过目录结构实现的,每个目录下面都有两个文件Kconfig和Makefile。Kconfig描述了所属目录源文件相关的内核配置菜单。在执行内核配置make menuconfig命令时,从Kconfig中读出菜单,用户选择配置后保存到.config文件。在内核编译是,执行主目录下的Makefile时,调用这个.config文件,完成用户配置项的编译。

Kconfig文件的语法可查看内核Documentation/kbuild/kconfig-language.txt文件。

所以向Linux内核添加模块时,需要: 将驱动程序源文件放到Linux内核源码的相应目录中,在目录的Kconfig文件中添加对应的编译选择,在目录的Makefile中添加对应的编译语句。

此外可以动态加载卸载模块:insmod xxx.ko 、rmmod xxx.ko、modprobe。查看模块:lsmod、modinfo

【字符设备驱动】

1.主设备号和次设备号:dev_t类型表示设备号

typedef u_long dev_t;

2.分配设备号:

静态分配设备号:register_chrdev_region();

动态分配设备号:alloc_chrdev_region();

3.释放设备号:unregister_chrdev_region();

4.Linux中用cdev结构体描述字符设备:

struct cdev {
          struct kobject kobj;
          struct module *owner;
          const struct file_operations *ops;
          struct list_head list;
          dev_t dev;
          unsigned int count;
  };

struct list_head {
          struct list_head *next, *prev;
  };
内核使用inode结构体在内部表示文件,Linux中用inode结构体表示/dev/目录下的设备文件,每个字符设备在/dev/目录下都有一个设备文件,打开设备文件时,系统会产生一个inode结点,然后通过inode结点的i_cdev字段找到cdev字符结构体,通过cdev的ops指针,找到设备的操作函数。

723 struct inode {
724         struct hlist_node       i_hash;
725         struct list_head        i_list;         /* backing dev IO list */
726         struct list_head        i_sb_list;
727         struct list_head        i_dentry;
728         unsigned long           i_ino;
729         atomic_t                i_cou