Linux 驱动注册流程

Linux设备管理模型将device、driver以链表的形式绑定在总线Bus上,向总线注册一个驱动时会去匹配相应设备,这里梳理下一个驱动注册的流程:

1.驱动模块初始化函数module_init()被调用流程:

start_kernel();
rest_init();
kernel_init();
kernel_init_freeable();
do_basic_setup();
do_initcalls();//
do_initcall_level();
.....
module_init();

2.以I2C设备为例,modul_init()会调用你自己的初始化函数:

static struct i2c_driver your_driver = {  
    .driver = {  
        .owner  = THIS_MODULE,  
        .name   = YOUR_DRIVER_NAME_UP,  
        .of_match_table = your_driver_of_match,  
    },  
    .probe    = your_probe_func,  
    .remove  = your_i2c_drv_remove,  
    .id_table   = your_i2c_drv_id_table,  
    //.suspend  = your_i2c_drv_suspend,  
    //.resume      = your_i2c_drv_resume,  
};  
static int __int your_init_func(void)  
{  
    …
    i2c_add_driver(&your_i2c_driver);  
    …
}  
modul_init(your_init_func);  

3.注册驱动流程:

i2c_register_driver()
driver_register()
bus_add_driver()
driver_attach()
bus_for_each_dev()
__driver_attach (for your device)
driver_probe_device()
really_probe()
i2c_device_probe (this is what dev->bus->probe is for an i2c driver)
your_probe_func()

4.以下分析具体函数:

(1)i2c_register_driver():                                                                                                               位置:drivers/i2c/i2c-core.c

int i2c_register_driver(struct module *owner, struct i2c_driver *driver)  
{  
    int res;  
  
    /* Can't register until after driver model init */  
    if (WARN_ON(!is_registered)) {  
        printk("unlikely(WARN_ON(!i2c_bus_type.p and return -EAGAIN.\n");  
        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;      //赋值bus type  
    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);  // 这里进入
    if (res){  
        printk("driver_register return res : %d\n", res);  
        return res;  
    }  
    
    pr_debug("driver [%s] registered\n", driver->driver.name);     
  
    /* iWalk the adapters that are already present */  
    i2c_for_each_dev(driver, __process_new_driver);  
  
    return 0;  
}  
 
type定义如下:
struct bus_type i2c_bus_type = {  
    .name       = "i2c",  
    .match      = i2c_device_match,  
    .probe      = i2c_device_probe, 
    .remove     = i2c_device_remove,  
    .shutdown   = i2c_device_shutdown,  
};  

(2)driver_register把驱动注册到总线:                                                                                           位置:drivers/base/driver.c

/**
 * 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.
 */
int driver_register(struct device_driver *drv)
{
......
	if ((drv->bus->probe && drv->probe) ||
	    (drv->bus->remove && drv->remove) ||
	    (drv->bus->shutdown && drv->shutdown))
 
	ret = bus_add_driver(drv);     //把drv驱动,注册到总线
.......
}

(3)驱动注册到总线的实现函数:                                                                                                        位置:drivers/base/bus.c

/**
 * bus_add_driver - Add a driver to the bus.        -----在总线上加入一个驱动
 * @drv: driver.
 */
int bus_add_driver(struct device_driver *drv)
{
......
	if (drv->bus->p->drivers_autoprobe) {
		error = driver_attach(drv);      //驱动的匹配函数
......
}

(4)driver_attach():                                                                                                                             位置:drivers/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.
 */
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);

(5)bus_for_each_dev()将会遍历总线上的每个设备,并调用__driver_attach() :                            位置:drivers/base/bus.c

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)
                error = fn(dev, data);       //实际调用__driver_attach()
        klist_iter_exit(&i);
        return error;
}
EXPORT_SYMBOL_GPL(bus_for_each_dev);

(6)上面调用的是__driver_attach():                                                                                                 位置:drivers/base/dd.c

static int __driver_attach(struct device *dev, void *data)
{
	struct device_driver *drv = data;
 
	/*
	 * 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.
	 *
	 * driver_probe_device() will spit a warning if there
	 * is an error.
	 */
 
	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;
}

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);

        pm_runtime_barrier(dev);
        ret = really_probe(dev, drv);    //入口
        pm_request_idle(dev);

        return ret;
}

(7)really_probe()函数:                                                                                                                         位置:drivers/base/dd.c

static int really_probe(struct device *dev, struct device_driver *drv)
{
......
//1.驱动所属总线的probe函数:
	if (dev->bus->probe) {
		ret = dev->bus->probe(dev);
		if (ret)
			goto probe_failed;
	} 
//2.驱动中的probe函数:
	else if (drv->probe) {
		ret = drv->probe(dev);
		if (ret)
			goto probe_failed;
	}
 
	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;
......
}

(8)i2c_device_probe()里将调用your_probe_func():                                                                        位置:driver/i2c/i2c-core.c

static int i2c_device_probe(struct device *dev)
{
        struct i2c_client       *client = i2c_verify_client(dev);
        struct i2c_driver       *driver;
        int status;

        if (!client)
                return 0;

        if (!client->irq && dev->of_node) {
                int irq = of_irq_get(dev->of_node, 0);

                if (irq == -EPROBE_DEFER)
                        return irq;
                if (irq < 0)
                        irq = 0;

                client->irq = irq;
        }

        driver = to_i2c_driver(dev->driver);
        if (!driver->probe || !driver->id_table)
                return -ENODEV;

        if (!device_can_wakeup(&client->dev))
                device_init_wakeup(&client->dev,
                                        client->flags & I2C_CLIENT_WAKE);
        dev_dbg(dev, "probe\n");

        status = of_clk_set_defaults(dev->of_node, false);
        if (status < 0)
                return status;

        status = dev_pm_domain_attach(&client->dev, true);
        if (status != -EPROBE_DEFER) {
                status = driver->probe(client, i2c_match_id(driver->id_table,
                                        client));  //调用你自己的probe函数
                if (status)
                        dev_pm_domain_detach(&client->dev, true);
        }

        return status;
}

(9)至此,就调用到你自己在驱动里边实现的your_probe_func()了

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值