Linux下v4l2-camera子系统之soc_camera_host(三)

Linux下v4l2-camera子系统之soc_camera_host(三)
平台:君正x1000
linux kernel: 3.10
camera sensor:ov7725
上节分析了camera_device感觉并没接触到核心,那么camera_host就该完成关键代码了。
Camera_host设备

static struct resource jz_cim_resources[] = {
	[0] = {
		.flags = IORESOURCE_MEM,
		.start = CIM_IOBASE,
		.end = CIM_IOBASE + 0x10000 - 1,
	},
	[1] = {
		.flags = IORESOURCE_IRQ,
		.start = IRQ_CIM,
	}
};

struct platform_device jz_cim_device = {
	.name = "jz-cim",
	.id = 0,
	.resource = jz_cim_resources,
	.num_resources = ARRAY_SIZE(jz_cim_resources),
};

struct jz_camera_pdata mensa_camera_pdata = {
    .mclk_10khz = 2400,
    .flags = 0,
    .cam_sensor_pdata[FRONT_CAMERA_INDEX] = {
        .gpio_rst = CAMERA_SENSOR_RESET,
        .gpio_power = CAMERA_FRONT_SENSOR_PWDN,
        .gpio_en = CAMERA_VDD_EN,
    },
};
jz_device_register(&jz_cim_device, &mensa_camera_pdata);
int jz_device_register(struct platform_device *pdev,void *pdata)
{
	pdev->dev.platform_data = pdata;
	return platform_device_register(pdev);
}

这里也是把host做为平台设备注册在platform总线下。
Camera_host驱动

static struct platform_driver jz_camera_driver = {
	.remove		= __exit_p(jz_camera_remove),
	.driver		= {
		.name	= DRIVER_NAME,   /* #define DRIVER_NAME “jz-cim” */
		.owner	= THIS_MODULE,
	},
};
static int __init jz_camera_init(void) {
	return platform_driver_probe(&jz_camera_driver, jz_camera_probe);
}
struct jz_camera_dev {
	struct soc_camera_host soc_host;
	struct soc_camera_device *icd[MAX_SOC_CAM_NUM];
	struct jz_camera_pdata *pdata;
	...
	}
	
static int __init jz_camera_probe(struct platform_device *pdev) {
	struct jz_camera_dev *pcdev;
	...
	pcdev->pdata = pdev->dev.platform_data;
	pcdev->soc_host.drv_name        = DRIVER_NAME;
	pcdev->soc_host.ops             = &jz_soc_camera_host_ops;
	pcdev->soc_host.priv            = pcdev;
	/*内嵌的v4l2框架定义的设备就是该camera host平台设备 */
	pcdev->soc_host.v4l2_dev.dev    = &pdev->dev;
	pcdev->soc_host.nr              = 0; 
	pcdev->poll_flag		= 0;
	pcdev->vb_address_flag		= 0;
	err = soc_camera_host_register(&pcdev->soc_host); 
}

那么此时就又引出来一个结构体struct soc_camera_host,它内嵌struct v4l2_device,就是我们刚开始分析的,camera_host在v4l2框架中代表父设备。

/*  \include\media\soc_camera.h  */
struct soc_camera_host {
	struct v4l2_device v4l2_dev;
	struct list_head list;
	struct mutex host_lock;		/* Protect pipeline modifications */
	unsigned char nr;		/* Host number */
	u32 capabilities;
	void *priv;
	const char *drv_name;
	struct soc_camera_host_ops *ops;
};

/* \drivers\media\platform\soc_camera\soc_camera.c */
int soc_camera_host_register(struct soc_camera_host ici)
{
/
调用v4l2接口注册初始化camera host ,使之做为父设备 /
ret = v4l2_device_register(ici->v4l2_dev.dev, &ici->v4l2_dev);
/
把camera host添加到全局&hosts链表 */
list_add_tail(&ici->list, &hosts);
……
scan_add_host(ici);
}
static void scan_add_host(struct soc_camera_host *ici)
{
struct soc_camera_device *icd;

/*扫描devices全局链表, 匹配icd->iface和ici->nr, icd->iface就是soc_camera_link的bus_id,nr就是camera host平台设备描述信息的id */
list_for_each_entry(icd, &devices, list) {
if (icd->iface == ici->nr) {

/* 这就是把camera_host 做为camera_device的parent*/
icd->parent = ici->v4l2_dev.dev;
soc_camera_probe(icd);
}
}
}

