四、注册 i2c_driver

来源:互联网 发布:正则表达式邮箱匹配php 编辑:程序博客网 时间:2024/04/29 16:21

前三步跟平台相关,从这里开始就只与具体的设备驱动相关了,这里我选取FLD00060光距感的驱动进行说明。

 

// 3rdparty/lsensor/fld60/special/driver/FLD60.c

static int __init fld60_pls_init(void)

{

       int temp=0;

       printk("baker :%s\n",__func__);

       fld60_pls_config_pins();

       printk("after baker :%s\n",__func__);

       temp = i2c_add_driver(&fld60_pls_driver);

       printk("add driver result = %d--\n",temp);

       return temp;

}

 

//kernel/include/linux/i2c.h

static inline int i2c_add_driver(struct i2c_driver *driver)

{

       return i2c_register_driver(THIS_MODULE, driver);

}

 

 

/*

 * An i2c_driver is used with one or morei2c_client (device) nodes to access

 * i2c slave chips, on a bus instanceassociated with some i2c_adapter.

 */

//kernel/drivers/i2c/i2c-core.c

int i2c_register_driver(struct module *owner, struct i2c_driver*driver)

{

       int res;

 

       /* Can't register until after drivermodel init */

       if (unlikely(WARN_ON(!i2c_bus_type.p)))

              return -EAGAIN;

 

       /* add the driver to the list of i2cdrivers in the driver core */

       driver->driver.owner = owner;

       driver->driver.bus =&i2c_bus_type;

 

       /* Whenregistration returns, the driver core

        * will have called probe() for allmatching-but-unbound devices.

        */

      //i2c_driver结构体中的driver变量是个device_driver类型的结构体

       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 alreadypresent */

       mutex_lock(&core_lock);

       bus_for_each_dev(&i2c_bus_type, NULL,driver, __process_new_driver);

       mutex_unlock(&core_lock);

 

       return 0;

}

 

 

/**

 * driver_register - register driver with bus

 * @drv: driver to register

 *

 * We pass off most of the work to thebus_add_driver() call,

 * since most of the things we have to do dealwith the bus

 * structures.

 */

//kernel/drivers/base/driver.c

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_typemethods\n", drv->name);

 

       other = driver_find(drv->name,drv->bus);

       if (other) {

              put_driver(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;

}

 

 

/**

 * bus_add_driver - Add a driver to the bus.

 * @drv: driver.

 */

//kernel/drivers/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);

       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;

 

       if(drv->bus->p->drivers_autoprobe) {

              error = driver_attach(drv);

              if (error)

                     goto out_unregister;

       }

  

       klist_add_tail(&priv->knode_bus,&bus->p->klist_drivers);

       module_add_driver(drv->owner, drv);

 

       error = driver_create_file(drv,&driver_attr_uevent);

       if (error) {

              printk(KERN_ERR "%s: ueventattr (%s) failed\n",

                     __func__, drv->name);

       }

    //如果有 driver client 匹配,就把 driver添加到总线中。

       error = driver_add_attrs(bus, drv);

       if (error) {

              /* How the hell do we get out ofthis pickle? Give up */

              printk(KERN_ERR "%s:driver_add_attrs(%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);

              }

       }

 

       kobject_uevent(&priv->kobj,KOBJ_ADD);

       return 0;

 

out_unregister:

       kobject_put(&priv->kobj);

       kfree(drv->p);

       drv->p = NULL;

out_put_bus:

       bus_put(bus);

       return error;

}

 

 

/**

 * driver_attach - try to bind driver todevices.

 * @drv: driver.

 *

 * Walk the list of devices that the bus has onit 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.

 */

//kernel/drivers/base/dd.c

intdriver_attach(structdevice_driver *drv)

{

       return bus_for_each_dev(drv->bus,NULL, drv, __driver_attach);

}

 

 

//kernel/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;

}

先执行 driver_match_device,当clientdriver匹配时,再调用driver_probe_device。下面我们先看看driver_match_device

 

//kernel/drivers/base/base.h

static inline int driver_match_device(struct device_driver *drv,

                                  struct device *dev)

{

       return drv->bus->match ?drv->bus->match(dev, drv) : 1;

   //drv就是i2c_driver->driver,i2c_driver->driver->bus->match函数存在时,就调用该函数,否则返回1

}

 

 

 

还记得在i2c_register_driver中对i2c_driver->driver->bus的初始化吗?

//kernel/drivers/i2c/i2c-core.c

int i2c_register_driver(structmodule *owner, struct i2c_driver *driver)

{

       … …

       driver->driver.bus =&i2c_bus_type;

       … …

 

}

 

//kernel/drivers/i2c/i2c-core.c

struct bus_type i2c_bus_type = {

       .name           ="i2c",

