linux驱动开发时, 因为代码处于linux内核环境, 所以调试打印信息和应用层有所区别。
开始学习linux驱动一定要明白打印日志信息, 这是后期调试过程中恐怕是唯一的锁定错误的方式。
因为在内核层没有标准库函数, 应用层的函数是不可以调用的。
linux驱动可以采用内部编译和外部编译两种方式。内部编译
是指直接将驱动程序编译到内核中, 然后调试内核。 这种方式耗时费力。外部编译
是指将驱动编译为一个模块,可以手动地装载与卸载。这是最省时省力的方法。
入口函数与出口函数
#include <linux/init.h>
#include <linux/module.h>
// 自定义入口函数
static int __init demo_init(void)
{
printk("hello my driver.\n");
return 0;
}
// 自定义出口函数
static void __exit demo_exit(void)
{
printk("bye my driver.\n");
}
// 将自定义的入口函数和出口函数注册到内核中
module_init(demo_init);
module_exit(demo_exit);
MODULE_LICENSE("GPL");
需要注意的问题
- 驱动程序中要引入的头文件根据所使用的C语言没有的关键词及函数来确定
例如:__init
是一个宏, 在内核源码中建立ctags
之后,vim -t
得到__init
出现的文件列表,其中linux/init.h
就是包含__init
的头文件 printk
输出时, 要注意加\n
来刷新缓冲区, 否则会出现printk
输出顺序错乱的问题- 驱动程序三要素
入口
,出口
,许可证
- 指定错入口出口函数会导致驱动无法卸载
- 如果是内部编译的方式, 入口函数在内核启动时调用,出口函数在内核停止时调用。
- 如果是外部编译的方式, 入口函数在模块装载时调用, 出口函数在模块卸载时调用。
模块装载与卸载的相关指令
# 装载模块
insmod mod_hello.ko
# 卸载模块, 注意卸载模块时没有.ko后缀
rmmod mod_hello
# 列出所有装载的模块
lsmod
# 查看模块信息
modinfo mod_hello.ko
打印信息方式: printk
printk有两种使用方式, 一种指定打印级别后打印, 一种使用默认打印级别打印
// 指定打印别打印
printk(KERN_ERR "error message");
// 使用默认打印级别打印
printk("error message");
调试驱动方式:
- 编写应用层程序调用驱动接口函数
- 装载驱动模块调试入口函数, 卸载驱动模块调试出口函数
printk
日志输出权限问题
内核的日志输出有一个优先级规则如下, 输出级别越高, 数值越小
include/linux/kern_levels.h
#define KERN_EMERG KERN_SOH "0" /* system is unusable */
#define KERN_ALERT KERN_SOH "1" /* action must be taken immediately */
#define KERN_CRIT KERN_SOH "2" /* critical conditions */
#define KERN_ERR KERN_SOH "3" /* error conditions */
#define KERN_WARNING KERN_SOH "4" /* warning conditions */
#define KERN_NOTICE KERN_SOH "5" /* normal but significant condition */
#define KERN_INFO KERN_SOH "6" /* informational */
#define KERN_DEBUG KERN_SOH "7" /* debug-level messages */
关于printk
的输出优先级, 采用如下方式查看和及修改
# 查看printk的优先级
cat /proc/sys/kernel/printk
#得到如下结果
4 4 1 7
# 通过man 2 syslog 可知, 这4个值依次对应如下4个等级的设置值
# 4 > console_loglevel
# 4 > default_message_loglevel 主要表示printk使用的优先级
# 1 > minimum_console_loglevel
# 7 > default_console_loglevel
# 让printk的优先级大于console_loglevel即可输出
# 所以执行如下操作(必须切换为root用户, 否则权限不够)
su root
echo 4 3 1 7 > /proc/sys/kernel/printk
在开发板系统的第一个启动脚本中添加如下信息, 每次启动开发板自动设置打印级别
文件位置: /etc/init.d/rcS
echo 4 3 1 7 > /proc/sys/kernel/printk