导图社区 linux I2C驱动 分析 (以AT24EEPROM为例,持续更新)
这是一篇关于linux I2C驱动 分析 (以AT24EEPROM为例,持续更新)的思维导图。I2C协议是嵌入式系统中广泛使用的一类通信协议,主要用于CPU和各种外设之间的低速数据通信。Linux kernel使用I2C framework抽象、管理相应的资源,并以各种形式,向各类使用者提供API。另外,作为总线(bus)的一种,I2C framework的实现体现了linux设备模型的精髓,值得研究与学习。
编辑于2021-03-31 22:39:30
static int __init at24_init(void){ if (!io_limit) { pr_err("at24: io_limit must not be 0!\n"); return -EINVAL; } io_limit = rounddown_pow_of_two(io_limit); return i2c_add_driver(&at24_driver);}module_init(at24_init);static void __exit at24_exit(void){ i2c_del_driver(&at24_driver);}module_exit(at24_exit);
module_init(at24_init);
static struct i2c_driver at24_driver = { .driver = { .name = "at24", .owner = THIS_MODULE, .bus=&i2c_bus_type }, .probe = at24_probe, .remove = at24_remove, .id_table = at24_ids,};
i2c_driver
driver
name
owner
bus
probe
remove
id_table
#define i2c_add_driver(driver) \ i2c_register_driver(THIS_MODULE, driver)
nt 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; /* When registration returns, the driver core * will have called probe() for all matching-but-unbound devices. */ res = driver_register(&driver->driver); if (res) return res; pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name); INIT_LIST_HEAD(&driver->clients); /* Walk the adapters that are already present */ i2c_for_each_dev(driver, __process_new_driver); return 0;}
struct bus_type i2c_bus_type = { .name = "i2c", .match = i2c_device_match, .probe = i2c_device_probe, .remove = i2c_device_remove, .shutdown = i2c_device_shutdown,};
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->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); if (ret) return ret; ret = driver_add_groups(drv, drv->groups); if (ret) { bus_remove_driver(drv); return ret; } kobject_uevent(&drv->p->kobj, KOBJ_ADD); return ret;}
driver_find 会执行 从I2c总线上查找同名设备
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); 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) { error = driver_attach(drv); 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); kfree(drv->p); drv->p = NULL;out_put_bus: bus_put(bus); return error;}
kobject_init_and_add 比较重要
这个新的priv结构体 和driver就是一一对应的关系
drv->name="at24"
struct driver_private { struct kobject kobj; struct klist klist_devices; struct klist_node knode_bus; struct module_kobject *mkobj; struct device_driver *driver;};
bus_add_driver 新建一个内存结点
static struct i2c_driver at24_driver = { .driver = { .name = "at24", .owner = THIS_MODULE, .bus=&i2c_bus_type }, .probe = at24_probe, .remove = at24_remove, .id_table = at24_ids, .p= ...};
复制的左边
kobject_init_and_add
创建 sys/bus/i2c/at24
这张图中的链表是 i2c bus 下的kset。kset、kobject、parent和list,在权威书籍LDD3-chapter14(linux设备驱动)中有一个很经典的图
int driver_attach(struct device_driver *drv){ return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);}
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; klist_iter_init_node(&bus->klist_devices, &i, (start ? &start->knode_bus : NULL)); while ((dev = next_device(&i)) && !error) error = fn(dev, data); klist_iter_exit(&i); return error;}
static int __driver_attach(struct device *dev, void *data){ struct device_driver *drv = data; if (!driver_match_device(drv, dev)) return 0; if (dev->parent) /* Needed for USB */ device_lock(dev->parent); device_lock(dev); if (!dev->driver) driver_probe_device(drv, dev); device_unlock(dev); if (dev->parent) device_unlock(dev->parent); return 0;}
判断设备和驱动是否匹配
设备是什么时候加入到总线上的?
匹配成功的条件是什么?