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

本文介绍了Linux内核中的dev_get_drvdata和dev_set_drvdata函数,它们用于设备驱动程序中存储和检索私有数据。dev_set_drvdata用于设置设备的driver_data,而dev_get_drvdata则在需要时获取数据。文章还提到这些函数在不同设备驱动和平台设备框架中的应用。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.youkuaiyun.com/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);
}
<think> 我们被要求使用中文回答问题,并且在回答后提出3-5个相关问题,且必须以“§§相关问题§§”开头,问题连续列出,不能换行分散。 问题:dev_get_drvdata是什么函数? 回答:解释dev_get_drvdata函数的作用、使用场景,并给出示例。 然后,提出3-5个相关问题。 </think> ### `dev_get_drvdata()` 函数详解 #### **函数定义作用** ```c void *dev_get_drvdata(const struct device *dev); ``` - **核心功能**:从Linux设备结构体`struct device`中提取驱动私有数据指针 - **返回值**:`void*`类型指针,指向驱动分配的私有数据结构 - **典型应用**: ```c struct my_private_data { int reg_value; char *buffer; }; void probe(struct device *dev) { // 获取私有数据 struct my_private_data *priv = dev_get_drvdata(dev); printk("寄存器值: %d\n", priv->reg_value); } ``` #### **底层实现原理** ```mermaid graph LR dev[device结构体] --> driver_data[driver_data字段] driver_data --> 私有数据结构 ``` - 实际访问`dev->driver_data`成员 - Linux内核源码实现: ```c // drivers/base/core.c void *dev_get_drvdata(const struct device *dev) { return dev->driver_data; // 直接返回指针 } ``` #### **使用场景对比** | **操作** | **设置数据** | **获取数据** | **关联函数** | |------------------------|-----------------------------|--------------------------|---------------------| | **写入数据指针** | `dev_set_drvdata(dev, data)` | `dev_get_drvdata(dev)` | 驱动初始化/probe阶段 | | **生命周期管理** | probe函数设置 | remove函数清理 | 贯穿设备运行周期 | | **典型数据结构** | 设备状态/寄存器映射等 | 配置参数/运行时数据 | | #### **错误使用示例** ```c // 错误:未初始化的访问 void read_data(struct device *dev) { struct priv *p = dev_get_drvdata(dev); // 可能返回NULL p->value = 10; // 空指针崩溃! } // 正确:初始化检查 void safe_access(struct device *dev) { if (!dev || !dev_get_drvdata(dev)) { return -EINVAL; // 错误处理 } } ``` #### **设备树协同工作** 1. **probe函数初始化**: ```c static int mydrv_probe(struct platform_device *pdev) { struct priv *priv = devm_kzalloc(&pdev->dev, sizeof(*priv)); dev_set_drvdata(&pdev->dev, priv); // 绑定私有数据 } ``` 2. **sysfs接口访问**: ```c static ssize_t show_value(struct device *dev, ...) { struct priv *priv = dev_get_drvdata(dev); return sprintf(buf, "%d\n", priv->value); } ``` #### **实际应用案例** **GPIO控制器驱动片段**: ```c struct gpio_private { void __iomem *base; struct gpio_chip chip; }; static int gpio_probe(struct platform_device *pdev) { struct gpio_private *priv; priv = devm_kzalloc(dev, sizeof(*priv)); priv->base = devm_ioremap_resource(dev, res); // 关键数据绑定 dev_set_drvdata(dev, priv); // 其他初始化 priv->chip.label = "my_gpio"; } static irqreturn_t gpio_irq(int irq, void *dev_id) { struct device *dev = dev_id; struct gpio_private *priv = dev_get_drvdata(dev); // 获取私有数据 u32 status = readl(priv->base + REG_STATUS); // 处理中断... } ```
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值