原创作品,转载时请务必以超链接形式标明文章原始出处:http://blog.youkuaiyun.com/gqb666/article/details/8789807,作者:gqb666
1、最近在写I2C下EEPROM的驱动程序,但发现使用i2c_new_probed_device函数无法枚举到设备,于是想调试该函数(位于driver/i2c/i2c-core.c内),看到其中有些调试信息如下:
- i2c_new_probed_device(...)
- {
- ...
- if (addr_list[i] == I2C_CLIENT_END) {
- dev_dbg(&adap->dev, "Probing failed, no device found\n");
- return NULL;
- }
- ...
- }
2、列出dev_dbg源码实现:(include/linux/device.h中)
- #if defined(DEBUG)
- #define dev_dbg(dev, format, arg...) \
- dev_printk(KERN_DEBUG , dev , format , ## arg)
问题找出,只需在引用头文件#include/linux/device.h前定义DEBUG宏即可。
在include/linux/i2c.h中修改代码如下:
- #define DEBUG /* add for debug eeprom */
- #include <linux/device.h> /* for struct device */
- #undef DEBUG /* add for debug eeprom */
加载驱动驱动模块后,并没有调试信息打印出。如下图:
但执行dmesg命令后Probing failed, no device found已经能够打印出来,如下图:

这是为什么呢?
3、注意dev_printk的打印级别:
- dev_printk(KERN_DEBUG , dev , format , ## arg)
#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 */
可以看到KERN_DEBUG级别最低为7。
再看/include/linux/printk.h下的一个宏:
- #define CONSOLE_LOGLEVEL_DEFAULT 7 /* anything MORE serious than KERN_DEBUG */
将该行修改为:
- #define CONSOLE_LOGLEVEL_DEFAULT 8 /* anything MORE serious than KERN_DEBUG */
在内核中经常见到一些调试打印信息。pr_debug,pr_err等。以前的理解是以为只有出错才会将pr_err中的内容打印出来,现在看来是错的。pr_err并不等同与perror。
关于pr_err,pr_debug的定义有两种:
第一种
(tools\perf\util\debug.h)
int eprintf(int level,
const char *fmt, ...) __attribute__((format(printf, 2, 3)));
#define pr_err(fmt, ...) \
eprintf(0, pr_fmt(fmt), ##__VA_ARGS__)
#define pr_warning(fmt, ...) \
eprintf(0, pr_fmt(fmt), ##__VA_ARGS__)
#define pr_info(fmt, ...) \
eprintf(0, pr_fmt(fmt), ##__VA_ARGS__)
#define pr_debug(fmt, ...) \
eprintf(1, pr_fmt(fmt), ##__VA_ARGS__)
#define pr_debugN(n, fmt, ...) \
eprintf(n, pr_fmt(fmt), ##__VA_ARGS__)
#define pr_debug2(fmt, ...) pr_debugN(2, pr_fmt(fmt), ##__VA_ARGS__)
#define pr_debug3(fmt, ...) pr_debugN(3, pr_fmt(fmt), ##__VA_ARGS__)
#define pr_debug4(fmt, ...) pr_debugN(4, pr_fmt(fmt), ##__VA_ARGS__)
第二种
(tools\virtio\linux\kernel.h)
#define pr_err(format, ...) fprintf (stderr, format, ## __VA_ARGS__)
#ifdef DEBUG
#define pr_debug(format, ...) fprintf (stderr, format, ## __VA_ARGS__)
#else
#define pr_debug(format, ...) do {} while (0)
#endif
#define dev_err(dev, format, ...) fprintf (stderr, format, ## __VA_ARGS__)
#define dev_warn(dev, format, ...) fprintf (stderr, format, ## __VA_ARGS__)
第一种定义,可以看出pr_err,pr_debug,pr_warning,pr_info实质上都是一样的,eprintf就是printf函数。__attribute__((format(printf, 2, 3)));表示printf格式化字符串从printf的第2个参数开始,可变参数从printf的第3个参数开始。关于attribute的介绍可以参加这里
所以,对于内核代码中出现pr_err,pr_debug,pr_warning,pr_info都是打印信息到终端。
第二种定义,关键是对fprintf的理解了。
<span style="font-size:18px;">fprintf(stderr, "Can't open it!\n"); fprintf(stdout, "Can't open it!\n");</span>
<span style="font-size:18px;">stdout -- 标准输出设备 (printf("..")) 同 stdout。 stderr -- 标准错误输出设备 两者默认向屏幕输出。 但如果用转向标准输出到磁盘文件,则可看出两者区别。stdout输出到磁盘文件,stderr在屏幕。</span>也就是说两者都是要向终端屏幕打印信息的。
【总结】:pr_err pr_debug等调用时,都会打印到终端屏幕的,不管之前的语句是否发生错误。之所以有几种定义,是为了代码清晰。