Linux 第n次驱动入门(一) ---- helloWorld

Linux驱动 helloWorld


根据下面的helloWorld.c驱动来了解总结内核中的printk,__init,__exit

helloWorld.c


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

static char* name = "the man like wind ";
module_param(name, charp, S_IRUGO);

static int age = 18;
module_param(age, int, 0644);


static int __init helloWorld_init(void){
    int ret = 0;

    printk(KERN_INFO "------------------>see you again , world   :-)\n");
    printk(KERN_INFO "-  name :     %s\n",name);
    printk(KERN_INFO "-  age   :      %d\n",age);

    return ret;
}

static void __exit helloWorld_exit(void){
    printk(KERN_INFO"------------------>bye %s  , good world   :(\n",name);
}

int add_integer(int a,int b){
    return a+b;
}
EXPORT_SYMBOL(add_integer);

int sub_integer(int a,int b){
    return a-b;
}
EXPORT_SYMBOL(sub_integer);


module_init(helloWorld_init);
module_exit(helloWorld_exit);

MODULE_AUTHOR("Qian <XXXXXXXX@qq.com>");
MODULE_LICENSE("GPL v2");
MODULE_VERSION("V9.9");
MODULE_ALIAS("a simple helloWorld driver");

1.__exit 和 __init

__init,__initdata,__exit,__exitdata的定义全部在<Linux/init.h>,这些宏定义的作用就是告诉编译器把这些函数或者数据放在相应的selection中,其中__init修饰函数。__initdata修饰变量。
静态加载(直接编入内核)
__init函数在区段.initcall.init中还保存了一份函数指针,在初始化时内核会通过这些函数指针调用这些__init函数指针,并在整个初始化完成后,释放整个init区段,当模块直接编进内核时,在linux启动到最后可以看到类似下面的提示,静态加载时__exit将没有作用也不会编入内核,因为内置了就不能卸载
PHY: 0:01 - Link is Up - 100/Full
VFS: Mounted root (nfs filesystem) on device 0:14.
devtmpfs: mounted
Freeing init memory: 196K
INIT: version 2.86 booting
动态加载(insmod modprobe)
__init进行初始化工作,在模块装载之后,模块装载就会将初始化函数扔掉,这样可以将该函数占用的内存释放出来。__exit进行清理工作

2.printk打印函数

日志级别一共有8个级别,printk的日志级别定义如下(在include/Linux/kernel.h中):  
#define KERN_EMERG 0/*紧急事件消息,系统崩溃之前提示,表示系统不可用*/  
#define KERN_ALERT 1/*报告消息,表示必须立即采取措施*/  
#define KERN_CRIT 2/*临界条件,通常涉及严重的硬件或软件操作失败*/  
#define KERN_ERR 3/*错误条件,驱动程序常用KERN_ERR来报告硬件的错误*/ 
#define KERN_WARNING 4/*警告条件,对可能出现问题的情况进行警告*/  
#define KERN_NOTICE 5/*正常但又重要的条件,用于提醒*/  
#define KERN_INFO 6/*提示信息,如驱动程序启动时,打印硬件信息*/  
#define KERN_DEBUG 7/*调试级别的消息*/

查看修改打印级别

#查看Ubuntu打印级别
study@ubuntu:~$ cat /proc/sys/kernel/printk
4   4   1   7

#####################################################################
#打印出来4个数字的意义                                              
#控制台日志级别:优先级高于该值的消息将被打印至控制台             
#默认的消息日志级别:将用该优先级来打印没有优先级的消息
#最低的控制台日志级别:控制台日志级别可被设置的最小值(最高优先级)
#默认的控制台日志级别:控制台日志级别的缺省值
#####################################################################

#发现在Ubuntu下无法修改打印级别,本着好学的态度,在一块开发板上,这样当我们在驱动中为了调试,应该把打印级别调到最低就是7
~ # cat /proc/sys/kernel/printk
7       4       1       7
~ # echo 6 4 1 7 > /proc/sys/kernel/printk 
~ # cat /proc/sys/kernel/printk
6       4       1       7

3.几个驱动使用的命令

insmod  #加载驱动,会执行module_init()修饰的函数
rmmod   #卸载驱动,执行module_exit()修饰的函数
lsmod   #列出目前加载的驱动 等同于cat /proc/modules
tree /sys/module/  #insmod后会在/sys/moudle生成驱动名的一个目录
modprobe #在加载时会同时加载依赖的模块 依赖关系在/lib/modules/<kerel_version>/modules.dep,格式很简单,下面是copy过来的一个
    kernel/lib/cpu-notifier-error-inject.ko: kernel/lib/notifier-error-inject.ko
modinfo #查看模块信息

4驱动程序结构

  • 模块加载函数 ,insmod时会被内核执行,完成初始化工作
  • 模块卸载函数 ,rmmod时会被内核执行,完成清理工作
  • 模块许可声明 ,MODULE_LICENSE(“GPL v2”),不声明会在加载时提示污染内核
  • 模块参数(可选),外界可以传给驱动变量的一个数值
  • 导出符号(可选),可以导出一个函数给其他驱动使用
  • 作者别名等其他描述信息(可选) , 使用MODULE_xx()声明
4.1模块参数

在/sys/module/驱动名字/parameters所以该驱动导出模块参数的文件,可以cat查看参数值

#可以传入的参数类型有byte short ushort int uint long ulong charp boo等
static char* name = "the man like wind ";
module_param(name, charp, S_IRUGO);
static int age = 18;
module_param(age, int, 0644);
#这样在使用时可以insmod *.ko name="leo" age=23
#如果是静态加载进入内核可以在uboot的bootargs里设置“模块名.参数名=值”

4.2导出符号

使用下面宏导出符号到内核符号表中
EXPORT_SYMBOL()
EXPORT_SYMBOL_GPL()

#可以通过/proc/kallsyms查找导出符号相关信息
int add_integer(int a,int b){
    return a+b;
}
EXPORT_SYMBOL(add_integer);

int sub_integer(int a,int b){
    return a-b;
}
EXPORT_SYMBOL(sub_integer);
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值