作者:彭東林
郵箱: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確實比較方便。
完。