Linux第一个驱动:Hello World

进入Linux底层驱动最重要的一个阶段:Linux驱动程序设计
知识结构:
1.驱动程序设计模型40%
2.内核相关知识30%
3.硬件相关知识30% 逐渐淡化

学习方法:

理论-->实验-->疑问-->理论-->实验-->.........


驱动程序的安装方法
(1)编译进内核:编译进内核的镜像文件
修改drivers/char/下的两个文件:
kconfig和Makefile
(2)编译成模块,然后以模块的方式安装
要的时候:   insmod xxx.ko
不要的时候: rmmod xxx.ko
区别:编译进内核的模块就会在内核启动时进行加载,编译成模块就是需要用到模块时通过命令进行加载


驱动函数的组成
(1)头文件【必须】
(2)模块参数【可选】
就是驱动模块加载时,需要传递给驱动模块的参数。最常见的就是,一个驱动模块需要完成多种功能,通过模块参数选择使用哪一种功能。
(3)模块功能函数【可选】
Linux内核源码里面模块功能函数对应的就是file_operations结构体成员所对应的函数指针
(4)模块加载函数(模块初始化函数)【必须】
也叫模块入口函数,该函数主要完成将该驱动的模块功能函数注册到内核数组chardev[]中,即把一项file_operations结构体告诉内核
通常函数叫static int __init xxx_init()
(5)模块释放函数【必须】
你的驱动模块完成了他的功能,不需要用到了,那么就需要把他从内核数组chardev[]里面拖出来释放掉
(6)对模块加载函数和释放函数的修饰【必须】
在linux2.6.30.4/include/linux/init.h文件中定义两个宏module_init和module_exit,使用:
module_init(xxx_init)
module_exit(xxx_exit)
作用:将模块加载函数和释放函数添加到对应的module_init函数列表和module_exit函数列表
(7)模块许可声明【必须】
MODULE_LICENSE("GPL");一般都是要写的,告诉内核该程序使用的许可证,不然在加载时它会提示该模块污染内核
“GNL”:General Public License通用公共许可证
当一个模块函数要对内核其他部分可见,则必须被显式导出。如:EXPORT_SYMBOL(name)或者EXPORT_SYMBOL_GPL(name),这二个宏均用于符号导出到模块外部。后者表示导出的模块只能被GPL许可证下的模块方可使用。

进入今天的主题:Hello World驱动程序的编写!

方法一、将Hello World驱动编译进内核:
实现要求:内核启动时加载该模块,用“Hello World!”表明该模块已实现加载。
实验操作:
(1)新建hello.c文件:将其放到内核的drivers目录的某一个位置,由于hello world驱动是字符设备驱动,所以这里把他放到linux/drivers/char目录下面
代码:

#include  //包含了很多装载模块需要的符号和函数的定义
#include    //用于包含了模块加载函数和模块释放函数的宏定义

static int __init hello_init(void)
{
	/* 执行insmod hello.ko时就会打印hello,world */
	printk(KERN_ERR "Hello World!\n");
	return 0;
}

static void __exit hello_exit(void)
{
	/*执行rmmod hello 时就会打印goodbye world*/
	printk(KERN_EMERG "Hello exit!\n");
}

module_init(hello_init); //修饰加载函数hello_init(),
module_exit(hello_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("CLBIAO");
MODULE_DESCRIPTION("Hello world module");

代码分析:
模块初始化函数应该被声明为static,因为这种函数除了在本文件内有意义,其他文件是没有意义的。
__init :双下划线__init的意思是,该函数仅仅在初始化期间内有效,在模块被装载之后,即insmod之后,模块装器就会将初始化函数丢弃,之后任何函数也没有办法调用初始化函数,因为该函数已经从内存中释放出来。
__exit :双下划线__exit表示该函数仅仅用于模块被卸载的时候或者系统关闭时被调用
KERN_EMERG:内核日志等级,相关内容下一篇博文讲述。

(2)修改Kconfig文件和Makefile
打开配置文件vim drivers/char/Kconfig,
在menu "Character Drivers"后面添加:
config HELLO_WORLD
bool "hello_world"
保存,退出,make menuconfig后配置编译到内核即可
配置结果查看内核源码顶层目录“.config”文件,里面多出了一项“CONFIG_HELLO_WORLD = y”,即编译进内核,若“=m”就是编译进模块
 
打开make文件vim drivers/char/Makefile
添加其中一项:
obj-$(CONFIG_HELLO_WORLD)      += hello.o
保存,退出,make zImage生成内核镜像,下载进开发板测试
 
方法二、将Hello World编译成独立模块
在drivers目录下(当然可以在任何的位置)新建一个hello文件夹,在里面单独编写一个万能Makefile,并将hello.c文件拷贝到这里
Makefile内容:

ifneq ($(KERNELRELEASE),)

obj-m :=hello.o
	
else
	
KDIR:= /opt/EmbedSky/linux-2.6.30.4
	
all:
	make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-
	
clean:
	rm -f *.ko *.o *.mod.o *.mod.c .symvers
	
endif

make之后将hello.ko文件拷贝到nfs文件系统目录下面,开发板串口终端输入命令:
insmod hello.ko
打印:Hello World!
lsmod
打印:hello 1376 0 - Live 0xbf012000
rmmod hello
打印:Hello exit!


你可能感兴趣的:(Linux,驱动开发)