linux摄像头c程序,以vivi.c为例分析摄像头驱动程序思路

以vivi.c为例分析摄像头驱动程序思路:

Virtual Video driver - This code emulates a real video device with v4l2 api

入口:static int __init vivi_init(void)

ret = vivi_create_instance(i) //创建设备

struct vivi_dev *dev; //定义一个vivi_dev结构体

(a)定义 struct video_device *vfd //定义一个video_devce结构体

struct vivi_dev {

struct list_head vivi_devlist;

struct v4l2_device      v4l2_dev;

spinlock_t slock;

struct mutex         mutex;

int users;

/* various device info */

struct video_device *vfd;

struct vivi_dmaqueue vidq;

/* Several counters */

int h, m, s, ms;

unsigned long jiffies;

char timestr[13];

int             mv_count;    /* Controls bars movement */

/* Input Number */

int             input;

/* Control 'registers' */

int              qctl_regs[ARRAY_SIZE(vivi_qctrl)];

};

重要成员:

/* various device info */

struct video_device *vfd; //套接一个video_devce结构体,里面设置设备信息

struct video_device

{

const struct v4l2_file_operations *fops;

/* sysfs */

struct device dev;        /* v4l device */

struct cdev *cdev;        /* character device */

/* Set either parent or v4l2_dev if your driver uses v4l2_device */

struct device *parent;        /* device parent */

struct v4l2_device *v4l2_dev;    /* v4l2_device parent */

/* device info */

char name[32];

int vfl_type;

/* 'minor' is set to -1 if the registration failed */

int minor;

u16 num;

/* use bitops to set/clear/test flags */

unsigned long flags;

/* attribute to differentiate multiple indices on one physical device */

int index;

int debug;            /* Activates debug level*/

/* Video standard vars */

v4l2_std_id tvnorms;        /* Supported tv norms */

v4l2_std_id current_norm;    /* Current tvnorm */

/* callbacks */

void (*release)(struct video_device *vdev);

const struct v4l2_ioctl_ops *ioctl_ops;

};

重要成员:

const struct v4l2_file_operations *fops; //定义设备操作函数

const struct v4l2_ioctl_ops *ioctl_ops; //定义ioctl 回调函数,用于应用程序获取底层信息比如获取、配置摄像头所支持的格式

vivi.c中对video_device设置的过程:

(b)分配    vfd = video_device_alloc(); //给前面定义的video_device结构体分配内存

(c)设置    *vfd = vivi_template; //把之前设置好的video_device结构体赋给vfd

注:

static struct video_device vivi_template = {

.name        = "vivi",

.fops = &vivi_fops,

.ioctl_ops     = &vivi_ioctl_ops,

.minor        = -1,

.release    = video_device_release,

其中包括几个两个重要操作函数的设置:

1.

static const struct v4l2_file_operations vivi_fops = {

.owner        = THIS_MODULE,

.open = vivi_open,

.release = vivi_close,

.read = vivi_read,

.poll        = vivi_poll,

.ioctl = video_ioctl2, /* V4L2 ioctl handler */

.mmap = vivi_mmap,

};

struct v4l2_file_operations {

struct module *owner;

ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);

ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);

unsigned int (*poll) (struct file *, struct poll_table_struct *);

long (*ioctl) (struct file *, unsigned int, unsigned long);

long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);

unsigned long (*get_unmapped_area) (struct file *, unsigned long,

unsigned long, unsigned long, unsigned long);

int (*mmap) (struct file *, struct vm_area_struct *);

int (*open) (struct file *);

int (*release) (struct file *);

};

2.

