在 Linux系统下,有用户空间与内核空间的区分。
应用程序运行在用户空间,而 Linux 驱动属于内核的一部分,因此驱动运行于内核空间。
应用程序需要打印信息到串口时,一般调用 printf()函数,但是,内核中需要打印信息时则会调用 printk()函数。
本文简单学习 printk()函数的使用。
在 Linux 内核中没有 printf 这个函数。printk 相当于 printf 的孪生兄妹,printf() 函数运行在用户态,printk()函数运行在内核态。在内核中想要向控制台输出或显示一些内容,必须使用 printk() 函数。不同之处在于,printk 可以根据日志级别对消息进行分类,一共有 8 个消息级别。
这 8 个消息级别定义在文件 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(KERN_EMERG "gsmi: Log Shutdown Reason\n");
如果使用 printk 的 时 候 不 显 式 的 设 置 消 息 级 别 , 那 么 printk 将 会 采 用 默 认 级 别
#define CONSOLE_LOGLEVEL_DEFAULT 7
例如,可以在 前面编写的字符驱动模块框架代码中,添加 printk()打印。chrdevbase.c 添加后如下:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
/*
* 驱动模块入口函数
*/
static int __init chrdevbase_init(void)
{
printk("chrdevbase_init()!\n\r");
return 0;
}
/*
* 驱动模块出口函数
*/
static void __exit chrdevbase_exit(void)
{
printk("chrdevbase_exit()!\r\n");
}
/*
* 驱动模块的入口与出口函数
*/
module_init(chrdevbase_init); /* 入口 */
module_exit(chrdevbase_exit); /* 出口 */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("LingXueWu");
首先,重新编译 工程,会生成 .ko文件。将 .ko 文件拷贝到 开发板根文件系统 /lib/modules/4.1.15目录下:
其次,开发板上电后,会进入开发板根文件系统,输入 "cd /lib/modules/4.1.15" 命令,进入 /lib/modules/4.1.15目录:
/ # cd lib/modules/4.1.15/
/lib/modules/4.1.15 # ls
chrdevbase.ko modules.alias modules.dep modules.symbols
最后,挂载驱动模块:
/lib/modules/4.1.15 # modprobe chrdevbase.ko
chrdevbase_init()!
/lib/modules/4.1.15 #
可以看出,当使用 modprobe 命令挂载驱动模块时,是调用了 chrdevbase_init()函数。
输入 "lsmod" 命令,查看驱动模块:
/lib/modules/4.1.15 # lsmod
Module Size Used by Tainted: G
chrdevbase 680 0
/lib/modules/4.1.15 #
卸载驱动模块:
/lib/modules/4.1.15 # rmmod chrdevbase.ko
chrdevbase_exit()!
/lib/modules/4.1.15 #
可以看出,当卸载驱动模块时,是运行了 chrdevbase_exit()函数。