Linux camera驱动(3) - 框架

V4L2框架:

        用户空间-->v4l2-->master-->slave

1.slave端(摄像头数据处理芯片)

ak8859_init
    -->i2c_add_driver(&ak8859_i2c_driver);
    -->ak8859_probe
    	-->v4l2_int_device_register(&ak8859_int_device)  #slave和master的注册都使用这个函数
    		-->v4l2_int_device_try_attach_all()
    			-->m->u.master->attach(s)

详解如下:

drivers/media/platform/mxc/capture/ak8859.c

static int ak8859_probe(struct i2c_client *client,const struct i2c_device_id *id)
{
    ak8859_int_device.priv = &ak8859_data;	/*用户open的时候会通过cam->sensor->priv来访问sensor*/
	ret = v4l2_int_device_register(&ak8859_int_device);	/*注册ak8859_data--->*/
}

drivers/media/v4l2-core/v4l2-int-device.c

int v4l2_int_device_register(struct v4l2_int_device *d)
{
    if (d->type == v4l2_int_type_slave)  /*按照序号存储,加快访问速度*/
        sort(d->u.slave->ioctls, d->u.slave->num_ioctls,sizeof(struct v4l2_int_ioctl_desc),&ioctl_sort_cmp, NULL);
	list_add(&d->head, &int_list);	/*无论是slave还是master都会添加到int_list中*/
	v4l2_int_device_try_attach_all(); //都会做匹配动作--->
}
void v4l2_int_device_try_attach_all(void)
{
    struct v4l2_int_device *m, *s;
    list_for_each_entry(m, &int_list, head) {/*对int_list中每个master*/
        if (m->type != v4l2_int_type_master)
            continue;
        list_for_each_entry(s, &int_list, head) {/*对int_list中每个slave*/
            if (s->type != v4l2_int_type_slave)
                continue;
            if (s->u.slave->master)/*slave中master已经被赋值说明已经连接起来*/
                continue;
            s->u.slave->master = m;/*说明slave找到了master*/
            if (m->u.master->attach(s)) { /*执行master的匹配函数*/
                s->u.slave->master = NULL;
                module_put(m->module);
                continue;
            }
        }
	}
}

2.master端(SOC内置摄像头控制器)

camera_init()
    -->mxc_v4l2_probe
        -->init_camera_struct(cam, pdev)
            -->cam->self->u.master = &mxc_v4l2_master
        -->v4l2_int_device_register(cam->self)   #slave和master的注册都使用这个函数
            -->v4l2_int_device_try_attach_all()   
                -->m->u.master->attach(s)
        -->video_register_device(cam-
        >video_dev, VFL_TYPE_GRABBER, video_nr)

详解如下:

drivers/media/platform/mxc/capture/mxc_v4l2_capture.c

static __init int camera_init(void)
{
	err = platform_driver_register(&mxc_v4l2_driver);  /*平台注册V4L2驱动*/
}
static int mxc_v4l2_probe(struct platform_device *pdev)
{
    init_camera_struct(cam, pdev); /*初始化cam_data结构--->*/
    /*在很多函数中,形参只是v4l2_int_device类型的self,相要获得更外层的cam_data结构体的话,就可以从self->priv中获取*/
	cam->self->priv = cam;	/*注意这里的cam赋值,后面match函数中会用到*/
	v4l2_int_device_register(cam->self); /*注册在init_camera_struct函数中填充的self结构体--->*/
	video_register_device(cam->video_dev, VFL_TYPE_GRABBER, video_nr)  /*注册video设备-->*/
}
static int init_camera_struct(cam_data *cam, struct platform_device *pdev)
{
    *(cam->video_dev) = mxc_v4l_template;	/* 注意这里的赋值,包含了ops操作,ops为用户空间提供了操作接口 */
    /*在视频采集过程中,如果一个buffer填充满的话,会产生一个中断信号,中断处理函数中最终会调用到这个函数来处理中断*/
    cam->enc_callback = camera_callback;	/*设置callback*/
    cam->self->u.master = &mxc_v4l2_master;   /*slave或者master注册时会调用master的匹配函数*/
}
static void camera_callback(u32 mask, void *dev)
{   #将填满的buffer从working_q链表删除,挂接到done_q链表,然后唤醒等待队列上指定的进程
    /* Added to the done queue */
	list_del(cam->working_q.next);
	list_add_tail(&done_frame->queue, &cam->done_q);
	/* Wake up the queue */
	cam->enc_counter++;
	wake_up_interruptible(&cam->enc_queue);    //唤醒等待队列上的进程cam->enc_queue
}

kernel/include/media/v4l2-dev.h

static inline int __must_check video_register_device(struct video_device *vdev,
		int type, int nr)
{
	return __video_register_device(vdev, type, nr, 1, vdev->fops->owner);
}

drivers/media/v4l2-core/v4l2-dev.c

int __video_register_device(struct video_device *vdev, int type, int nr,int warn_if_nr_in_use, struct module *owner)
{
/* Part 1: 检查设备类型,我们这里是VFL_TYPE_GRABBER*/
	switch (type) {
	case VFL_TYPE_GRABBER:
		name_base = "video";
		break;
	······
	case VFL_TYPE_RADIO:
		name_base = "radio";
		break;
  }
  /* Part 2:查找空闲的minor*/
  /* Part 3:初始化字符设备*/
  vdev->cdev->ops = &v4l2_fops;	/*用户打开设备后的file ops!!!!!*/
  ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1);  
  /* Part 4:注册设备到sysfs*/
  /* Part 5:注册一个media设备实体*/
  /* Part 6:激活设备,设备可以使用 */
}

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值