我们经常在驱动中看到如下代码:
staticintxxx_probe(struct platform_device *pdev){ struct my_dev *my_dev; my_dev = devm_kzalloc(&pdev->dev, sizeof(*my_dev), GFP_KERNEL); if (!my_dev) return -ENOMEM; platform_set_drvdata(pdev, my_dev);}intxxx_remove(struct platform_device *pdev){ struct my_dev *key_dev = platform_get_drvdata(pdev); .....}
上面通过platform_set_drvdata来保存数据,然后再通过platform_get_drvdata来获取数据。通常用来传递自定义的设备结构体。很多同学可能会想,干嘛不直接用个全部变量,省得在几个函数间传来传去,接下来我们来讲讲它的好处,以及为什么不用全局变量。
比如:系统中有两个 SPI 控制器或者两个相同的温度传感器,你不能使用一个全局变量来存储每个设备的特定数据结构(如中断号、内存基址、设备私有状态)。所有设备实例都会尝试读写同一个全局变量,导致数据混乱和竞态条件。
回到上面的例子,我们可以看到在probe()函数中会为设备分配内存,这样子每个设备实例都会创建自己的设备结构体。然后通过platform_set_drvdata保存,这样子就独立开了。
platform_set_drvdata 是 Linux 设备驱动模型(LDDM) 推荐且标准化的做法。使用标准 API 可以让熟悉内核代码的开发者更容易理解你的驱动程序的意图和结构。
除非你确信设备驱动永远只会加载一个实例且不需要热插拔,否则永远应该使用 platform_set_drvdata 来绑定你的私有设备数据。这是编写健壮、可维护和符合内核规范的 Linux 驱动的关键一步。
每一个总线都有类似的函数,这里只是以platform总线为例。