v4l2_i2c_new_subdev_board接口分析(侧重I2C设备的探测)

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

你可能感兴趣的:(c,function,struct,Module,null,callback)