参考:

《Linux设备驱动程序》第三版 P294

  许多内部的内核函数返回一个指针值给调用者,而这些函数中很多可能会失败。在大部分情况下,失败是通过返回一个NULL指针值来表示的。这种技巧有作用,但是它不能传递问题的确切性质。某些接口确实需要返回一个实际的错误编码,以使调用者可以根据实际出错的情况做出正确的决策。

  许多内核接口通过把错误值编码到一个指针值中来返回错误信息。这种函数必须小心使用,因为他们的返回值不能简单地和NULL比较。为了帮助创建和使用这种类型的接口,<linux/err.h>中提供了一小组函数。

  返回指针类型的函数可以通过如下函数返回一个错误值:

    void *ERR_PTR(long err);

  这里error是通常的负的错误编码。调用者可以使用IS_ERR来检查所返回的指针是否是一个错误编码:

    long IS_ERR(const void *ptr);

  如果需要实际的错误编码,可以通过如下函数把它提取出来:

    long PTR_ERR(const void *ptr);

  应该使用IS_ERR对某值返回真值时才对该值使用PTR_ERR,因为任何其他值都是有效指针。

补充:

在include/linux/err.h中定义如下几个宏:

1、void * ERR_PTR(long error):将错误编码转为指针

2、long PTR_ERR(const void *ptr):将指针转为错误编码

3、bool IS_ERR(const void *ptr):检查返回指针是否为一个错误编码,如果返回真,表示确实发生了错误

4、bool IS_ERR_OR_NULL(const void *ptr):检查返回的指针是否为NULL或是否为一个错误编码

5、int PTR_ERR_OR_ZERO(const void *ptr):将返回的指针转为0或者错误编码

6、void * ERR_CAST(const void *ptr):将const void *转为void *,防止编译报错

 #define MAX_ERRNO    4095

 #define IS_ERR_VALUE(x) unlikely((unsigned long)(void *)(x) >= (unsigned long)-MAX_ERRNO)

 static inline void * __must_check ERR_PTR(long error)
{
return (void *) error;
} static inline long __must_check PTR_ERR(__force const void *ptr)
{
return (long) ptr;
} static inline bool __must_check IS_ERR(__force const void *ptr)
{
return IS_ERR_VALUE((unsigned long)ptr);
} static inline bool __must_check IS_ERR_OR_NULL(__force const void *ptr)
{
return unlikely(!ptr) || IS_ERR_VALUE((unsigned long)ptr);
} /**
* ERR_CAST - Explicitly cast an error-valued pointer to another pointer type
* @ptr: The pointer to cast.
*
* Explicitly cast an error-valued pointer to another pointer type in such a
* way as to make it clear that's what's going on.
*/
static inline void * __must_check ERR_CAST(__force const void *ptr)
{
/* cast away the const */
return (void *) ptr;
} static inline int __must_check PTR_ERR_OR_ZERO(__force const void *ptr)
{
if (IS_ERR(ptr))
return PTR_ERR(ptr);
else
return ;
}

示例:

1、比如函数_devm_regulator_get用于获得指定的regulator指针:

 static struct regulator *_devm_regulator_get(struct device *dev, const char *id,
int get_type)
{
struct regulator **ptr, *regulator; ptr = devres_alloc(devm_regulator_release, sizeof(*ptr), GFP_KERNEL);
if (!ptr)
return ERR_PTR(-ENOMEM); switch (get_type) {
case NORMAL_GET:
regulator = regulator_get(dev, id);
break;
case EXCLUSIVE_GET:
regulator = regulator_get_exclusive(dev, id);
break;
case OPTIONAL_GET:
regulator = regulator_get_optional(dev, id);
break;
default:
regulator = ERR_PTR(-EINVAL);
} if (!IS_ERR(regulator)) {
*ptr = regulator;
devres_add(dev, ptr);
} else {
devres_free(ptr);
} return regulator;
}

第7行返回NULL,表示内存分配失败,但是由于该函数需要返回的是指针类型,所以我们用ERR_PTR对-ENOMEM进行包装

