作者:彭东林

邮箱:pengdonglin137@163.com

在阅读kernel代码的时候,总是看到有很多驱动都在第一行定义pr_fmt,闲来没事,分析了一下, 发现,确实挺方便的。下面记录分享一下。

我们知道,在驱动中可以使用dev_dbg来输出log,在输出的log中会有一些额外的信息,如所属的device的name。

而pr_fmt就可以实现这个目的,先看一个用法(drivers/i2c/i2c-core.c):

  1. #define pr_fmt(fmt) "i2c-core: " fmt
  2.  
  3. #include <dt-bindings/i2c/i2c.h>
  4. #include <asm/uaccess.h>
  5. #include <linux/acpi.h>
  6. ... ...

但是在这个文件中并没有看到pr_fmt被使用。然后,猜测应该是被哪个宏使用了,所以我在include下搜索pr_fmt发现:

  1. include/linux/printk.h:: printk(KERN_EMERG pr_fmt(fmt), ##__VA_ARGS__)
  2. include/linux/printk.h:: printk(KERN_ALERT pr_fmt(fmt), ##__VA_ARGS__)
  3. include/linux/printk.h:: printk(KERN_CRIT pr_fmt(fmt), ##__VA_ARGS__)
  4. include/linux/printk.h:: printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__)
  5. include/linux/printk.h:: printk(KERN_WARNING pr_fmt(fmt), ##__VA_ARGS__)
  6. include/linux/printk.h:: printk(KERN_NOTICE pr_fmt(fmt), ##__VA_ARGS__)
  7. include/linux/printk.h:: printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
  8. include/linux/printk.h:: 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 = ;
  4. int i = ;
  5. int gpio = -;
  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确实比较方便。

完。

Linux驱动开发——pr_fmt的用法的更多相关文章

  1. 嵌入式Linux驱动开发日记

    嵌入式Linux驱动开发日记 主机硬件环境 开发机:虚拟机Ubuntu12.04 内存: 1G 硬盘:80GB 目标板硬件环境 CPU: SP5V210 (开发板:QT210) SDRAM: 512M ...

  2. Linux 驱动开发

    linux驱动开发总结(一) 基础性总结 1, linux驱动一般分为3大类: * 字符设备 * 块设备 * 网络设备 2, 开发环境构建: * 交叉工具链构建 * NFS和tftp服务器安装 3, ...

  3. Linux驱动开发必看详解神秘内核(完全转载)

    Linux驱动开发必看详解神秘内核 完全转载-链接:http://blog.chinaunix.net/uid-21356596-id-1827434.html   IT168 技术文档]在开始步入L ...

  4. linux驱动开发流程

    嵌入式linux驱动开发流程嵌入式系统中,操作系统是通过各种驱动程序来驾驭硬件设备的.设备驱动程序是操作系统内核和硬件设备之间的接口,它为应用程序屏蔽了硬件的细节,这样在应用程序看来,硬件设备只是一个 ...

  5. 嵌入式linux驱动开发之点亮led(驱动编程思想之初体验)

    这节我们就开始开始进行实战啦!这里顺便说一下啊,出来做开发的基础很重要啊,基础不好,迟早是要恶补的.个人深刻觉得像这种嵌入式的开发对C语言和微机接口与原理是非常依赖的,必须要有深厚的基础才能hold的 ...

  6. 【转】linux驱动开发的经典书籍

    原文网址:http://www.cnblogs.com/xmphoenix/archive/2012/03/27/2420044.html Linux驱动学习的最大困惑在于书籍的缺乏,市面上最常见的书 ...

  7. Linux驱动开发 -- 打开dev_dbg()

    Linux驱动开发 -- 打开dev_dbg() -- :: 分类: LINUX linux设备驱动调试,我们在内核中看到内核使用dev_dbg来控制输出信息,这个函数的实质是调用printk(KER ...

  8. Linux驱动开发学习的一些必要步骤

      1. 学会写简单的makefile 2. 编一应用程序,可以用makefile跑起来 3. 学会写驱动的makefile 4. 写一简单char驱动,makefile编译通过,可以insmod, ...

  9. 驱动编程思想之初体验 --------------- 嵌入式linux驱动开发之点亮LED

    这节我们就开始开始进行实战啦!这里顺便说一下啊,出来做开发的基础很重要啊,基础不好,迟早是要恶补的.个人深刻觉得像这种嵌入式的开发对C语言和微机接口与原理是非常依赖的,必须要有深厚的基础才能hold的 ...

随机推荐

  1. 【探索】机器指令翻译成 JavaScript

    前言 前些时候研究脚本混淆时,打算先学一些「程序流程」相关的概念.为了不因太枯燥而放弃,决定想一个有趣的案例,可以边探索边学. 于是想了一个话题:尝试将机器指令 1:1 翻译 成 JavaScript ...

  2. C#基础篇 - 正则表达式入门

    1.基本概念 正则表达式(Regular Expression)就是用事先定义好的一些特定字符(元字符)或普通字符.及这些字符的组合,组成一个“规则字符串”,这个“规则字符串”用来判断我们给定的字符串 ...

  3. Android和JavaScript相互调用的方法

    转载地址:http://www.jb51.net/article/77206.htm 这篇文章主要介绍了Android和JavaScript相互调用的方法,实例分析了Android的WebView执行 ...

  4. 46张PPT讲述JVM体系结构、GC算法和调优

    本PPT从JVM体系结构概述.GC算法.Hotspot内存管理.Hotspot垃圾回收器.调优和监控工具六大方面进行讲述.(内嵌iframe,建议使用电脑浏览) 好东西当然要分享,PPT已上传可供下载 ...

  5. Angular企业级开发(4)-ngResource和REST介绍

    一.RESTful介绍 RESTful维基百科 REST(表征性状态传输,Representational State Transfer)是Roy Fielding博士在2000年他的博士论文中提出来 ...

  6. 玩转spring boot——AOP与表单验证

    AOP在大多数的情况下的应用场景是:日志和验证.至于AOP的理论知识我就不做赘述.而AOP的通知类型有好几种,今天的例子我只选一个有代表意义的“环绕通知”来演示. 一.AOP入门 修改“pom.xml ...

  7. JAVA GUI编程学习笔记目录

    2014年暑假JAVA GUI编程学习笔记目录 1.JAVA之GUI编程概述 2.JAVA之GUI编程布局 3.JAVA之GUI编程Frame窗口 4.JAVA之GUI编程事件监听机制 5.JAVA之 ...

  8. 快速了解微信小程序的使用,一个根据小程序的框架开发的todos app

    微信官方已经开放微信小程序的官方文档和开发者工具.前两天都是在看相关的新闻来了解小程序该如何开发,这两天官方的文档出来之后,赶紧翻看了几眼,重点了解了一下文档中框架与组件这两个部分,然后根据简易教程, ...

  9. docker4dotnet #4 使用Azure云存储构建高速 Docker registry

    使用Docker来构建应用程序最常见的操作就是 docker run 或者 docker pull了,但是由于众所周知的原因,在国内想要高速稳定的获取docker hub上面的资源并不是件容易的事情, ...

  10. js实现四大经典排序算法

    为了方便测试,这里写了一个创建长度为n的随机数组 function createArr(n) { var arr = []; while (n--) { arr.push(~~(Math.random ...