Linux驅動開發——pr_fmt的用法


作者:彭東林

郵箱:pengdonglin137@163.com

 

在閱讀kernel代碼的時候,總是看到有很多驅動都在第一行定義pr_fmt,閑來沒事,分析了一下, 發現,確實挺方便的。下面記錄分享一下。

我們知道,在驅動中可以使用dev_dbg來輸出log,在輸出的log中會有一些額外的信息,如所屬的device的name。

而pr_fmt就可以實現這個目的,先看一個用法(drivers/i2c/i2c-core.c):

#define pr_fmt(fmt) "i2c-core: " fmt

#include <dt-bindings/i2c/i2c.h>
#include <asm/uaccess.h>
#include <linux/acpi.h>
... ...

但是在這個文件中並沒有看到pr_fmt被使用。然后,猜測應該是被哪個宏使用了,所以我在include下搜索pr_fmt發現:

include/linux/printk.h:271:    printk(KERN_EMERG pr_fmt(fmt), ##__VA_ARGS__)
include/linux/printk.h:273:    printk(KERN_ALERT pr_fmt(fmt), ##__VA_ARGS__)
include/linux/printk.h:275:    printk(KERN_CRIT pr_fmt(fmt), ##__VA_ARGS__)
include/linux/printk.h:277:    printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__)
include/linux/printk.h:279:    printk(KERN_WARNING pr_fmt(fmt), ##__VA_ARGS__)
include/linux/printk.h:282:    printk(KERN_NOTICE pr_fmt(fmt), ##__VA_ARGS__)
include/linux/printk.h:284:    printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
include/linux/printk.h:296:    printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)

然后看一下printk.h:

 1 ... ...
 2 #ifndef pr_fmt
 3 #define pr_fmt(fmt) fmt
 4 #endif
 5 
 6 /*
 7  * These can be used to print at the various log levels.
 8  * All of these will print unconditionally, although note that pr_debug()
 9  * and other debug macros are compiled out unless either DEBUG is defined
10  * or CONFIG_DYNAMIC_DEBUG is set.
11  */
12 #define pr_emerg(fmt, ...) \
13     printk(KERN_EMERG pr_fmt(fmt), ##__VA_ARGS__)
14 #define pr_alert(fmt, ...) \
15     printk(KERN_ALERT pr_fmt(fmt), ##__VA_ARGS__)
16 #define pr_crit(fmt, ...) \
17     printk(KERN_CRIT pr_fmt(fmt), ##__VA_ARGS__)
18 #define pr_err(fmt, ...) \
19     printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__)
20 #define pr_warning(fmt, ...) \
21     printk(KERN_WARNING pr_fmt(fmt), ##__VA_ARGS__)
22 #define pr_warn pr_warning
23 #define pr_notice(fmt, ...) \
24     printk(KERN_NOTICE pr_fmt(fmt), ##__VA_ARGS__)
25 #define pr_info(fmt, ...) \
26     printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
27 
28 #if defined(CONFIG_DYNAMIC_DEBUG)
29 #include <linux/dynamic_debug.h>
30 
31 /* dynamic_pr_debug() uses pr_fmt() internally so we don't need it here */
32 #define pr_debug(fmt, ...) \
33     dynamic_pr_debug(fmt, ##__VA_ARGS__)
34 #elif defined(DEBUG)
35 #define pr_debug(fmt, ...) \
36     printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
37 #else
38 #define pr_debug(fmt, ...) \
39     no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
40 #endif
41 ... ...

可以看到,如果驅動中沒有定義pr_fmt(fmt),那么,pr_fmt(fmt)就是fmt。

使用pr_fmt的還不少, 這里有幾個比較常用的函數: pr_err, pr_info,  如果沒有定義CONFIG_DYNAMIC_DEBUG, 那么pr_debug也會使用pr_fmt。

從上面的代碼已經看到pr_fmt的作用了吧,就是在用戶要輸出的log前面添加額外的固定的信息。下面結合gpio_demo.c驅動看一下pr_fmt的幾種用法:

1 #define pr_fmt(fmt) "gpio_demo: " fmt
2 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
3 #define pr_fmt(fmt) KBUILD_MODNAME ":%s:%d: " fmt, __func__, __LINE__

 在gpio_demo.c的第一行定義上面的一種, 然后, 在驅動中調用pr_info, 如:

 1 static int gpio_demo_probe(struct platform_device *pdev) {
 2     struct device *dev = &pdev->dev;
 3     int ret = 0;
 4     int i = 0;
 5     int gpio = -1;
 6     gpio_demo_data_t *data = NULL;
 7     struct resource *res = NULL;
 8     u32 config, pud, drv;
 9 
10     pr_info("%s enter.\n", __func__);
11 ... ...

下面是 #define pr_fmt(fmt) "gpio_demo: " fmt 的輸出:

[ 1022.623230] gpio_demo: gpio_demo_probe enter.

下面是 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 的輸出(KBUILD_MODNAME是模塊的名字,可以閱讀這個驅動文件的Makefile文件獲得):

[ 1088.639631] gpio_demo: gpio_demo_probe enter.

下面是 #define pr_fmt(fmt) KBUILD_MODNAME ":%s:%d: " fmt, __func__, __LINE__ 的輸出:

[ 1135.108534] gpio_demo:gpio_demo_probe:87: gpio_demo_probe enter.

這對輸出log確實比較方便。

完。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM