Linux下驱动开发(一)

Linux驱动开发hello

驱动模块的加载和卸载

Linux驱动有两种运行方式,第一种就是将驱动编译进Linux内核中,这样当Linux内核启动时就会自动运行驱动程序。第二种就是将驱动编译成模块(Linux下模块扩展名为.ko),在Linux内核启动以后使用”insmod”命令加载驱动模块。

在调试的时候一般编译成模块,这样不需要编译整个Linux代码。而且在调试的时候只需要加载或者卸载驱动模块即可,不需要重启整个系统。最大的好处就是方便。

模块加载和卸载注册函数如下

module_init(xxx_init);	//注册模块加载函数

module_exit(xxx_exit);	//注册模块卸载函数

module__init、module__exit这两个宏是定义在include/linux/init.h中:

static __init int hello _init(void) 宏就被展开为 static __section(.init.text) __cold notrace int hello_init(void)

static __exit int hello _init(void) 宏就被展开为 static __section(.exit.text) __exitused__cold notrace int hello_exit

这里的*__section*为gcc链接选项,他表示把该函数链接到Linux内核映像文件的相应段中,这样hello_init将会被链接进.init.text段中,而hello_exit将会被链接进.exit.text段中。被链接进这两段中的函数的代码在调试完之后,内核将会自动释放他们所占用的内存资源。因为这些函数只需要初始化或退出一次,所以hello_init()和hello_exit()函数做好在前面加上__init和__exit。

module_inti(hello_init)宏被展开为:

satic int (*initcall_t)(void) _initcall_hello_init6_used_attribute((section(“initcall”“6"”.init")))=hello_init

这段代码也就是定义了一个叫 __initcall_hello_init6的函数指针,他指向hello_init这个函数,gcc的链接选项__attribute__和__section__将该指针变量链接到linux内核映像的.initcall段中。linux系统在启动时,完成CPU和板级初始化之后,就会从该段中读入所有的模块初始化函数执行。每一个Linux内核模块都需要使用module_init()和module_exit()宏来修饰,这样系统启动时才能自动调用并初始化他们。

当使用”insmod”命令来加载驱动的时候,xxx_init函数就会被调用。

当使用”rmmod”命令卸载具体驱动的时候,xxx_exit函数就会被调用。

编写hello模块C文件

#include <linux/init.h>
#include <linux/module.h> 
#include <linux/kernel.h>

static __init int hello_init(void)
{
    printk(KERN_ALERT "hello world\n");
 
    return 0;
}
 
static __exit void hello_exit(void)
{
    printk(KERN_ALERT "Goodbye\n");
}
 
module_init(hello_init);
module_exit(hello_exit);
 
MODULE_LICENSE("xxx");
MODULE_AUTHOR("xxx")

定义了个名为 xxx_init 的驱动入口函数,并且使用了“__init”来修饰。

定义了个名为 xxx_exit 的驱动出口函数,并且使用了“__exit”来修饰。

调用函数 module_init 来声明 xxx_init 为驱动入口函数,当加载驱动的时候 xxx_init函数就会被调用。

调用函数module_exit来声明xxx_exit为驱动出口函数,当卸载驱动的时候xxx_exit函数就会被调用。

运行测试

如架构为x86系统编写Makefile如下:

KERNAL_DIR ?= /lib/modules/$(shell uname -r)/build
 PWD :=$(shell pwd)
 obj-m := kernel_hello.o
 
 modules:
     $(MAKE) -C $(KERNAL_DIR) M=$(PWD) modules
     @make clear
 clear:
     @rm -f *.o *.cmd *.mod *.mod.c
     @rm -rf *~ core .depend .tmp_versions Module.symvers modules.order -f
     @rm -f .*ko.cmd .*.o.cmd .*.o.d
     @rm -f *.unsigned
 
 clean:
     @rm -f *.ko
  

用dmesg查看Linux内核打印信息,dmesg -c将会清除之前Linux 内核的打印信息

安装Linux模块,并查看内核打印信息:

111@ubuntu:~/x86$ sudo insmod kernel_hello.ko

111@ubuntu:~/x86$ sudo rmmod kernel_hello 

111@ubuntu:~/x86$ sudo insmod kernel_hello.ko

111@ubuntu:~/x86$ dmesg | tail -3

[1120961.091209] hello world
[1121083.590510] Goodbye
[1121093.936166] hello world

用lsmod命令查看当前linux内核安装了的内核模块

关于Makefile文件的说明

KERNAL_DIR是指定开发板所运行的源码路径,并且这个linux内核源码必须make menuconfig并且make过的,因为Linux内核的一个模块可能依赖于另一个模块,如果另一个没有编译则出问题。所以Linux内核必须编译过,这样才能确认这种依赖关系;

obj-m +:= kernel_hello.o 该行告诉Makefile要将kernel_hello.c源码编译生成内核模块kernel_hello.ko;

$(MAKE) -C ( K E R N A L D I R ) M = (KERNAL_DIR) M= (KERNALDIR)M=(PWD) modules ,-C:把工作目录切换到-C后面指定的参数目录,M是Makefile里面的一个变量,作用是回到当前目录继续读取Makefile。当前使用make命令编译内核驱动模块时,将会进入到KERNAL_DIR指定的linux内核源码中去编译,并在当前目录下生成很多临时文件以及驱动模块文件kernel_hello.ko;

clear目标将编译linux内核过程生成的一些临时文件全部删掉;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值