static const struct v4l2_ioctl_ops vivi_ioctl_ops = {

/* 表示它是一个摄像头设备 */

.vidioc_querycap = vidioc_querycap,

/* 用于选择输入源,在xawtv里面就是video source */

//.vidioc_enum_input = vidioc_enum_input,

//.vidioc_g_input = vidioc_g_input,

//.vidioc_s_input = vidioc_s_input,

/* 用于列举、获得TV 制式,不是必须的*/

//.vidioc_s_std = vidioc_s_std,

/* video_device里面:

.tvnorms = V4L2_STD_525_60, //用于IDIOC_ENUMSTD

.current_norm = V4L2_STD_NTSC_M,// 用于VIDIOC_G_STD

*/

/* 用于列举、获得、测试、设置摄像头所提供的格式 */

.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,//也可以去掉

.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,

.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,

.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,

/* 缓冲区操作: 申请/ 查询/ 放入队列/取出队列*/

.vidioc_reqbufs = vidioc_reqbufs,

.vidioc_querybuf = vidioc_querybuf,

.vidioc_qbuf = vidioc_qbuf,

.vidioc_dqbuf = vidioc_dqbuf,

/* 查询/获得/设置属性 */

//.vidioc_queryctrl = vidioc_queryctrl,

//.vidioc_g_ctrl = vidioc_g_ctrl,

//.vidioc_s_ctrl = vidioc_s_ctrl,

/* 启动/停止摄像头 */

.vidioc_streamon = vidioc_streamon,

.vidioc_streamoff = vidioc_streamoff,

};

