- V4L2中增加I2C设备接口:v4l2_i2c_new_subdev_board接口分析
- struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev,
- struct i2c_adapter *adapter, const char *module_name,
- struct i2c_board_info *info, const unsigned short *probe_addrs)
- {
- ........
- if (module_name)
- request_module(module_name); //加载I2C驱动模块
- /* Create the i2c client */
- if (info->addr == 0 && probe_addrs)
- client = i2c_new_probed_device(adapter, info, probe_addrs);
- else
- client = i2c_new_device(adapter, info); //在此接口中会增加sysfs,会把驱动和设备关联起来,并会调用于I2C驱动中的probe接口
- /* Note: by loading the module first we are certain that c->driver
- will be set if the driver was found. If the module was not loaded
- first, then the i2c core tries to delay-load the module for us,
- and then c->driver is still NULL until the module is finally
- loaded. This delay-load mechanism doesn't work if other drivers
- want to use the i2c device, so explicitly loading the module
- is the best alternative. */
- if (client == NULL || client->driver == NULL)
- goto error;
- /* Lock the module so we can safely get the v4l2_subdev pointer */
- if (!try_module_get(client->driver->driver.owner))
- goto error;
- sd = i2c_get_clientdata(client);//获取I2C驱动中的结构变量
- /* Register with the v4l2_device which increases the module's
- use count as well. */
- if (v4l2_device_register_subdev(v4l2_dev, sd))//
- sd = NULL;
- /* Decrease the module use count to match the first try_module_get. */
- module_put(client->driver->driver.owner);
- if (sd) {
- /* We return errors from v4l2_subdev_call only if we have the
- callback as the .s_config is not mandatory */
- int err = v4l2_subdev_call(sd, core, s_config,
- info->irq, info->platform_data); //调用I2C驱动中定义的接口,来配置I2C CAMERA。
- if (err && err != -ENOIOCTLCMD) {
- v4l2_device_unregister_subdev(sd);
- sd = NULL;
- }
- }
- .............
- return sd;
- }
- struct i2c_client *
- i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
- {
- struct i2c_client *client;
- int status;
- client = kzalloc(sizeof *client, GFP_KERNEL); //为新的I2C client分配空间
- if (!client)
- return NULL;
- client->adapter = adap;
- client->dev.platform_data = info->platform_data;
- if (info->archdata)
- client->dev.archdata = *info->archdata;
- client->flags = info->flags;
- client->addr = info->addr;
- client->irq = info->irq;
- strlcpy(client->name, info->type, sizeof(client->name));
- /* Check for address business */
- status = i2c_check_addr(adap, client->addr); //检查I2C设备是否已经加载过了
- if (status)
- goto out_err;
- client->dev.parent = &client->adapter->dev;
- client->dev.bus = &i2c_bus_type; //注册I2C总线处理回调函数,如果探测到设备后会调用于其中的接口
- client->dev.type = &i2c_client_type; //注册引sysfs有关的接口
- dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap),
- client->addr);
- status = device_register(&client->dev);//注册I2C设备
- if (status)
- goto out_err;
- dev_dbg(&adap->dev, "client [%s] registered with bus id %s/n",
- client->name, dev_name(&client->dev));
- printk("%s , %d /n", __FUNCTION__, __LINE__);
- return client;
- out_err:
- dev_err(&adap->dev, "Failed to register i2c client %s at 0x%02x "
- "(%d)/n", client->name, client->addr, status);
- kfree(client);
- return NULL;
- }
- int device_register(struct device *dev)
- {
- device_initialize(dev); //初始化设备的相关成员
- return device_add(dev);
- }
- int device_add(struct device *dev)
- {
- ...........
- bus_probe_device(dev); //从总线上探测设备
- ...........
- }
- void bus_probe_device(struct device *dev)
- {
- struct bus_type *bus = dev->bus;
- int ret;
- if (bus && bus->p->drivers_autoprobe) {
- ret = device_attach(dev);//把驱动和设备关联起来
- WARN_ON(ret < 0);
- }
- }
- int device_attach(struct device *dev)
- {
- int ret = 0;
- down(&dev->sem);
- if (dev->driver) {
- ret = device_bind_driver(dev);
- if (ret == 0)
- ret = 1;
- else {
- dev->driver = NULL;
- ret = 0;
- }
- } else {
- pm_runtime_get_noresume(dev);
- ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach); //会调用于此
- pm_runtime_put_sync(dev);
- }
- up(&dev->sem);
- return ret;
- }
- static int __device_attach(struct device_driver *drv, void *data)
- {
- struct device *dev = data;
- if (!driver_match_device(drv, dev)) //找到驱动结构是名字匹配的设备
- return 0;
- return driver_probe_device(drv, dev);
- }
- 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_get_noresume(dev);
- pm_runtime_barrier(dev);
- ret = really_probe(dev, drv); //设备驱动中的probe
- pm_runtime_put_sync(dev);
- return ret;
- }
- static int really_probe(struct device *dev, struct device_driver *drv)
- {
- int ret = 0;
- atomic_inc(&probe_count);
- pr_debug("bus: '%s': %s: probing driver %s with device %s/n",
- drv->bus->name, __func__, drv->name, dev_name(dev));
- WARN_ON(!list_empty(&dev->devres_head));
- dev->driver = drv;
- //增加驱动在sysfs 中的文件
- if (driver_sysfs_add(dev)) {
- printk(KERN_ERR "%s: driver_sysfs_add(%s) failed/n",
- __func__, dev_name(dev));
- goto probe_failed;
- }
- //调用前面注册的总线上的probe,然后在其中会调用到驱动中的probe函数
- if (dev->bus->probe) {
- ret = dev->bus->probe(dev);
- if (ret)
- goto probe_failed;
- } 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;
- probe_failed:
- devres_release_all(dev);
- driver_sysfs_remove(dev);
- dev->driver = NULL;
- if (ret != -ENODEV && ret != -ENXIO) {
- /* driver matched but the probe failed */
- printk(KERN_WARNING
- "%s: as 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;
- }
v4l2_i2c_new_subdev_board接口分析(侧重I2C设备的探测)
最新推荐文章于 2024-05-13 16:48:12 发布