第21行,表示传入的参数不合法,此时用ERR_PTR对-EINVAL进行包装

下面是调用devm_regulator_get的地方:

     case snd_soc_dapm_regulator_supply:
w->regulator = devm_regulator_get(dapm->dev, w->name);
if (IS_ERR(w->regulator)) {
ret = PTR_ERR(w->regulator);
dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n",
w->name, ret);
return NULL;
}

第3行,如果IS_ERR返回指针确实是一个错误编码对应的指针,第4行就会用PTR_ERR将该指针转为一个错误编码给ret,后面可以根据需要处理该ret。

第7行,除了使用return NULL之外,还可以使用ERR_CAST(w->regulator)

 

完。

Linux驱动开发——指针和错误值的更多相关文章

  1. Linux 驱动开发

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

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

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

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

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

  4. Linux内核(17) - 高效学习Linux驱动开发

    这本<Linux内核修炼之道>已经开卖(网上的链接为: 卓越.当当.china-pub ),虽然是严肃文学,但为了保证流畅性,大部分文字我还都是斟词灼句,反复的念几遍才写上去的,尽量考虑到 ...

  5. linux驱动开发流程

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

  6. Linux驱动开发:USB驱动之usb_skel分析

    在学习了这么些天的驱动之后,个人觉得驱动就是个架构的问题,只要把架构弄清楚了 然后往里面添砖加瓦就可以了,所以似乎看起来不是太困难,但也许是是我经验不足吧,这只能算是个人浅见了 这两天在学习USB驱动 ...

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

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

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

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

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

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

随机推荐

  1. scrapy主动触发关闭爬虫

    在spider中时在方法里直接写 self.crawler.engine.close_spider(self, 'cookie失效关闭爬虫')   在pipeline和downloaderMiddle ...

  2. windows下使用pip安装python模块lxml

    pip install lxml 1 1 会有如下问题:  结果一路解决下去,解决了一个坑还是有一个坑,遂放弃,查找有没有别的解决办法. 亲测使用wheel+pip可以成功安装lxml! wheel本 ...

  3. ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2) 的解决办法

    更换mysql数据目录后出现ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql ...

  4. python基础-装饰器,生成器和迭代器

    学习内容 1.装饰器 2.生成器 3.迭代器 4.软件目录结构规范 一:装饰器(decorator) 1.装饰器定义:本质就是函数,用来装饰其他函数,即为其他函数添加附加功能. 2.装饰器原则:1)不 ...

  5. 深入迁出mybatis系列

    本系列教程均源于南柯梦,经好库文摘转发,感谢南柯梦的辛苦整理. 深入迁出mybatis系列 深入浅出Mybatis系列(一)---Mybatis入门 深入浅出Mybatis系列(二)---配置简介(m ...

  6. 文件时间戳修改touch和查看stat和ls --time

    查看文件时间戳命令:stat awk.txtFile: `awk.txt'Size: 20  Blocks: 8  IO Block: 4096  regular fileDevice: 801h/2 ...

  7. vue-element-table-js去重合并单元格解析【实战需求】

    有数据如下: { '2019-01-23': [ { 'channel': 'zp', 'listScanListNum': 24, 'listParseOkNum': 0, 'listPersonM ...

  8. 【Java】 大话数据结构(14) 排序算法(1) (冒泡排序及其优化)

    本文根据<大话数据结构>一书,实现了Java版的冒泡排序. 更多:数据结构与算法合集 基本概念 基本思想:将相邻的元素两两比较,根据大小关系交换位置,直到完成排序. 对n个数组成的无序数列 ...

  9. 005.KVM日常管理2-virt管理

    一 安装管理工具 [root@kvm-host ~]# rpm -qa|grep libguestfs-tools #查看相关管理工具,若没安装,可使用yum安装.   二 日常管理 2.1 命令格式 ...

  10. SpringBoot详细研究-03系统集成

    据说杰克船长被黑客盗片了,看来信息安全依然任重而道远,本文以此为引子,来介绍下spring boot对于系统集成方面的支持. Spring Security提供一套安全框架,通过IOC和AOP来实现安 ...