GPIO Devres
之前常用的gpio接口,需要对申请的资源进行管理,如果要管理多个资源,这是很麻烦的一件事,Is there a easier way?
调用下面的接口,将申请的资源与device绑定,就不需要手动管理这些资源了:
devm_gpiod_get()
devm_gpiod_get_index()
devm_gpiod_get_index_optional()
devm_gpiod_get_optional()
devm_gpiod_put()
devm_gpiod_unhinge()
devm_gpiochip_add_data()
devm_gpio_request()
devm_gpio_request_one()
devm_gpio_free()
其实很多资源都可以用这种方法进行管理的,这个在Documentation/driver-api/driver-model/devres.rst中有简单的介绍。
那么,对资源进行管理都发生在什么时候呢:
- 驱动remove时
- 驱动probe失败时
- 驱动响应一个事件时临时申请释放的资源
- …
devres机制可以对这些资源全部进行管理吗?这个有待商榷,至少第三种资源是不适合的。不过这种资源可以通过devres group机制进行管理。
那先看第一种,接下来以platform驱动为例,查看函数platform_driver_unregister
:
platform_driver_unregister
|
V
driver_unregister
|
V
bus_remove_driver
|
V
driver_detach
|
V
device_release_driver_internal
|
V
__device_release_driver
一直跟踪,在__device_release_driver中有一个与devres机制相关的函数调用devres_release_all
,将其展开,不用查看函数内部,看注释该函数的功能,是将device所绑定的资源全部release。所以说,只要使用devres机制,在驱动probe函数获取的资源,就不需要在驱动remove时进行释放了。
/**
* devres_release_all - Release all managed resources
* @dev: Device to release resources for
*
* Release all resources associated with @dev. This function is
* called on driver detach.
*/
int devres_release_all(struct device *dev)
{
unsigned long flags;
/* Looks like an uninitialized device structure */
if (WARN_ON(dev->devres_head.next == NULL))
return -ENODEV;
spin_lock_irqsave(&dev->devres_lock, flags);
return release_nodes(dev, dev->devres_head.next, &dev->devres_head,
flags);
}
接下来看第二种情况,驱动probe失败时,devres机制可以对这种资源进行管理吗,接下来以platform驱动为例,跟踪platform_driver_register
:
platform_driver_register
|
V
__platform_driver_register
|
V
driver_register
|
V
bus_add_driver
|
V
driver_attach
|
V
bus_for_each_dev
|
V
__driver_attach
|
V
device_driver_attach
|
V
driver_probe_device
|
V
really_probe
将really_probe
函数展开,下面的函数只保留本次分析的关键点,在调用驱动的probe时,若probe失败,会调用devres_release_all
将probe时获取的资源释放掉。
static int really_probe(struct device *dev, struct device_driver *drv)
{
if (dev->bus->probe) {
ret = dev->bus->probe(dev);
if (ret)
goto probe_failed;
} else if (drv->probe) {
ret = drv->probe(dev);
if (ret)
goto probe_failed;
}
probe_failed:
if (dev->bus)
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
BUS_NOTIFY_DRIVER_NOT_BOUND, dev);
pinctrl_bind_failed:
device_links_no_driver(dev);
devres_release_all(dev);
}
对devres机制要有更深入的了解,可以查看源码drivers/gpio/gpiolib-devres.c,及drivers/base/devres.c等等。