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用来控制是否打开调试信息打印。

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