/* \drivers\media\platform\soc_camera\soc_camera.c */
static int soc_camera_probe(struct soc_camera_device icd)
{
/
既然camera_host 是camera_device的parent,那么这就可以icd->parent获取camera_host */
struct soc_camera_host ici = to_soc_camera_host(icd->parent);
/
获取扳级文件里面camera_device的soc_camera_link信息 */
struct soc_camera_desc *sdesc = to_soc_camera_desc(icd);
struct soc_camera_host_desc *shd = &sdesc->host_desc;
struct soc_camera_subdev_desc *ssdd = &sdesc->subdev_desc;
struct device *control = NULL;
struct v4l2_subdev sd;
struct v4l2_mbus_framefmt mf;
……
/
v4l2_ctrl处理机制,服务于sensor驱动,是应用层对驱动的ioctl的调用 /
ret = v4l2_ctrl_handler_init(&icd->ctrl_handler, 16);
ret = video_dev_create(icd); <1> /
创建camera host的应用层的设备文件 */

if (shd->board_info) {
ret = soc_camera_init_i2c(icd, sdesc); <2>
}
sd = soc_camera_to_subdev(icd);
sd->grp_id = soc_camera_grp_id(icd);
v4l2_set_subdev_hostdata(sd, icd);
ret = v4l2_ctrl_add_handler(&icd->ctrl_handler, sd->ctrl_handler, NULL);
ret = soc_camera_init_user_formats(icd);
ret = soc_camera_video_start(icd); <3>
}
<1>标记
这其实是对v4l2框架中struct video_device的初始化,它就是向应用层生成设备节点的关键结构。

static int video_dev_create(struct soc_camera_device *icd)
{
	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
	struct video_device *vdev = video_device_alloc();
	strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name));
	vdev->parent		= icd->pdev;
	vdev->current_norm	= V4L2_STD_UNKNOWN;
	vdev->fops		= &soc_camera_fops;
	vdev->ioctl_ops		= &soc_camera_ioctl_ops;
	vdev->release		= video_device_release;
	vdev->tvnorms		= V4L2_STD_UNKNOWN;
	vdev->ctrl_handler	= &icd->ctrl_handler;
	vdev->lock		= &ici->host_lock;
	icd->vdev = vdev;
	return 0;
}

<2>标记

/* \drivers\media\platform\soc_camera\soc_camera.c  */
static int soc_camera_init_i2c(struct soc_camera_device *icd,
			       struct soc_camera_desc *sdesc)
{ 
	struct i2c_client *client;
	struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
	struct soc_camera_host_desc *shd = &sdesc->host_desc;
	struct i2c_adapter *adap = i2c_get_adapter(shd->i2c_adapter_id);
	struct v4l2_subdev *subdev;
	
	shd->board_info->platform_data = &sdesc->subdev_desc;
   //这里面就是处理i2c sensor
	subdev = v4l2_i2c_new_subdev_board(&ici->v4l2_dev, adap,shd->board_info, NULL);
	client = v4l2_get_subdevdata(subdev);
	/* Use to_i2c_client(dev) to recover the i2c client */
	icd->control = &client->dev;
	return 0;
}
/* \drivers\media\v4l2-core\v4l2-common.c */
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;
	/* Create the i2c client */
	if (info->addr == 0 && probe_addrs)
		client = i2c_new_probed_device(adapter, info, probe_addrs,	NULL);
	else
		client = i2c_new_device(adapter, info);//创建一个i2c设备
sd = i2c_get_clientdata(client);// 获取i2c sensor驱动里client的v4l2_subdev
/*  将v4l2_subdev与v4l2_device绑定,将sensor里的所有的ioctl操作添加到icd的ctrl里 */
if (v4l2_device_register_subdev(v4l2_dev, sd))
		sd = NULL;
return sd;
}

这里i2c_new_device(adapter, info)创建一个i2c设备后就会找对应的驱动匹配,匹配后就进入驱动的probe函数。等probe执行完后i2c_new_device返回,
<3>标记

/*  \drivers\media\platform\soc_camera\soc_camera.c  */
static int soc_camera_video_start(struct soc_camera_device *icd)
{ 
	const struct device_type *type = icd->vdev->dev.type;
	/* 调用v4l2框架函数,在应用层创建/dev/videox */
	ret = video_register_device(icd->vdev, VFL_TYPE_GRABBER, -1);
}
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值