linux驅動中串口打印調試函數彙總說明

    linux驅動中串口打印函數主要有3類,分別爲printk、pr_xxx、dev_xxx。下面分別介紹這三種。

1. printk

    printk和應用層下的printf的區別是在參數最前面多了一個宏,宏如下:

#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_DEBUG即可,提示信息使用KERN_INFO。如若不加宏,則使用默認的信息級別MESSAGE_LOGLEVEL_DEFAULT
    默認信息級別如下:
kernel/printk/printk.c中:

int console_printk[4] = {
	CONSOLE_LOGLEVEL_DEFAULT,	/* console_loglevel */
	MESSAGE_LOGLEVEL_DEFAULT,	/* default_message_loglevel */
	CONSOLE_LOGLEVEL_MIN,		/* minimum_console_loglevel */
	CONSOLE_LOGLEVEL_DEFAULT,	/* default_console_loglevel */
};

    如上數組中的宏定義在include/linux/printk.h

/* printk's without a loglevel use this 
#define MESSAGE_LOGLEVEL_DEFAULT CONFIG_MESSAGE_LOGLEVEL_DEFAULT

/* We show everything that is MORE important than this.. 
#define CONSOLE_LOGLEVEL_SILENT  0 /* Mum's the word */
#define CONSOLE_LOGLEVEL_MIN	 1 /* Minimum loglevel we let people use */
#define CONSOLE_LOGLEVEL_QUIET	 4 /* Shhh ..., when booted with "quiet" */
#define CONSOLE_LOGLEVEL_DEFAULT 7 /* anything MORE serious than KERN_DEBUG */
#define CONSOLE_LOGLEVEL_DEBUG	10 /* issue debug messages */
#define CONSOLE_LOGLEVEL_MOTORMOUTH 15	/* You can't shut this one up */

    當我們在控制檯中輸入如下命令cat /proc/sys/kernel/printk時,可以打印出數組console_printk的值,當然,也可以使用命令echo 1 4 1 7 > /proc/sys/kernel/printk來重寫數組的值。

2. pr_xxx

    在Linux中,爲方便書寫,使用pr_xxx宏對printk進行了封裝。同樣,在頭文件include/linux/printk.h中,有如下定義:

#define pr_emerg(fmt, ...) \
	printk(KERN_EMERG pr_fmt(fmt), ##__VA_ARGS__)
#define pr_alert(fmt, ...) \
	printk(KERN_ALERT pr_fmt(fmt), ##__VA_ARGS__)
#define pr_crit(fmt, ...) \
	printk(KERN_CRIT pr_fmt(fmt), ##__VA_ARGS__)
#define pr_err(fmt, ...) \
	printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__)
#define pr_warning(fmt, ...) \
	printk(KERN_WARNING pr_fmt(fmt), ##__VA_ARGS__)
#define pr_warn pr_warning
#define pr_notice(fmt, ...) \
	printk(KERN_NOTICE pr_fmt(fmt), ##__VA_ARGS__)
#define pr_info(fmt, ...) \
	printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
    
/* If you are writing a driver, please use dev_dbg instead */
#if defined(CONFIG_DYNAMIC_DEBUG)
/* dynamic_pr_debug() uses pr_fmt() internally so we don't need it here */
#define pr_debug(fmt, ...) \
	dynamic_pr_debug(fmt, ##__VA_ARGS__)
#elif defined(DEBUG)
#define pr_debug(fmt, ...) \
	printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
#else
#define pr_debug(fmt, ...) \
	no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
#endif

    使用pr_xxx打印可以省略KERN_DEBUG等宏,其書寫格式和應用層的printf一樣。調試信息打印使用pr_debug,提示信息打印使用pr_info

3. dev_xxx

    在linux驅動中,使用dev_xxx打印信息可以將當前的設備名稱一同打印處理,這樣在查看log的時候,便可以知道是哪一個驅動打印的信息,這是值得推薦的一種打印方法。主要有如下實現:

void dev_emerg(const struct device *dev, const char *fmt, ...);
void dev_crit(const struct device *dev, const char *fmt, ...);
void dev_alert(const struct device *dev, const char *fmt, ...);
void dev_err(const struct device *dev, const char *fmt, ...);
void dev_warn(const struct device *dev, const char *fmt, ...);
void dev_notice(const struct device *dev, const char *fmt, ...);
void dev_info(const struct device *dev, const char *fmt, ...);
void dev_dgb(const struct device *dev, const char *fmt, ...);

    再來看dev_dbg的實現。

#if defined(CONFIG_DYNAMIC_DEBUG)
#define dev_dbg(dev, format, ...)		     \
do {						     \
	dynamic_dev_dbg(dev, format, ##__VA_ARGS__); \
} while (0)
#elif defined(DEBUG)
#define dev_dbg(dev, format, arg...)		\
	dev_printk(KERN_DEBUG, dev, format, ##arg)
#else
#define dev_dbg(dev, format, arg...)				\
({								\
	if (0)							\
		dev_printk(KERN_DEBUG, dev, format, ##arg);	\
})
#endif

    可見,dev_dbg最後調用的是dev_printk函數。

4. 驅動添加調試信息打印方法

    可在文件起始位置添加如下信息:

#define USE_DEBUG
#undef UDEBUG            
#ifdef USE_DEBUG
#define UDEBUG(fmt,args...) printk(KERN_DEBUG "scull: " fmt, ## args)
#else
#define UDEBUG(fmt, args...) /* not debugging: nothing */
#endif 

    然後在驅動代碼中使用UDEBUG來打印調試信息便可,宏USE_DEBUG用來控制是否打開調試信息打印。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章