linux驱动开发中常用函数--dev_get_drvdata()与dev_set_drvdata()的用法

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/xi_xix_i/article/details/134608997

1. 开发环境

linux 4.19

1. dev_get_drvdata()与dev_set_drvdata()函数简介

dev_get_drvdata()函数和dev_set_drvdata()函数位于include/linux/device.h中,起源码如下:

static inline void *dev_get_drvdata(const struct device *dev)
{
	return dev->driver_data;
}
...
static inline void dev_set_drvdata(struct device *dev, void *data)
{
	dev->driver_data = data;
}

可以看到,这两个函数非常简单,dev_set_drvdata()是设置传入的devicedriver_data变量指向传入的datadev_get_drvdata()是获取devdata变量,其中driver_data可以理解为这个device的私有数据。

而且与其他大部分文章所描述的函数源码不同,如这篇文章,我将其转载过来。

 void *dev_get_drvdata(const struct device *dev)
{
     if (dev && dev->p) {
           return dev->p->driver_data;
     return NULL;
}

可以看到根据文章所述dev_get_drvdata()函数是对device下的struct device_private类型私有数据结构体变量p中的driver_data进行操作,在查看struct device_private的定义后(位于文件drivers/base/base.h):

/**
 * struct device_private - structure to hold the private to the driver core portions of the device structure.
 *
 * @klist_children - klist containing all children of this device
 * @knode_parent - node in sibling list
 * @knode_driver - node in driver list
 * @knode_bus - node in bus list
 * @deferred_probe - entry in deferred_probe_list which is used to retry the
 *	binding of drivers which were unable to get all the resources needed by
 *	the device; typically because it depends on another driver getting
 *	probed first.
 * @device - pointer back to the struct device that this structure is
 * associated with.
 * @dead - This device is currently either in the process of or has been
 *	removed from the system. Any asynchronous events scheduled for this
 *	device should exit without taking any action.
 *
 * Nothing outside of the driver core should ever touch these fields.
 */
struct device_private {
	struct klist klist_children;
	struct klist_node knode_parent;
	struct klist_node knode_driver;
	struct klist_node knode_bus;
	struct list_head deferred_probe;
	struct device *device;
	u8 dead:1;
};

发现device_private下也没有driver_data变量。而且根据文章作者描述,该源码位于drivers/base/dd.c文件中,但是在我的内核版本中该文件下并没有dev_get_drvdata的函数定义代码。所以我猜测这是早期的linux版本下的dev_get_drvdata()的实现方式。不过思想倒是相似的,就是给设备设置私有数据,需要用到这些数据的时候就取出来。

2. dev_get_drvdata()与dev_set_drvdata()函数测试

看一段内核中自带的驱动程序中是如何使用这一对函数的:

...
struct rv3029_data {
	struct device		*dev;
	struct rtc_device	*rtc;
	struct regmap		*regmap;
	int irq;
};
...
static int rv3029_read_regs(struct device *dev, u8 reg, u8 *buf,
			    unsigned int len)
{
	struct rv3029_data *rv3029 = dev_get_drvdata(dev);				/* 调用dev_get_drvdata()函数 */

	if ((reg > RV3029_USR1_RAM_PAGE + 7) ||
	    (reg + len > RV3029_USR1_RAM_PAGE + 8))
		return -EINVAL;

	return regmap_bulk_read(rv3029->regmap, reg, buf, len);
}
...
static int rv3029_probe(struct device *dev, struct regmap *regmap, int irq,
			const char *name)
{
	struct rv3029_data *rv3029;
	...
	rv3029 = devm_kzalloc(dev, sizeof(*rv3029), GFP_KERNEL);
	...
	dev_set_drvdata(dev, rv3029);							/* 调用dev_set_drvdata()函数 */
	...
	return 0;
}

调用dev_set_drvdata()设置私有数据,然后需要用到的时候可以调用dev_get_drvdata()取出来。

并且很多其他类似的函数底层都是调用上述两个函数,比如定义于include/linux/platform_device.h下的platform_set_drvdata()platform_get_drvdata()函数:

static inline void platform_set_drvdata(struct platform_device *pdev,
					void *data)
{
	dev_set_drvdata(&pdev->dev, data);
}

static inline void *platform_get_drvdata(const struct platform_device *pdev)
{
	return dev_get_drvdata(&pdev->dev);
}

又或者是定于于include/linux/i2c.h下的i2c_set_clientdata()i2c_get_clientdata()函数:

static inline void *i2c_get_clientdata(const struct i2c_client *dev)
{
	return dev_get_drvdata(&dev->dev);
}

static inline void i2c_set_clientdata(struct i2c_client *dev, void *data)
{
	dev_set_drvdata(&dev->dev, data);
}
  • 10
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值