要写一个摄像头驱动其实很简单,只要符合V4L2框架即可。剩下的就是对摄像头本身的操作。
static int myvivi_init(void)
{
int error;
/* 1. 分配一个video_device结构体 */
myvivi_device = video_device_alloc();
/* 2. 设置 */
/* 2.1 */
myvivi_device->release = myvivi_release;
/* 2.2 */
myvivi_device->fops = &myvivi_fops;
/* 2.3 */
myvivi_device->ioctl_ops = &myvivi_ioctl_ops;
/* 2.4 队列操作
* a. 定义/初始化一个队列(会用到一个spinlock)
*/
spin_lock_init(&myvivi_queue_slock);
/* 3. 注册 */
error = video_register_device(myvivi_device, VFL_TYPE_GRABBER, -1);
/* 用定时器产生数据并唤醒进程 */
init_timer(&myvivi_timer);
myvivi_timer.function = myvivi_timer_function;
INIT_LIST_HEAD(&myvivi_vb_local_queue);
return error;
}
static void myvivi_exit(void)
{
video_unregister_device(myvivi_device);
video_device_release(myvivi_device);
}
module_init(myvivi_init);
module_exit(myvivi_exit);
MODULE_LICENSE("GPL");
1.分配一个video_device结构体:video_device_alloc()
2.设置
主要设置video_device->release回调函数
设置video_device->fops
设置video_device->ioctl_ops
3.初始化队列
4.注册video_device, video_register_device()l
其中最重要的是根据具体摄像头实现video_device->fops和video_device->ioctl_ops。
static const struct v4l2_ioctl_ops myvivi_ioctl_ops = {
// 表示它是一个摄像头设备
.vidioc_querycap = myvivi_vidioc_querycap,
/* 用于列举、获得、测试、设置摄像头的数据的格式 */
.vidioc_enum_fmt_vid_cap = myvivi_vidioc_enum_fmt_vid_cap,
.vidioc_g_fmt_vid_cap = myvivi_vidioc_g_fmt_vid_cap,
.vidioc_try_fmt_vid_cap = myvivi_vidioc_try_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = myvivi_vidioc_s_fmt_vid_cap,
/* 缓冲区操作: 申请/查询/放入队列/取出队列 */
.vidioc_reqbufs = myvivi_vidioc_reqbufs,
.vidioc_querybuf = myvivi_vidioc_querybuf,
.vidioc_qbuf = myvivi_vidioc_qbuf,
.vidioc_dqbuf = myvivi_vidioc_dqbuf,
// 启动/停止
.vidioc_streamon = myvivi_vidioc_streamon,
.vidioc_streamoff = myvivi_vidioc_streamoff,
};
static const struct v4l2_file_operations myvivi_fops = {
.owner = THIS_MODULE,
.open = myvivi_open,
.release = myvivi_close,
.mmap = myvivi_mmap,
.ioctl = video_ioctl2, /* V4L2 ioctl handler */
.poll = myvivi_poll,
};