       .match         = i2c_device_match,

       .probe           =i2c_device_probe,

       .remove        =i2c_device_remove,

       .shutdown     =i2c_device_shutdown,

       .pm        =&i2c_device_pm_ops,

};


 

//kernel/drivers/i2c/i2c-core.c

static inti2c_device_match(structdevice *dev, struct device_driver *drv)

{

       struct i2c_client  *client = i2c_verify_client(dev);

       struct i2c_driver *driver;

       if (!client)

              return 0;

       driver = to_i2c_driver(drv);

       /* match on an id table if there is one*/

       if (driver->id_table)

              return i2c_match_id(driver->id_table, client) != NULL;

 

       return 0;

}

 

 

//kernel/drivers/i2c/i2c-core.c

static conststruct i2c_device_id *i2c_match_id(const struct i2c_device_id *id,

                                          conststruct i2c_client *client)

{

       while (id->name[0]) {

       //比较项为 client->name i2c_driver->id_table->name,因此 client的注册要在 driver之前,要不然这里将无法比较

              if (strcmp(client->name,id->name) == 0)

                     return id;

              id++;

       }

       return NULL;

}




driver_match_device完了后,接下来我们再看看 driver_probe_device

/**//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 deviceis not registered,

 * 1 if the device is bound successfully and 0otherwise.

 *

 * This function must be called with @dev lockheld.  When called for a

 * USB interface, @dev->parent lock must beheld as well.

 */

//kernel/drivers/base/dd.c

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: matcheddevice %s with driver %s\n",

               drv->bus->name, __func__, dev_name(dev),drv->name);

 

       pm_runtime_get_noresume(dev);

       pm_runtime_barrier(dev);

       ret = really_probe(dev, drv);

       pm_runtime_put_sync(dev);

 

       return ret;

}

 

 

//kernel/drivers/base/dd.c

static int really_probe(struct device *dev, struct device_driver*drv)

{

       int ret = 0;

 

       atomic_inc(&probe_count);

       pr_debug("bus: '%s': %s: probingdriver %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 (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) {

       //如果总线存在probe函数存在,先调用该probe函数

       //这里dev->busdrv->bus是一样的吗?由drv.bus=&i2c_bus_type以及dev->driver=drv知,这里的dev是不是要换成dev->driver?

              ret = dev->bus->probe(dev);

              if (ret)

                     goto probe_failed;

       } else if (drv->probe) {

       //否则调用i2c_driver->device_driver->probe函数

              ret = drv->probe(dev);

              if (ret)

                     goto probe_failed;

       }

 

       driver_bound(dev);

       ret = 1;

       pr_debug("bus: '%s': %s: bounddevice %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;

 

       if (ret != -ENODEV && ret !=-ENXIO) {

              /* driver matched but the probefailed */

              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;

}

 


//kernel/drivers/i2c/i2c-core.c

int i2c_register_driver(structmodule *owner, struct i2c_driver *driver)

{

       … …

       driver->driver.bus= &i2c_bus_type;

       … …

}

 

 

//kernel/drivers/i2c/i2c-core.c

struct bus_type i2c_bus_type = {

       .name           ="i2c",

       .match          =i2c_device_match,

       .probe    = i2c_device_probe,

       .remove        =i2c_device_remove,

       .shutdown     =i2c_device_shutdown,

       .pm        =&i2c_device_pm_ops,

};

 

//kernel/drivers/i2c/i2c-core.c

static inti2c_device_probe(structdevice *dev)

{

       struct i2c_client  *client = i2c_verify_client(dev);

       struct i2c_driver *driver;

       int status;

 

       if (!client)

              return 0;

 

   //really_probe函数可知,dev->driver = drv,因此dev->driver实际就是i2c_driver->device_driver

   //利用to_i2c_driverdevice_driver转换成了i2c_driver

       driver =to_i2c_driver(dev->driver);

       if (!driver->probe ||!driver->id_table)

              return -ENODEV;

       client->driver = driver;

       if(!device_can_wakeup(&client->dev))

              device_init_wakeup(&client->dev,

                                   client->flags& I2C_CLIENT_WAKE);

       dev_dbg(dev, "probe\n");

 

       status = driver->probe(client, i2c_match_id(driver->id_table,client));

       if (status) {

              client->driver = NULL;

              i2c_set_clientdata(client, NULL);

       }

       return status;

}

 

 

// 3rdparty/lsensor/fld60/special/driver/FLD60.c

static structi2c_driver fld60_pls_driver = {

    .driver = {

        .owner = THIS_MODULE,

        .name = FLD60_PLS_DEVICE,

    },

       .probe      = fld60_pls_probe,

       .remove     = fld60_pls_remove,

       .id_table = fld60_pls_id,

};