struct v4l2_ioctl_ops {

/* ioctl callbacks */

/* VIDIOC_QUERYCAP handler */

int (*vidioc_querycap)(struct file *file, void *fh, struct v4l2_capability *cap);

/* Priority handling */

int (*vidioc_g_priority) (struct file *file, void *fh,

enum v4l2_priority *p);

int (*vidioc_s_priority) (struct file *file, void *fh,

enum v4l2_priority p);

/* VIDIOC_ENUM_FMT handlers */

int (*vidioc_enum_fmt_vid_cap) (struct file *file, void *fh,

struct v4l2_fmtdesc *f);

int (*vidioc_enum_fmt_vid_overlay) (struct file *file, void *fh,

struct v4l2_fmtdesc *f);

int (*vidioc_enum_fmt_vid_out) (struct file *file, void *fh,

struct v4l2_fmtdesc *f);

int (*vidioc_enum_fmt_type_private)(struct file *file, void *fh,

struct v4l2_fmtdesc *f);

/* VIDIOC_G_FMT handlers */

int (*vidioc_g_fmt_vid_cap) (struct file *file, void *fh,

struct v4l2_format *f);

int (*vidioc_g_fmt_vid_overlay)(struct file *file, void *fh,

struct v4l2_format *f);

int (*vidioc_g_fmt_vid_out) (struct file *file, void *fh,

struct v4l2_format *f);

int (*vidioc_g_fmt_vid_out_overlay)(struct file *file, void *fh,

struct v4l2_format *f);

int (*vidioc_g_fmt_vbi_cap) (struct file *file, void *fh,

struct v4l2_format *f);

int (*vidioc_g_fmt_vbi_out) (struct file *file, void *fh,

struct v4l2_format *f);

int (*vidioc_g_fmt_sliced_vbi_cap)(struct file *file, void *fh,

struct v4l2_format *f);

int (*vidioc_g_fmt_sliced_vbi_out)(struct file *file, void *fh,

struct v4l2_format *f);

int (*vidioc_g_fmt_type_private)(struct file *file, void *fh,

struct v4l2_format *f);

/* VIDIOC_S_FMT handlers */

int (*vidioc_s_fmt_vid_cap) (struct file *file, void *fh,

struct v4l2_format *f);

int (*vidioc_s_fmt_vid_overlay)(struct file *file, void *fh,

struct v4l2_format *f);

int (*vidioc_s_fmt_vid_out) (struct file *file, void *fh,

struct v4l2_format *f);

int (*vidioc_s_fmt_vid_out_overlay)(struct file *file, void *fh,

struct v4l2_format *f);

int (*vidioc_s_fmt_vbi_cap) (struct file *file, void *fh,

struct v4l2_format *f);

int (*vidioc_s_fmt_vbi_out) (struct file *file, void *fh,

struct v4l2_format *f);

int (*vidioc_s_fmt_sliced_vbi_cap)(struct file *file, void *fh,

struct v4l2_format *f);

int (*vidioc_s_fmt_sliced_vbi_out)(struct file *file, void *fh,

struct v4l2_format *f);

int (*vidioc_s_fmt_type_private)(struct file *file, void *fh,

struct v4l2_format *f);

/* VIDIOC_TRY_FMT handlers */

int (*vidioc_try_fmt_vid_cap) (struct file *file, void *fh,

struct v4l2_format *f);

int (*vidioc_try_fmt_vid_overlay)(struct file *file, void *fh,

struct v4l2_format *f);

int (*vidioc_try_fmt_vid_out) (struct file *file, void *fh,

struct v4l2_format *f);

int (*vidioc_try_fmt_vid_out_overlay)(struct file *file, void *fh,

struct v4l2_format *f);

int (*vidioc_try_fmt_vbi_cap) (struct file *file, void *fh,

struct v4l2_format *f);

int (*vidioc_try_fmt_vbi_out) (struct file *file, void *fh,

struct v4l2_format *f);

int (*vidioc_try_fmt_sliced_vbi_cap)(struct file *file, void *fh,

struct v4l2_format *f);

int (*vidioc_try_fmt_sliced_vbi_out)(struct file *file, void *fh,

struct v4l2_format *f);

int (*vidioc_try_fmt_type_private)(struct file *file, void *fh,

struct v4l2_format *f);

/* Buffer handlers */

int (*vidioc_reqbufs) (struct file *file, void *fh, struct v4l2_requestbuffers *b);

int (*vidioc_querybuf)(struct file *file, void *fh, struct v4l2_buffer *b);

int (*vidioc_qbuf) (struct file *file, void *fh, struct v4l2_buffer *b);

int (*vidioc_dqbuf) (struct file *file, void *fh, struct v4l2_buffer *b);

int (*vidioc_overlay) (struct file *file, void *fh, unsigned int i);

#ifdef CONFIG_VIDEO_V4L1_COMPAT

/* buffer type is struct vidio_mbuf * */

int (*vidiocgmbuf) (struct file *file, void *fh, struct video_mbuf *p);

#endif

int (*vidioc_g_fbuf) (struct file *file, void *fh,

struct v4l2_framebuffer *a);

int (*vidioc_s_fbuf) (struct file *file, void *fh,

struct v4l2_framebuffer *a);

/* Stream on/off */

int (*vidioc_streamon) (struct file *file, void *fh, enum v4l2_buf_type i);

int (*vidioc_streamoff)(struct file *file, void *fh, enum v4l2_buf_type i);

/* Standard handling

ENUMSTD is handled by videodev.c

*/

int (*vidioc_g_std) (struct file *file, void *fh, v4l2_std_id *norm);

int (*vidioc_s_std) (struct file *file, void *fh, v4l2_std_id *norm);

int (*vidioc_querystd) (struct file *file, void *fh, v4l2_std_id *a);

/* Input handling */

int (*vidioc_enum_input)(struct file *file, void *fh,

struct v4l2_input *inp);

int (*vidioc_g_input) (struct file *file, void *fh, unsigned int *i);

int (*vidioc_s_input) (struct file *file, void *fh, unsigned int i);

/* Output handling */

int (*vidioc_enum_output) (struct file *file, void *fh,

struct v4l2_output *a);

int (*vidioc_g_output) (struct file *file, void *fh, unsigned int *i);

int (*vidioc_s_output) (struct file *file, void *fh, unsigned int i);

/* Control handling */

int (*vidioc_queryctrl) (struct file *file, void *fh,

struct v4l2_queryctrl *a);

int (*vidioc_g_ctrl) (struct file *file, void *fh,

struct v4l2_control *a);

int (*vidioc_s_ctrl) (struct file *file, void *fh,

struct v4l2_control *a);

int (*vidioc_g_ext_ctrls) (struct file *file, void *fh,

struct v4l2_ext_controls *a);

int (*vidioc_s_ext_ctrls) (struct file *file, void *fh,

struct v4l2_ext_controls *a);

int (*vidioc_try_ext_ctrls) (struct file *file, void *fh,

struct v4l2_ext_controls *a);

int (*vidioc_querymenu) (struct file *file, void *fh,

struct v4l2_querymenu *a);

/* Audio ioctls */

int (*vidioc_enumaudio) (struct file *file, void *fh,

struct v4l2_audio *a);

int (*vidioc_g_audio) (struct file *file, void *fh,

struct v4l2_audio *a);

int (*vidioc_s_audio) (struct file *file, void *fh,

struct v4l2_audio *a);

/* Audio out ioctls */

int (*vidioc_enumaudout) (struct file *file, void *fh,

struct v4l2_audioout *a);

int (*vidioc_g_audout) (struct file *file, void *fh,

struct v4l2_audioout *a);

int (*vidioc_s_audout) (struct file *file, void *fh,

struct v4l2_audioout *a);

int (*vidioc_g_modulator) (struct file *file, void *fh,

struct v4l2_modulator *a);

int (*vidioc_s_modulator) (struct file *file, void *fh,

struct v4l2_modulator *a);

/* Crop ioctls */

int (*vidioc_cropcap) (struct file *file, void *fh,

struct v4l2_cropcap *a);

int (*vidioc_g_crop) (struct file *file, void *fh,

struct v4l2_crop *a);

int (*vidioc_s_crop) (struct file *file, void *fh,

struct v4l2_crop *a);

/* Compression ioctls */

int (*vidioc_g_jpegcomp) (struct file *file, void *fh,

struct v4l2_jpegcompression *a);

int (*vidioc_s_jpegcomp) (struct file *file, void *fh,

struct v4l2_jpegcompression *a);

int (*vidioc_g_enc_index) (struct file *file, void *fh,

struct v4l2_enc_idx *a);

int (*vidioc_encoder_cmd) (struct file *file, void *fh,

struct v4l2_encoder_cmd *a);

int (*vidioc_try_encoder_cmd) (struct file *file, void *fh,

struct v4l2_encoder_cmd *a);

/* Stream type-dependent parameter ioctls */

int (*vidioc_g_parm) (struct file *file, void *fh,

struct v4l2_streamparm *a);

int (*vidioc_s_parm) (struct file *file, void *fh,

struct v4l2_streamparm *a);

/* Tuner ioctls */

int (*vidioc_g_tuner) (struct file *file, void *fh,

struct v4l2_tuner *a);

int (*vidioc_s_tuner) (struct file *file, void *fh,

struct v4l2_tuner *a);

int (*vidioc_g_frequency) (struct file *file, void *fh,

struct v4l2_frequency *a);

int (*vidioc_s_frequency) (struct file *file, void *fh,

struct v4l2_frequency *a);

/* Sliced VBI cap */

int (*vidioc_g_sliced_vbi_cap) (struct file *file, void *fh,

struct v4l2_sliced_vbi_cap *a);

/* Log status ioctl */

int (*vidioc_log_status) (struct file *file, void *fh);

int (*vidioc_s_hw_freq_seek) (struct file *file, void *fh,

struct v4l2_hw_freq_seek *a);

/* Debugging ioctls */

#ifdef CONFIG_VIDEO_ADV_DEBUG

int (*vidioc_g_register) (struct file *file, void *fh,

struct v4l2_dbg_register *reg);

int (*vidioc_s_register) (struct file *file, void *fh,

struct v4l2_dbg_register *reg);

#endif

int (*vidioc_g_chip_ident) (struct file *file, void *fh,

struct v4l2_dbg_chip_ident *chip);

int (*vidioc_enum_framesizes) (struct file *file, void *fh,

struct v4l2_frmsizeenum *fsize);

int (*vidioc_enum_frameintervals) (struct file *file, void *fh,

struct v4l2_frmivalenum *fival);

/* For other private ioctls */

long (*vidioc_default)     (struct file *file, void *fh,

int cmd, void *arg);

};

