为什么写?临时起意。
写什么?一个Battery Fuel Guage,I2C设备驱动的注册过程。
遇到一个电池Guage的使用,写一下对I2C设备注册的整个过程。该电池Gauage型号是Maxim
max1720x/max1721x。
驱动入口,通常就是probe函数,例如:
static int max1720x_probe(struct i2c_client *client,const struct i2c_device_id *id),在这个函数中,进行Guage的初始化/信息获取等操作。
那问题来了,这个接口的参数怎么来的呢?是啥作用?带着这两个问题,简单跟一内核代码(kernle4.19)。
接口隶属于下面的结构:
static struct i2c_driver max1720x_i2c_driver = {
.driver = {
.name = "max1720x", //这个名字在驱动和设备的匹配中没有起到作用,仅仅是在设备表示上有意义.
#ifdef CONFIG_OF //OF open firmware.
.of_match_table = of_match_ptr(max1720x_dt_match), // of: open firmware
#endif
.pm = &max1720x_pm_ops,
},
.probe = max1720x_probe,
.remove = max1720x_remove,
.id_table = max1720x_id,
};
/* module_i2c_driver(max1720x_i2c_driver); */
很清楚能够看到这是一个struct i2c_driver 类型的变量的一个成员函数。那么,这个变量如何使用?可以看到,内核设备驱动的统一入口使用了它。
static int __init max1720x_battery_init(void)
{
int ret;
ret = i2c_add_driver(&max1720x_i2c_driver);
if (ret)
printk(KERN_ERR "Unable to register MAX1720x driver\n");
return ret;
}
module_init(max1720x_battery_init); //这个module_init就是设备驱动的统一入口,后面再细说。反正内核启动之后,会逐一去运行module_init中的函数。
module_init( xxx ),这个暂且不提,就知道系统内核启动过程中会去调用其参数(接口)就行。
max1720x_battery_init( xxx )函数提只进行了一项操作--> i2c_add_driver ( xxx );
好,现在注意力集中了,我们要正式进入linux 内核的世界 了,英踹斯汀。
i2c_add_driver( xxx )定义在linux/include/i2c.h
/* use a define to avoid include chaining to get THIS_MODULE */
#define i2c_add_driver(driver) \
i2c_register_driver(THIS_MODULE, driver)
//第一句的注释是没看懂没关系,老规矩,先别急,随着眼界的不断提高,慢慢就懂了。
//这是一个宏,对应的定义位于 driver/i2c/i2c-core.c , 我们正式来到了i2c的驱动核心了。
/*
* An i2c_driver is used with one or more i2c_client (device) nodes to access
* i2c slave chips, on a bus instance associated with some i2c_adapter.
* 这个注释能想到,刚开始学习驱动时候,一个驱动对应多个同类型设备的概念。
*/
int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
{
int res;
/* Can't register until after driver model init */
if (unlikely(WARN_ON(!i2c_bus_type.p)))
return -EAGAIN;
/* add the driver to the list of i2c drivers in the driver core */
driver->driver.owner = owner;
driver->driver.bus = &i2c_bus_type; //先给要注册到内核的驱动对应的总线。显然,这个是i2c总线。物理上,总线是通常直接到CPU,总线上安插着控制器和多个设备。
INIT_LIST_HEAD(&driver->clients);
/* When registration returns, the driver core
* will have called probe() for all matching-but-unbound devices.
*/
res = driver_register(&driver->driver); //这里注册的不是i2c_driver 的实例(max1720x_i2c_driver),而是device_driver 的一个变量。这里借用C++面向对象的说法,i2c_driver 继承了struct device_driver。 可以说注册的是父类的一个实例。
if (res)
return res;
pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
/* Walk the adapters that are already present */ //这个操作很神奇,为什么要去遍历控制器adapter?老规矩,先别急,随着眼界的不断提高,慢慢就懂了。目前知道一个事情就行了,bus对附着着的设备一视同仁,都是设备。
i2c_for_each_dev(driver, __process_new_driver);
return 0;
}
EXPORT_SYMBOL(i2c_register_driver); //简单的说,就是这里定义,他出使用。
重点看下 res = driver_register(&driver->driver); 定义位于:driver/base/driver.c。将要进行一个最基本struct device_driver变量的一个注册操作。
/**
* driver_register - register driver with bus
* @drv: driver to register
*
* We pass off most of the work to the bus_add_driver() call,
* since most of the things we have to do deal with the bus
* structures. //可见这个bus多重要。要想富,先铺路啊。
*/
int driver_register(struct device_driver *drv) //驱动模型的最小粒度数据结构
{
int ret;
struct device_driver *other;
BUG_ON(!drv->bus->p); //很好玩的一个调试手段,英踹斯汀
if ((drv->bus->probe && drv->probe) || //drv->probe肯定得是空,为什么?因为父类的方法一定是需要重写的方法。父类只负责内核的设备模型,而具体实现/行为是每个设备自己实现。
(drv->bus->remove && drv->remove) ||
(drv->bus->shutdown && drv->shutdown))
printk(KERN_WARNING "Driver '%s' needs updating - please use "
"bus_type methods\n", drv->name);
other = driver_find(drv->name, drv->bus); //这里要干什么?内核要确认目前的总线上并没有哦注册同名的驱动,如果有重名的,说明有冲突或者说已经注册过驱动了。
if (other) {
printk(KERN_ERR "Error: Driver '%s' is already registered, "
"aborting...\n", drv->name);
return -EBUSY;
}
ret = bus_add_driver(drv); //父类driver负责设备模型,将驱动加入和内核世界。这里会走驱动和设备的匹配过程。暂时按下不表。
if (ret)
return ret;
ret = driver_add_groups(drv, drv->groups); //将device_driver放入到驱动组用于设备模型构建。
if (ret) {
bus_remove_driver(drv);
return ret;
}
kobject_uevent(&drv->p->kobj, KOBJ_ADD); //uevent又是一个英踹斯汀话题,暂时按下不表。
return ret;
}
EXPORT_SYMBOL_GPL(driver_register);
我们来看看这个功能最复杂的也是最重要的bus_add_driver函数.
/**
* bus_add_driver - Add a driver to the bus.
* @drv: driver.
*/
int bus_add_driver(struct device_driver *drv)
{
struct bus_type *bus;
struct driver_private *priv;
int error = 0;
bus = bus_get(drv->bus);
if (!bus)
return -EINVAL;
pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);
priv = kzalloc(sizeof(*priv), GFP_KERNEL); //为driver申请私有数据空间
if (!priv) {
error = -ENOMEM;
goto out_put_bus;
}
klist_init(&priv->klist_devices, NULL, NULL);
priv->driver = drv;
drv->p = priv;
priv->kobj.kset = bus->p->drivers_kset;
error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
"%s", drv->name); //设备模型
if (error)
goto out_unregister;
klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
if (drv->bus->p->drivers_autoprobe) { //i2c_bus 中没有初始化p。那如果初始化了,会有什么好处?设计上的优势?
if (driver_allows_async_probing(drv)) {
pr_debug("bus: '%s': probing driver %s asynchronously\n",
drv->bus->name, drv->name);
async_schedule(driver_attach_async, drv);
} else {
error = driver_attach(drv); //驱动和对应的设备进行链接/和对应的bus进行链接
if (error)
goto out_unregister;
}
}
module_add_driver(drv->owner, drv); //
error = driver_create_file(drv, &driver_attr_uevent);
if (error) {
printk(KERN_ERR "%s: uevent attr (%s) failed\n",
__func__, drv->name);
}
error = driver_add_groups(drv, bus->drv_groups);
if (error) {
/* How the hell do we get out of this pickle? Give up */
printk(KERN_ERR "%s: driver_create_groups(%s) failed\n",
__func__, drv->name);
}
if (!drv->suppress_bind_attrs) {
error = add_bind_files(drv); //这是在做什么?
if (error) {
/* Ditto */
printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
__func__, drv->name);
}
}
return 0;
out_unregister:
kobject_put(&priv->kobj);
/* drv->p is freed in driver_release() */
drv->p = NULL;
out_put_bus:
bus_put(bus);
return error;
}
来到,driver_attach(...); driver/base/dd.c
/**
* driver_attach - try to bind driver to devices.
* @drv: driver.
*
* Walk the list of devices that the bus has on it and try to
* match the driver with each one. If driver_probe_device()
* returns 0 and the @dev->driver is set, we've found a
* compatible pair.
* 这段注释很优美,能够知道很多内容。1. 内核中已有设备list。2. 用当前的driver去遍历 3. 遍历bus上已经有的所有设备。
*/
int driver_attach(struct device_driver *drv)
{
return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach); //__driver_attach,作为参数传入的函数调用。优美!
}
EXPORT_SYMBOL_GPL(driver_attach);
接着是,drivers/base/bus.c
/**
* bus_for_each_dev - device iterator.
* @bus: bus type.
* @start: device to start iterating from.
* @data: data for the callback.
* @fn: function to be called for each device.
*
* Iterate over @bus's list of devices, and call @fn for each, //这个fn厉害了!
* passing it @data. If @start is not NULL, we use that device to
* begin iterating from.
*
* We check the return of @fn each time. If it returns anything
* other than 0, we break out and return that value.
*
* NOTE: The device that returns a non-zero value is not retained
* in any way, nor is its refcount incremented. If the caller needs
* to retain this data, it should do so, and increment the reference
* count in the supplied callback.
*/
int bus_for_each_dev(struct bus_type *bus, struct device *start,
void *data, int (*fn)(struct device *, void *))
{
struct klist_iter i; //是不是有点迭代器内味。
struct device *dev;
int error = 0;
if (!bus || !bus->p)
return -EINVAL;
klist_iter_init_node(&bus->p->klist_devices, &i,
(start ? &start->p->knode_bus : NULL));
while ((dev = next_device(&i)) && !error) //原来设备时这么来的,某bus上的设备列表。
error = fn(dev, data); //从上面的调用,可以看到这个data就是struct driver *device_driver, 这里即i2c_driver中的device_driver. fn即__driver_attach()
klist_iter_exit(&i);
return error;
}
EXPORT_SYMBOL_GPL(bus_for_each_dev);
来了来了,fb( dev, data) -> __driver_attach(dev,drv):
static int __driver_attach(struct device *dev, void *data)
{
struct device_driver *drv = (struct device_driver*) data; //进行强行类型转换。这里的void*是无类型指针,可以指向任何类型,不要尝试进行解引用。英踹斯汀。
/*
* Lock device and try to bind to it. We drop the error
* here and always return 0, because we need to keep trying
* to bind to devices and some drivers will return an error
* simply if it didn't support the device.
* 优美的注释,可以说“清水出芙蓉,天然去雕饰”的注释,为什么返回0,因为我允许你可以范错误。
* driver_probe_device() will spit a warning if there
* is an error.
*/
if (!driver_match_device(drv, dev)) //通过idtable中的名称和设备树中的名称进行匹配;确定系统启动过程中,dt正确,对应的设备创建合理,最后bus上挂有对应的设备.
return 0;
if (lock_parent(dev))
device_lock(dev->parent);
device_lock(dev);
if (!dev->driver) //这个必然为空,大家想想为什么?(想想多态性,用父类的指针指向子类时候,对应的接口,我们会根据上下文context,决定要调用子类中的的接口,这里父类的接口一定格式一个虚,需要子类复写。所以,这里的作为父类的device,移动不用实现)
driver_probe_device(drv, dev); //准备调用驱动中的probe接口,进行设备和驱动的绑定,这里对应的就是max1270x电池设备驱动的max1720x_probe。
device_unlock(dev);
if (lock_parent(dev))
device_unlock(dev->parent);
return 0;
}
最核心的时候到了,driver_probe_device(...);
/**
* driver_probe_device - attempt to bind device & driver together
* @drv: driver to bind a device to
* @dev: device to try to bind to the driver
*
* This function returns -ENODEV if the device is not registered,
* 1 if the device is bound successfully and 0 otherwise.
*
* This function must be called with @dev lock held. When called for a
* USB interface, @dev->parent lock must be held as well.
*
* If the device has a parent, runtime-resume the parent before driver probing.
*/
int driver_probe_device(struct device_driver *drv, struct device *dev)
{
int ret = 0;
if (!device_is_registered(dev))
return -ENODEV;
pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
drv->bus->name, __func__, dev_name(dev), drv->name);
if (dev->parent)
pm_runtime_get_sync(dev->parent);
pm_runtime_barrier(dev); //英踹斯汀,暂时按下不表。
ret = really_probe(dev, drv); //这个名称起的真是好,真正的探寻设备。
pm_request_idle(dev);
if (dev->parent)
pm_runtime_put(dev->parent);
return ret;
}
really_probe(...)//简单的说就是真正的探测设备来了。要用子类/具体类型的设备驱动来绑定对应的dts中定义的设备。
static int really_probe(struct device *dev, struct device_driver *drv)
{
int ret = 0;
int local_trigger_count = atomic_read(&deferred_trigger_count);
atomic_inc(&probe_count);
pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
drv->bus->name, __func__, drv->name, dev_name(dev));
WARN_ON(!list_empty(&dev->devres_head));
dev->driver = drv;
/* If using pinctrl, bind pins now before probing */
ret = pinctrl_bind_pins(dev); //将设备和用pin(GPIO)的情况绑定,英踹斯汀。
if (ret)
goto probe_failed;
if (driver_sysfs_add(dev)) {
printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
__func__, dev_name(dev));
goto probe_failed;
}
if (dev->pm_domain && dev->pm_domain->activate) {
ret = dev->pm_domain->activate(dev); //激活设备,优美。
if (ret)
goto probe_failed;
}
if (dev->bus->probe) { //如果对应的总线上有probe接口,那么调用总线的probe. 最终还是call到了所注册驱动的probe接口.
ret = dev->bus->probe(dev); //这个probe就是i2c_bus 中的probe,我们回到i2c-core.c
if (ret)
goto probe_failed;
} else if (drv->probe) {
ret = drv->probe(dev); //driver都没实现,怎么会有接口实现呢?
if (ret)
goto probe_failed;
}
pinctrl_init_done(dev);
if (dev->pm_domain && dev->pm_domain->sync)
dev->pm_domain->sync(dev);
driver_bound(dev); //新面孔
ret = 1;
pr_debug("bus: '%s': %s: bound device %s to driver %s\n",
drv->bus->name, __func__, dev_name(dev), drv->name);
goto done;
probe_failed:
devres_release_all(dev);
driver_sysfs_remove(dev);
dev->driver = NULL;
dev_set_drvdata(dev, NULL);
if (dev->pm_domain && dev->pm_domain->dismiss)
dev->pm_domain->dismiss(dev);
switch (ret) {
case -EPROBE_DEFER:
/* Driver requested deferred probing */
dev_dbg(dev, "Driver %s requests probe deferral\n", drv->name);
driver_deferred_probe_add(dev);
/* Did a trigger occur while probing? Need to re-trigger if yes */
if (local_trigger_count != atomic_read(&deferred_trigger_count))
driver_deferred_probe_trigger();
break;
case -ENODEV:
case -ENXIO:
pr_debug("%s: probe of %s rejects match %d\n",
drv->name, dev_name(dev), ret);
break;
default:
/* driver matched but the probe failed */
printk(KERN_WARNING
"%s: probe of %s failed with error %d\n",
drv->name, dev_name(dev), ret);
}
/*
* Ignore errors returned by ->probe so that the next driver can try
* its luck.
*/
ret = 0;
done:
atomic_dec(&probe_count);
wake_up(&probe_waitqueue);
return ret;
}
i2c-core.c中的i2c_bus_type -> probe
static int i2c_device_probe(struct device *dev)
{
struct i2c_client *client = i2c_verify_client(dev); //这个verify是具体如何check的呢?
struct i2c_driver *driver;
int status;
if (!client)
return 0;
if (!client->irq) {
int irq = -ENOENT;
if (dev->of_node) {
irq = of_irq_get_byname(dev->of_node, "irq");
if (irq == -EINVAL || irq == -ENODATA)
irq = of_irq_get(dev->of_node, 0);
} else if (ACPI_COMPANION(dev)) {
irq = acpi_dev_gpio_irq_get(ACPI_COMPANION(dev), 0);
}
if (irq == -EPROBE_DEFER)
return irq;
if (irq < 0)
irq = 0;
client->irq = irq;
}
driver = to_i2c_driver(dev->driver); //来了来了, 跑到了最后的i2c_drvier了;具体类型的bus,具体设备类型的驱动。是i2c就是i2c_driver, 完美!
if (!driver->probe || !driver->id_table)
return -ENODEV;
if (client->flags & I2C_CLIENT_WAKE) {
int wakeirq = -ENOENT;
if (dev->of_node) {
wakeirq = of_irq_get_byname(dev->of_node, "wakeup"); //唤醒系统功能?
if (wakeirq == -EPROBE_DEFER)
return wakeirq;
}
device_init_wakeup(&client->dev, true); //注册的设备是否具有唤醒系统功能,英踹斯汀,暂时按下不表。
if (wakeirq > 0 && wakeirq != client->irq)
status = dev_pm_set_dedicated_wake_irq(dev, wakeirq);
else if (client->irq > 0)
status = dev_pm_set_wake_irq(dev, client->irq);
else
status = 0;
if (status)
dev_warn(&client->dev, "failed to set up wakeup irq");
}
dev_dbg(dev, "probe\n");
status = of_clk_set_defaults(dev->of_node, false);
if (status < 0)
goto err_clear_wakeup_irq;
status = dev_pm_domain_attach(&client->dev, true);
if (status == -EPROBE_DEFER)
goto err_clear_wakeup_irq;
status = driver->probe(client, i2c_match_id(driver->id_table, client)); //最终还是call的注册驱动的probe接口进行初始化!来了来了。这里的client,id_table 和具体的电池驱动中的接口对上了:static int max1720x_probe(struct i2c_client *client,const struct i2c_device_id *id)。
if (status)
goto err_detach_pm_domain;
return 0;
err_detach_pm_domain:
dev_pm_domain_detach(&client->dev, true);
err_clear_wakeup_irq:
dev_pm_clear_wake_irq(&client->dev);
device_init_wakeup(&client->dev, false);
return status;
}
static int max1720x_probe(struct i2c_client *client,const struct i2c_device_id *id) 开始运行。到此,从具体i2c设备驱动的注册到内核中的基础代码的执行过程。最终,我们知道了,具体i2c驱动中的probe参数的来历,以后再也不会迷路了。
英踹斯汀