我們知道,當我們註冊soc_camera host時,會通過搜索鏈表devices來尋找需要安裝到該host上的soc camera device(這就意味着soc camera device的初始化必須要早於soc camera host),當有需要安裝到該host上的設備時,我們就註冊該soc camera device,根據總線,設備,驅動模型,這時就會調用soc_camera_probe函數,下面再次詳細分析一下soc camera probe函數。
static int soc_camera_probe(struct device *dev)
{
struct soc_camera_device *icd = to_soc_camera_dev(dev);
struct soc_camera_host *ici = to_soc_camera_host(dev->parent);
struct soc_camera_link *icl = to_soc_camera_link(icd);
struct device *control = NULL;
int ret;
ret = ici->ops->add(icd);
if (ret < 0)
goto eadd;
ret = soc_camera_power_set(icd, icl, 1);
if (ret < 0)
goto epower;
/* The camera could have been already on, try to reset */
if (icl->reset)
icl->reset(icd->pdev);
/* Must have icd->vdev before registering the device */
ret = video_dev_create(icd);
if (ret < 0)
goto evdc;
/* Non-i2c cameras, e.g., soc_camera_platform, have no board_info */
if (icl->board_info) {
ret = soc_camera_init_i2c(icd, icl);
if (ret < 0)
goto eadddev;
} else if (!icl->add_device || !icl->del_device) {
ret = -EINVAL;
goto eadddev;
} else {
if (icl->module_name)
ret = request_module(icl->module_name);
ret = icl->add_device(icl, &icd->dev);
if (ret < 0)
goto eadddev;
/*
* FIXME: this is racy, have to use driver-binding notification,
* when it is available
*/
control = to_soc_camera_control(icd);
if (!control || !control->driver || !dev_get_drvdata(control) ||
!try_module_get(control->driver->owner)) {
icl->del_device(icl);
goto enodrv;
}
}
/* At this point client .probe() should have run already */
ret = soc_camera_init_user_formats(icd);
if (ret < 0)
goto eiufmt;
icd->field = V4L2_FIELD_ANY;
icd->vdev->lock = &icd->video_lock;
/*
* ..._video_start() will create a device node, video_register_device()
* itself is protected against concurrent open() calls, but we also have
* to protect our data.
*/
mutex_lock(&icd->video_lock);
ret = soc_camera_video_start(icd);
if (ret < 0)
goto evidstart;
/* Do we have to sysfs_remove_link() before device_unregister()? */
if (sysfs_create_link(&icd->dev.kobj, &to_soc_camera_control(icd)->kobj,
"control"))
dev_warn(&icd->dev, "Failed creating the control symlink\n");
ici->ops->remove(icd);
soc_camera_power_set(icd, icl, 0);
mutex_unlock(&icd->video_lock);
return 0;
evidstart:
mutex_unlock(&icd->video_lock);
soc_camera_free_user_formats(icd);
eiufmt:
if (icl->board_info) {
soc_camera_free_i2c(icd);
} else {
icl->del_device(icl);
module_put(control->driver->owner);
}
enodrv:
eadddev:
video_device_release(icd->vdev);
evdc:
soc_camera_power_set(icd, icl, 0);
epower:
ici->ops->remove(icd);
eadd:
return ret;
}
我們着重分析一下ret =soc_camera_init_i2c(icd, icl);的過程。首先貼出soc_camera_init_i2c的代碼。
static int soc_camera_init_i2c(structsoc_camera_device *icd,
struct soc_camera_link *icl)
{
structi2c_client *client;
structsoc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct i2c_adapter *adap =i2c_get_adapter(icl->i2c_adapter_id);通過icl傳入的adapter_id來獲取i2c adapter適配器。
structv4l2_subdev *subdev;
if(!adap) {
dev_err(&icd->dev,"Cannot get I2C adapter #%d. No driver?\n",
icl->i2c_adapter_id);
goto ei2cga;
}
icl->board_info->platform_data = icd;//這裏很重要哦,是爲了建立icd和i2c client之間的聯繫。
subdev =v4l2_i2c_new_subdev_board(&ici->v4l2_dev, adap,
icl->board_info,NULL);//重點分析該代碼
if(!subdev)
gotoei2cnd;
client= v4l2_get_subdevdata(subdev);
/*Use to_i2c_client(dev) to recover the i2c client */
dev_set_drvdata(&icd->dev,&client->dev);
return0;
ei2cnd:
i2c_put_adapter(adap);
ei2cga:
return-ENODEV;
}
我們來貼出v4l2_i2c_new_subdev_board的源碼。struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev,
struct i2c_adapter *adapter, struct i2c_board_info *info,
const unsigned short *probe_addrs)
{
struct v4l2_subdev *sd = NULL;
struct i2c_client *client;
BUG_ON(!v4l2_dev);
request_module(I2C_MODULE_PREFIX "%s", info->type);
/* Create the i2c client */
......
client = i2c_new_device(adapter, info); //初始化一個i2c client,我們來分析一下該函數的行爲。
【
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); //爲client申請分配內存。
if (!client)
return NULL;
client->adapter = adap;
client->dev.platform_data = info->platform_data;//還記得之前icl->board_info->platform_data = icd嗎,這裏就是將client->dev.platform_data指向icd,那麼這裏究竟是爲了什麼這樣做呢,是爲了在image capture驅動中獲取到icd,下面會就具體驅動實例分析。
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 validity */
status = i2c_check_client_addr_validity(client);//檢查i2c地址是否可用。
if (status) {
dev_err(&adap->dev, "Invalid %d-bit I2C address 0x%02hx\n",
client->flags & I2C_CLIENT_TEN ? 10 : 7, client->addr);
goto out_err_silent;
}
/* Check for address business */
status = i2c_check_addr_busy(adap, client->addr);//檢查地址是否已經被佔用。
if (status)
goto out_err;
client->dev.parent = &client->adapter->dev;
client->dev.bus = &i2c_bus_type;
client->dev.type = &i2c_client_type;
client->dev.of_node = info->of_node;
dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap),
client->addr);
status = device_register(&client->dev); //這裏註冊i2c client,根據總線,設備,驅動模型,我們可以知道,此時會觸發對應的i2c driver(根據name 來match),這時就會調用image capture的驅動探測函數(probe函數。)
if (status)
goto out_err;
dev_dbg(&adap->dev, "client [%s] registered with bus id %s\n",
client->name, dev_name(&client->dev));
return client;
out_err:
dev_err(&adap->dev, "Failed to register i2c client %s at 0x%02x "
"(%d)\n", client->name, client->addr, status);
out_err_silent:
kfree(client);
return NULL;
】
......
sd = i2c_get_clientdata(client);//我們知道在image capture驅動中,已經建立了client和subdev之間的聯繫,因此可以通過i2c_get_clientdata來獲取到subdev。
/* 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);
error:
/* If we have a client but no subdev, then something went wrong and
we must unregister the client. */
if (client && sd == NULL)
i2c_unregister_device(client);
return sd;
}
下面我就mt9m001.c來分析一下image capture的probe函數
static int mt9m001_probe(struct i2c_client *client,
const struct i2c_device_id *did)
{
struct mt9m001 *mt9m001;
struct soc_camera_device *icd = client->dev.platform_data; //通過platform_data獲取icd。
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); //通過client->dev.parent獲取adapter,這裏源於初始化client時(client->dev.parent = &client->adapter->dev;)
struct soc_camera_link *icl;
int ret;
if (!icd) {
dev_err(&client->dev, "MT9M001: missing soc-camera data!\n");
return -EINVAL;
}
icl = to_soc_camera_link(icd);
if (!icl) {
dev_err(&client->dev, "MT9M001 driver needs platform data\n");
return -EINVAL;
}
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
dev_warn(&adapter->dev,
"I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
return -EIO;
}
mt9m001 = kzalloc(sizeof(struct mt9m001), GFP_KERNEL);
if (!mt9m001)
return -ENOMEM;
v4l2_i2c_subdev_init(&mt9m001->subdev, client, &mt9m001_subdev_ops);//這個是個有趣且有伏筆的地方,我們來展開代碼分析:
【
void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client,
const struct v4l2_subdev_ops *ops)
{
v4l2_subdev_init(sd, ops);//初始化subdev,並且將其ops指針指向ops.
sd->flags |= V4L2_SUBDEV_FL_IS_I2C;
/* the owner is the same as the i2c_client's driver owner */
sd->owner = client->driver->driver.owner;
/* i2c_client and v4l2_subdev point to one another */
v4l2_set_subdevdata(sd, client); //使得 sd->dev_priv = client
i2c_set_clientdata(client, sd);//使得client->dev->p->driver_data=sd
通過以上兩行代碼,建立了subdev與i2c client直接的聯繫。
/* initialize name */
snprintf(sd->name, sizeof(sd->name), "%s %d-%04x",
client->driver->driver.name, i2c_adapter_id(client->adapter),
client->addr);
}
】
/* Second stage probe - when a capture adapter is there */
icd->ops = &mt9m001_ops;//icd的回調函數集,由image capture驅動來實現。
.......
}