驱动加载到I2C总线,如何运行到probe

为了简短文章长度,一些检查和调试信息被删除

1. 在xxx_init()中会调用i2c_add_driver()函数   

static int __init ltr559_init(void)
{
    return i2c_add_driver(&ltr_ps_driver);//ltr_ps_driver是一个struct i2c_driver
} 

static void __exit ltr559_exit(void)
{
    i2c_del_driver(&ltr_ps_driver);    
}

module_init(ltr559_init);
module_exit(ltr559_exit);

2. i2c_add_driver

        是一个宏命令,调用 i2c_register_driver

/*************************  include/linux/i2c.h  *******************************/
#define i2c_add_driver(driver) \
         i2c_register_driver(THIS_MODULE, driver)

3.  i2c_register_driver

     在一些 i2c_adapter 相关总线实例, 一个 i2c_driver 可以被一个或多个 i2c_client 设备节点使用去访问 i2c_slave_chip

     该函数

/**********************  kernel/drivers/i2c/i2c_core.c   ************************/
int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
{
	int res;

	/*在驱动模块初始化完成后才可以注册 */
	if (unlikely(WARN_ON(!i2c_bus_type.p)))
		return -EAGAIN;

	/* 添加该驱动到i2c驱动链表上 */
	driver->driver.owner = owner;
 	driver->driver.bus = &i2c_bus_type;

	/* 当注册完成,驱动代码将调用probe()去匹配设备 */
	res = driver_register(&driver->driver);

	INIT_LIST_HEAD(&driver->clients);

	i2c_for_each_dev(driver, __process_new_driver);

	return 0;
}

4. driver_register

    主要的工作还是由 bus_add_driver 来操作

/***************************    kernel/driver/base/driver.c  **************************/
int driver_register(struct device_driver *drv)
{
	int ret;
	struct device_driver *other;

	BUG_ON(!drv->bus->p);
	
	other = driver_find(drv->name, drv->bus);//通过driver_name在bus上查找该driver,正常返回0
	
	ret = bus_add_driver(drv); //主要
	
	ret = driver_add_groups(drv, drv->groups);
	if (ret) {
		bus_remove_driver(drv);
		return ret;
	}
	kobject_uevent(&drv->p->kobj, KOBJ_ADD);

	return ret;
}

5. bus_add_driver


/****************  kernel/driver/base/bus.c **********************************/
int bus_add_driver(struct device_driver *drv)
{
    struct bus_type *bus;
    struct driver_private *priv;
    int error = 0;

    bus = bus_get(drv->bus);   

    priv = kzalloc(sizeof(*priv), GFP_KERNEL);
 
    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);
   
    klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
    if (drv->bus->p->drivers_autoprobe) {
        error = driver_attach(drv);  //尝试绑定
        
    }
    module_add_driver(drv->owner, drv);

    error = driver_create_file(drv, &driver_attr_uevent); //为驱动创建文件,继续调用sysfs_create_file()
    
    error = driver_add_attrs(bus, drv);
    
    if (!drv->suppress_bind_attrs) {
        error = add_bind_files(drv);
        
    }

    return 0;
}

6. driver_attach


/**
 * 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);
}

7. bus_for_each_dev

     参数 fn 就是__driver_attach()函数

/**
 * 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. 
 */
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);
	klist_iter_exit(&i);
	return error;
}

8. __driver_attach


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)	/* 如果是被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;
}

9. driver_probe_device

    如果设备没有注册,则该函数返回 -ENODEV , probe 成功 返回 1 ,失败 返回 0 。该函数被调用时,设备一定要上锁

/**********************  kernel/drivers/base/dd.c *********************************
 * 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
 */
int driver_probe_device(struct device_driver *drv, struct device *dev)
{
	int ret = 0;

	if (!device_is_registered(dev))  //判断设备是否注册
		return -ENODEV;
	pm_runtime_barrier(dev);
 	ret = really_probe(dev, drv);
	pm_request_idle(dev);

	return ret;
}

10. really_probe

/**********************  kernel/drivers/base/dd.c *********************************/
static int really_probe(struct device *dev, struct device_driver *drv)
{
	int ret = 0;

	atomic_inc(&probe_count);

	WARN_ON(!list_empty(&dev->devres_head));

	dev->driver = drv;


	ret = pinctrl_bind_pins(dev);
	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->bus->probe) {
		ret = dev->bus->probe(dev);
		if (ret)
			goto probe_failed;
	} else if (drv->probe) {
		ret = drv->probe(dev); //这里才是正在调用驱动中实现的probe函数
		if (ret)
			goto probe_failed;
	}

	driver_bound(dev);
	ret = 1;	
	goto done;

probe_failed:
	devres_release_all(dev);
	driver_sysfs_remove(dev);
	dev->driver = NULL;
	dev_set_drvdata(dev, NULL);

	if (ret == -EPROBE_DEFER) {
		/* Driver requested deferred probing */
		dev_info(dev, "Driver %s requests probe deferral\n", drv->name);
		driver_deferred_probe_add(dev);
	} else if (ret != -ENODEV && ret != -ENXIO) {
		/* driver matched but the probe failed */
		printk(KERN_WARNING
		       "%s: probe of %s failed with error %d\n",
		       drv->name, dev_name(dev), ret);
	} else {
		pr_debug("%s: probe of %s rejects match %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;
}

 



    











































评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值