查看注册虚拟 platform 和 I2c 驱动共同点
/**
* platform_driver_register
* @drv: platform driver structure
*/
int platform_driver_register(struct platform_driver *drv)
{
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;
if (drv->suspend)
drv->driver.suspend = platform_drv_suspend;
if (drv->resume)
drv->driver.resume = platform_drv_resume;
return driver_register(&drv->driver);
}
EXPORT_SYMBOL_GPL(platform_driver_register);
/* ------------------------------------------------------------------------- */
/*
* 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. There
* are two models for binding the driver to its device: "new style" drivers
* follow the standard Linux driver model and just respond to probe() calls
* issued if the driver core sees they match(); "legacy" drivers create device
* nodes themselves.
*/
int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
{
int res;
/* new style driver methods can't mix with legacy ones */
if (is_newstyle_driver(driver)) {
if (driver->attach_adapter || driver->detach_adapter
|| driver->detach_client) {
printk(KERN_WARNING
"i2c-core: driver [%s] is confused\n",
driver->driver.name);
return -EINVAL;
}
}
/* add the driver to the list of i2c drivers in the driver core */
driver->driver.owner = owner;
driver->driver.bus = &i2c_bus_type;
/* for new style drivers, 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;
mutex_lock(&core_lists);
list_add_tail(&driver->list,&drivers);
pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
/* legacy drivers scan i2c busses directly */
if (driver->attach_adapter) {
struct i2c_adapter *adapter;
list_for_each_entry(adapter, &adapters, list) {
driver->attach_adapter(adapter);
}
}
mutex_unlock(&core_lists);
return 0;
}
EXPORT_SYMBOL(i2c_register_driver);
由上可得
driver->driver.bus = &i2c_bus_type;
和
res = driver_register(&driver->driver);
int driver_register(struct device_driver * drv)
{
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);
}
klist_init(&drv->klist_devices, NULL, NULL);
return bus_add_driver(drv);
}
void klist_init(struct klist * k, void (*get)(struct klist_node *),
void (*put)(struct klist_node *))
{
INIT_LIST_HEAD(&k->k_list);//初始化头节点
spin_lock_init(&k->k_lock);//初始化自旋锁
k->get = get;
k->put = put;
}
/**
1. bus_add_driver - Add a driver to the bus.
2. @drv: driver.
3. */
int bus_add_driver(struct device_driver *drv)
{
struct bus_type * bus = get_bus(drv->bus);
int error = 0;
if (!bus)
return -EINVAL;
pr_debug("bus %s: add driver %s\n", bus->name, drv->name);
error = kobject_set_name(&drv->kobj, "%s", drv->name);
if (error)
goto out_put_bus;
drv->kobj.kset = &bus->drivers;
if ((error = kobject_register(&drv->kobj)))
goto out_put_bus;
if (drv->bus->drivers_autoprobe) {
error = driver_attach(drv);
if (error)
goto out_unregister;
}
klist_add_tail(&drv->knode_bus, &bus->klist_drivers);
module_add_driver(drv->owner, drv);
error = driver_add_attrs(bus, drv);
if (error) {
/* How the hell do we get out of this pickle? Give up */
printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",
__FUNCTION__, drv->name);
}
error = add_bind_files(drv);
if (error) {
/* Ditto */
printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
__FUNCTION__, drv->name);
}
return error;
out_unregister:
kobject_unregister(&drv->kobj);
out_put_bus:
put_bus(bus);
return error;
}
int bus_add_driver(struct device_driver *drv)
|---> bus_get/*获取总线类型(bus_type)*/
|--->driver_attach //调用该函数,那么drv驱动程序会和drv所在总线上连接了的物理设备进行一一匹配
|--->module_add_driver //添加drv的module
|--->driver_add_attrs//加入driver目录下
|--->add_bind_files //add_bind_files()函数(实际上是由add_bind_files()函数调用driver_create_file()函数)在sys文件系统下为其创建一个新的目录。
driver_attach
查看
driver_attach()函数 分析
可以学习到的函数
platform_driver_register
driver_register // driver->driver.bus = &i2c_bus_type; 被 driver_register 需要
INIT_LIST_HEAD(&k->k_list);//初始化头节点
spin_lock_init(&k->k_lock);//初始化自旋锁
int bus_add_driver(struct device_driver *drv)
|---> bus_get/*获取总线类型(bus_type)*/
|--->driver_attach //调用该函数,那么drv驱动程序会和drv所在总线上连接了的物理设备进行一一匹配
|--->module_add_driver //添加drv的module
|--->driver_add_attrs//加入driver目录下
|--->add_bind_files //add_bind_files()函数(实际上是由add_bind_files()函数调用driver_create_file()函数)在sys文件系统下为其创建一个新的目录。