(d)注册     ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);

return video_register_device_index(vdev, type, nr, -1);

/*注册三部曲*/

vdev->cdev = cdev_alloc(); //第一步 分配字符设备内存

vdev->cdev->ops = &v4l2_fops; //第二部 设置将设备节点的操作函数

ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1); //将字符设备注册进内核

以上是虚拟视频驱动vivi.c的分析,以下下是分析vivi.c的open,read,write,ioctl过程:

1. open

app: open(/dev/video0)

2. read

app: read(/dev/video0)

3. write

app: write(/dev/video0)

4. ioctl

app: iotcl(/dev/video0)

以上系统函数调用,在进入驱动程序里都对应上面注册的v4l2_fops结构体里面的对应函数:

static const struct file_operations v4l2_fops = {

.owner = THIS_MODULE,

.read = v4l2_read,

.write = v4l2_write,

.open = v4l2_open,

.get_unmapped_area = v4l2_get_unmapped_area,

.mmap = v4l2_mmap,

.ioctl = v4l2_ioctl,

static int v4l2_open(struct inode *inode, struct file *filp)

{

struct video_device *vdev;

int ret = 0;

/* Check if the video device is available */

mutex_lock(&videodev_lock);

vdev = video_devdata(filp); // 根据次设备号从数组中得到video_device

/* return ENODEV if the video device has been removed

already or if it is not registered anymore. */

if (vdev == NULL || video_is_unregistered(vdev)) {

mutex_unlock(&videodev_lock);

return -ENODEV;

}

/* and increase the device refcount */

video_get(vdev);

mutex_unlock(&videodev_lock);

if (vdev->fops->open)

ret = vdev->fops->open(filp); //这里才显示庐山真面目,最终调用的是前面写的vivi_open函数

/* decrease the refcount in case of an error */

if (ret)

video_put(vdev);

return ret;

}

注:

struct video_device *video_devdata(struct file *file)

{

return video_device[iminor(file->f_path.dentry->d_inode)];

}

同理:app中的read函数最终会调用v4l2_read函数:

static ssize_t v4l2_read(struct file *filp, char __user *buf,

size_t sz, loff_t *off)

{

struct video_device *vdev = video_devdata(filp);

if (!vdev->fops->read)

return -EINVAL;

if (video_is_unregistered(vdev))

return -EIO;

return vdev->fops->read(filp, buf, sz, off); //最终会调用v4l2_fops操作结构体中的vivi_read函数

}

注:由于采用总线设备驱动模型,一些驱动通用的函数,linux系统已经帮助实现v4l2_dev.c(例v4l2_fops),到具体open,read,write,ioctl时,即最终

的open,read,write,ioctl等函数还要写驱动的人实现。

static ssize_t v4l2_write(struct file *filp, const char __user *buf,

size_t sz, loff_t *off)

{

struct video_device *vdev = video_devdata(filp);

if (!vdev->fops->write)

return -EINVAL;

if (video_is_unregistered(vdev))

return -EIO;

return vdev->fops->write(filp, buf, sz, off);//最终会调用v4l2_fops操作结构体中的vivi_write函数

}

static int v4l2_ioctl(struct inode *inode, struct file *filp,

unsigned int cmd, unsigned long arg)

{

struct video_device *vdev = video_devdata(filp);

if (!vdev->fops->ioctl)

return -ENOTTY;

/* Allow ioctl to continue even if the device was unregistered.

Things like dequeueing buffers might still be useful. */

return vdev->fops->ioctl(filp, cmd, arg); //最终会调用v4l2_fops操作结构体中的vivi_ioctl函数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值