要寫一個攝像頭驅動其實很簡單,只要符合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,
};