GNU/Linux内核驱动编程学习之路
摘要:因为本科毕业设计跟Linux环境下驱动程序开发有关,一开始什么也没接触,没有过这方面的开发经验。应该是从零开始,借阅了很多大咖的书籍,参考了很多大牛博主的博文,现在把自己的一些理解和一些实验写下来,供大家一起讨论,欢迎大家一起交流。
1_GNU/Linux的朴素认识与入门驱动程序
Linux操作系统是UNIX操作系统的一种克隆系统,是一种类UNIX系操作系统,诞生于1991年10月5日,起初的作者是Linus Torvalds。
发展和成长主要依赖的五个支柱:UNIX操作系统、Minix操作系统、GNU计划、POSIX标准和Internet。
GNU/Linux的朴素认识
从严格意义上说,可将操作系统定义为一种软件,它控制计算机的硬件资源,提供程序运行环境。我们通常称这种软件为内核,因为它相对较小,而且位于环境的核心。
下面是UNIX系统的体系结构:
内核的接口被称为系统调用。公用函数库构建在系统调用的接口之上,应用函数既可使用公用函数库,也可使用系统调用。shell是一个特殊的应用程序,为运行其他应用程序提供了一个接口。
Linux内核组成
https://www.kernel.org/可以下载Linux内核源码
- Linux内核源代码的目录结构
arch:包含和硬件体系相关的代码,每种平台占一个相应的目录,如i386、arm、arm64、powerpc、mips等。
block:块设备驱动程序I/O调度。
crypto:常用的加密和散列算法(如AES、SHA等),还有一些压缩和CRC校验算法。
documentation:内核各部分的通用解释和注释。
drivers:设备驱动程序,每个不同的驱动占用一个子目录,如char,block,net,mtd,i2c等。
fs:所支持的各种文件系统,如EXT、FAT、NTFS、JJFFS2等。
include:头文件,与系统相关的头文件放置在include/linux子目录下。
init:内核初始化代码。著名的start_kernel()就位于init/main.c文件中。
ipc:进程间通信的代码。
kernel:内核最核心的部分,包括进程调度、定时器等,而和平台相关的一部分代码放在arch/***/kernel目录下。
lib:库文件代码。
mm:内存管理代码,和平台相关的一部分代码放在arch/***/mm下。
net:网络相关代码,实现各种各样的网络协议。
scripts:用于配置内核的脚本协议。
security:主要是一个SELinux的模块。
sound:ALSA、OSS音频设备的驱动核心代码和常用设备驱动。
usr:实现用于打包和压缩的cpio等。 - Linux内核的组成部分
进程调度 内存管理 虚拟文件系统 网络接口 进程间通信 - Linux内核的内核空间和用户空间
现代CPU内部往往实现了不同的操作模式(级别),不同模式下有不同功能,高层程序不能访问低级功能,而必须以某种形式切换到低级模式。
Linux内核驱动编程
Linux设备驱动会以内核模块的形式出现,设备驱动也是在内核状态下运行。
首先我们需要知道应用程序、库、内核、驱动程序之间的关系。如下图:
-
应用程序调用函数库,通过对文件的操作完成一系列功能;
函数库:部分函数无需内核的支持,由库函数内部通过代码实现,直接完成功能;部分函数涉及到硬件操作或内核的支持,由内核完成对应功能,我们称其为系统调用。
应用程序:以文件形式访问各种硬件设备(linux特有的抽象方式,把所有的硬件访问抽象为对文件的读写、设置)。 -
内核处理系统调用
根据设备文件类型、主设备号、从设备号(后面会讲解),调用设备驱动程序; -
设备驱动直接与硬件通信
设备类型
所有的硬件设备大致分为三类:字符设备、块设备、网络设备。
字符设备:字符(char)设备是个能够像字节流(类似文件)一样被访问的设备。
块设备:一个块设备驱动程序主要通过传输固定大小的数据(一般为512或1K)来访问设备。
网络设备:通过访问网络接口的方法。
驱动程序和应用程序的区别
应用程序从main函数开始,驱动程序从模块初始化函数module_init()函数作为入口。
第一个驱动程序编程
首先直接贴代码
1.驱动文件hello.c
//头文件,在linux内核源码include/linux目录下都可以查询到
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
//主设备号 宏定义
#define HELLO_MAJOR 231
//设备名 宏定义
#define DEVICE_NAME "HelloModule"
//打开操作
static int hello_open(struct inode *inode, struct file *file){
printk(KERN_EMERG "hello open.\n");
return 0;
}
//写操作
static ssize_t hello_write(struct file *file, const char __user * buf, size_t count, loff_t *ppos){
printk(KERN_EMERG "hello write.\n");
return 0;
}
//file_operations结构体中的成员函数与内核虚拟文件系统的接口。
static struct file_operations hello_flops = {
.owner = THIS_MODULE,
.open = hello_open,
.write = hello_write,
};
//模块加载函数 __init声明
static int __init hello_init(void){
int ret;
//申请设备号
ret = register_chrdev(HELLO_MAJOR,DEVICE_NAME, &hello_flops);
if (ret < 0) {
printk(KERN_EMERG DEVICE_NAME " can't register major number.\n");
return ret;
}
printk(KERN_EMERG DEVICE_NAME " initialized.\n");
return 0;
}
//模块卸载函数 __exit声明
static void __exit hello_exit(void){
unregister_chrdev(HELLO_MAJOR, DEVICE_NAME);
printk(KERN_EMERG DEVICE_NAME " removed.\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
补充一下设备驱动与文件系统的关系:
2.Makefile:用来编译驱动文件hello.c
ifneq ($(KERNELRELEASE),)
MODULE_NAME = hellomodule
$(MODULE_NAME)-objs := hello.o
obj-m := $(MODULE_NAME).o
else
KERNEL_DIR = /lib/modules/$(shell uname -r)/build
MODULEDIR := $(shell pwd)
.PHONY: modules
default: modules
modules:
make -C $(KERNEL_DIR) M=$(MODULEDIR) modules
clean distclean:
rm -f *.o *.mod.c .*.*.cmd *.ko
rm -rf .tmp_versions
endif
3.测试程序hellotest.c
#include <fcntl.h>
#include <stdio.h>
int main(void)
{
int fd;
int val = 1;
fd = open("/dev/hellodev", O_RDWR);
if(fd < 0){
printf("can't open!\n");
}
write(fd, &val, 4);
return 0;
}
测试:
将这三分代码放置在一个目录下:
make
生成驱动模块 hello.ko
sudo insmod hellomodule.ko
加载驱动
使用dmesg命令查看:
dmesg | tail
sudo mknod /dev/hellodev c 231 0
sudo chmod 777 /dev/hellodev
创建设备节点文件并赋予权限:
gcc hellotest.c -o hellotest
编译测试程序
运行测试程序
./hellohost
sudo rmmod hellomodule
dmesg | tail
卸载驱动并查看信息
这是一个简单的demo,对于整个驱动开发流程有了一定的了解。麻雀虽小,五脏俱全。缺少的可能是对硬件的操作,还有中断,DMA等各种其他操作。参考了很多了大神大牛的博文,附上参考链接:
http://www.cnblogs.com/amanlikethis/p/4914510.html
https://www.cnblogs.com/mrzhangxinjie/p/7170736.html
参考书籍:
Linux设备驱动开发详解基于最新的Linux 4.0内核 宋宝华编著 机械工业出版社
欢迎大家指正错误,一起交流,为技术信仰而交流。谢谢!!!
之后我会继续编写驱动编写的文章,大家一起加油。