基于linux 3.10.49内核的gpio流程分析
linux kernel 3.10.49+
在这里, 我们说说linux 是怎么通过platform_driver驱动代码匹配到platform_device的.static const struct of_device_id ***_gpio_of_match[] = {
{ .compatible = "******,***-gpio", }, // 这个字符串就是dts里的compatible字符串
{}
};
MODULE_DEVICE_TABLE(of, ***_gpio_of_match);
static struct platform_driver ***_gpio_driver = {
.probe = ***_gpio_probe, // 匹配完成后, 运行的probe函数, 可以做一些初始化.
.driver = {
.name = "***_gpio",
.owner = THIS_MODULE,
.of_match_table = ***_gpio_of_match,
},
};
module_platform_driver(***_gpio_driver);
1. drivers/gpio/gpio-***.c : module_platform_driver(***_gpio_driver); // gpio驱动入口
2. include/linux/platform_device.h 宏 : module_platform_driver
#define module_platform_driver(__platform_driver) \
module_driver(__platform_driver, platform_driver_register, \
platform_driver_unregister)
3. drivers/base/platform.c : platform_driver_register(...)
drv->driver.bus = &platform_bus_type;
drv->driver.bus = &platform_bus_type;
if (drv->probe)
drv->driver.probe = platform_drv_probe; // 后面会使用.
if (drv->remove)
drv->driver.remove = platform_drv_remove;
if (drv->shutdown)
drv->driver.shutdown = platform_drv_shutdown;
return driver_register(&drv->driver);
4. drivers/base/driver.c : driver_register(...)
...
ret = bus_add_driver(drv);
...
5. drivers/base/bus.c : bus_add_driver(...)
...
error = driver_attach(drv);
...
6. drivers/base/bus.c : driver_attach(...)
int driver_attach(struct device_driver *drv)
{
return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
}
7. drivers/base/dd.c : bus_for_each_dev(...)
...
klist_iter_init_node(&bus->p->klist_devices, &i,
(start ? &start->p->knode_bus : NULL));
while ((dev = next_device(&i)) && !error) // 这个就是全局变量中, 所有已经进行过注册的device.
// 在上一篇 基于linux 3.10.49内核 从dts文件里注册platform_device流程分析 已介绍过
error = fn(dev, data); // fn 就是 __driver_attach 函数指针. 轮询device进行匹配.
klist_iter_exit(&i);
...
8. drivers/base/dd.c : __driver_attach(...)
...
if (!driver_match_device(drv, dev)) // 匹配成功, 返加非0, 否则返回0. // 跳到第8-1-1步
return 0;
if (dev->parent) /* Needed for USB */ // 有父设备, 父设备也就加锁
device_lock(dev->parent);
device_lock(dev); // 设备加锁
if (!dev->driver) // 如果device没有驱动程序, 就driver_probe_device
driver_probe_device(drv, dev); // 跳到第8-2-1步
device_unlock(dev); // 设备释放锁
if (dev->parent) // 有父设备, 父设备也就释放锁
device_unlock(dev->parent);
return 0
8-1-1. drivers/base/base.h : driver_match_device(...)
static inline int driver_match_device(struct device_driver *drv,
struct device *dev)
{
return drv->bus->match ? drv->bus->match(dev, drv) : 1;
}
// drv->bus 就是 第三步的 drv->driver.bus = &platform_bus_type;
// 也就是相当于platform_bus_type->match(dev, drv);
// struct bus_type platform_bus_type = { // drivers/base/platform.c
// .name = "platform",
// .dev_attrs = platform_dev_attrs,
// .match = platform_match,
// .uevent = platform_uevent,
// .pm = &platform_dev_pm_ops,
// };
// EXPORT_SYMBOL_GPL(platform_bus_type);
// 也就是platform_match(dev, drv);
8-1-2. drivers/base/platform.c : platform_match(...)
static int platform_match(struct device *dev, struct device_driver *drv)
{
...
if (of_driver_match_device(dev, drv))
return 1;
...
}
8-1-3. include/linux/of_device.h : of_driver_match_device(...)
static inline int of_driver_match_device(struct device *dev,
const struct device_driver *drv)
{
return of_match_device(drv->of_match_table, dev) != NULL; // 也就是***_gpio_of_match
}
of_match_device(...) --> of_match_node(...)
of_match_node(...) --> __of_match_node(...)
static const struct of_device_id *__of_match_node(const struct of_device_id *matches,
const struct device_node *node) // matches 就是drv->of_match_table, 也就是***_gpio_of_match
{
if (!matches)
return NULL;
while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
int match = 1;
if (matches->name[0])
match &= node->name
&& !strcmp(matches->name, node->name);
if (matches->type[0])
match &= node->type
&& !strcmp(matches->type, node->type);
if (matches->compatible[0])
match &= __of_device_is_compatible(node, // 匹配 compatible
matches->compatible); // ***_gpio_of_match.compatible 与 device node 的 compatible 匹配
if (match)
return matches;
matches++;
}
return NULL;
}
static int __of_device_is_compatible(const struct device_node *device,
const char *compat)
{
const char* cp;
int cplen, l;
cp = __of_get_property(device, "compatible", &cplen); // 这里就是获取device的compatible的字符串信息
if (cp == NULL)
return 0;
while (cplen > 0) {
if (of_compat_cmp(cp, compat, strlen(compat)) == 0) // 对比device的compatible的字符串信息和driver的compatible的字符串信息是否相等
return 1;
l = strlen(cp) + 1;
cp += l;
cplen -= l;
}
return 0;
}
8-2-1. drivers/base/dd.c : driver_probe_device(...)
driver_probe_device(...) --> really_probe(...)
8-2-2. drivers/base/dd.c : really_probe(...)
...
dev->driver = drv; // 驱动 赋值给 设备.
pinctrl_bind_pins(); // 跳到第8-2-2-1-1步
...
if (dev->bus->probe) {
ret = dev->bus->probe(dev);
if (ret)
goto probe_failed;
} else if (drv->probe) {
ret = drv->probe(dev); // 前面platform_driver_register(...)时 drv->driver.probe = platform_drv_probe, 所以进入platform_drv_probe
// 跳到第8-2-2-2-1步
if (ret)
goto probe_failed;
}
driver_bound(dev); // 驱动挷定设备
8-2-2-1-1. drivers/base/pinctrl.c : pinctrl_bind_pins(...)
dev->pins = devm_kzalloc(dev, sizeof(*(dev->pins)), GFP_KERNEL);
if (!dev->pins)
return -ENOMEM;
dev->pins->p = devm_pinctrl_get(dev); // 调用 pinctrl_get(...) --> create_pinctrl(...)
// 又进入到pinctrl子系统代码中
// 在create_pinctrl(...)里
// p->states, p->dt_maps都为空, 只有pinctrl-0的dts节点设备才不为空, 具体查看, pinctrl驱动初始化
// 具体查看 基于linux 3.10.49内核的pinctrl流程分析 补充 已介绍过
// 加入到list_add_tail(&p->node, &pinctrl_list);
// 每一个驱动注册时, alloc的struct pinctrl都会加入到全局变量pinctrl_list列表中.
if (IS_ERR(dev->pins->p)) {
dev_dbg(dev, "no pinctrl handle\n");
ret = PTR_ERR(dev->pins->p);
goto cleanup_alloc;
}
dev->pins->default_state = pinctrl_lookup_state(dev->pins->p,
PINCTRL_STATE_DEFAULT); // gpio是没有state, 一般只有pinctrl-0的dts节点设备才存在.
if (IS_ERR(dev->pins->default_state)) {
dev_dbg(dev, "no default pinctrl state\n");
/* printk(">>>>>>>>>>>>>>>>>>>>>>>>>>>> dev_name(dev) = %s\n", dev_name(dev)); */
ret = 0;
goto cleanup_get; // 没有state, ret = 0; 直接goto cleanup_get;
}
8-2-2-2-1. drivers/base/platform.c : platform_drv_probe(...)
...
ret = drv->probe(dev); // struct platform_driver ***_gpio_driver的probe函数.也就是***_gpio_probe, 最终目的来到这里.可以自定义写代码了.
...