版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/xi_xix_i/article/details/134608997
linux 4.19
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()
是设置传入的device
的driver_data
变量指向传入的data
,dev_get_drvdata()
是获取dev
的data
变量,其中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()
的实现方式。不过思想倒是相似的,就是给设备设置私有数据,需要用到这些数据的时候就取出来。
看一段内核中自带的驱动程序中是如何使用这一对函数的:
...
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);
}