struct task_struct *kthread;
struct xxx_buffer {
/* common v4l buffer stuff -- must be first */
struct vb2_v4l2_buffer vb;
struct list_head list;
};
struct xxx_fmt {
u32 pixelformat;
u32 bit_depth;
};
struct xxx_fmt xxx_formats[] = {
{
.pixelformat = V4L2_PIX_FMT_RGB565,
.bit_depth = 16,
},
};
int xxx_queue_setup(struct vb2_queue *q,
unsigned int *num_buffers, unsigned int *num_planes,
unsigned int sizes[], struct device *alloc_devs[])
{
// 一帧数据大小sizeimage(bytes)
sizes[0] = sizeimage;
return 0;
}
int xxx_buf_prepare(struct vb2_buffer *vb)
{
// 一帧数据大小sizeimage(bytes)
vb2_set_plane_payload(vb, 0, sizeimage);
return 0;
}
void xxx_buf_queue(struct vb2_buffer *vb)
{
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
struct xxx_buffer *buf = container_of(vbuf, struct xxx_buffer, vb);
// 将buffer存放到链表中
list_add_tail(&buf->list, &list);
}
static int xxx_kthread(void *data)
{
struct xxx_buffer *buf = NULL;
void *vbuf;
for (;;) {
if (kthread_should_stop())
break;
// 获得链表第一个buffer
buf = list_entry(list.next, struct xxx_buffer, list);
// 从链表中删除buffer
list_del(&buf->list);
// 获得buffer地址
vbuf = vb2_plane_vaddr(&buf->vb.vb2_buf, 0);
// 这里为了简单,直接填充数据0x88,一帧数据大小sizeimage(bytes)
// 实际中通过此处填充摄像头数据
memset(vbuf, 0x88, sizeimage);
// 通知应用层buffer已经准备完毕,可以读取
vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
// 这里为了简单,直接调用msleep(),实际应用中不能这样做
// 实际中通过此处实现摄像头帧率
msleep(100);
}
return 0;
}
int xxx_start_streaming(struct vb2_queue *q, unsigned int count)
{
/* 创建并启动内核线程
* xxx_kthread : 内核线程函数
* xxx : 传递给内核线程的参数,
* xxx-kthread : 内核线程的名字
*/
kthread = kthread_run(xxx_kthread, xxx, "xxx-kthread");
return 0;
}
void xxx_stop_streaming(struct vb2_queue *q)
{
// 删除链表中所有buffers
while (!list_empty(&list)) {
struct xxx_buffer *buf;
buf = list_entry(list.next, struct xxx_buffer, list);
list_del(&buf->list);
vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
}
kthread_stop(kthread);
}
const struct vb2_ops xxx_queue_ops = {
.queue_setup = xxx_queue_setup,
.buf_prepare = xxx_buf_prepare,
.buf_queue = xxx_buf_queue,
.start_streaming = xxx_start_streaming,
.stop_streaming = xxx_stop_streaming,
};
/*
* 获得摄像头信息
*/
int xxx_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
{
strcpy(cap->driver, "xxx_driver");
strcpy(cap->card, "xxx_card");
strcpy(cap->bus_info, "xxx_bus_info");
return 0;
}
/*
* 枚举摄像头支持的像素格式
*/
int xxx_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f)
{
struct xxx_fmt *fmt;
if (f->index >= ARRAY_SIZE(xxx_formats))
return -EINVAL;
fmt = &xxx_formats[f->index];
f->pixelformat = fmt->pixelformat;
return 0;
}
/*
* 获得目前摄像头的分辨率width*height, 像素格式pixelformat,一帧数据大小sizeimage(bytes)
*/
int xxx_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
{
struct v4l2_pix_format pix = f->fmt.pix;
pix.width = width;
pix.height = height;
pix.pixelformat = pixelformat;
pix.sizeimage = sizeimage;
return 0;
}
/*
* 设置摄像头的分辨率width*height, 像素格式pixelformat,一帧数据大小sizeimage(bytes)
*/
int xxx_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
{
struct v4l2_pix_format pix = f->fmt.pix;
int i;
width = pix.width;
height = pix.height;
pixelformat = pix.pixelformat;
for(i=0; i<ARRAY_SIZE(xxx_formats); i++) {
if(pix.pixelformat == xxx_formats[i].pixelformat)
break;
}
sizeimage = width * (xxx_formats[i].bit_depth >> 3) * height;
return 0;
}
const struct v4l2_file_operations xxx_fops = {
.owner = THIS_MODULE,
.open = v4l2_fh_open,
.release = v4l2_fh_release,
.poll = vb2_fop_poll,
.unlocked_ioctl = video_ioctl2,
.mmap = vb2_fop_mmap,
};
const struct v4l2_ioctl_ops xxx_ioctl_ops = {
.vidioc_querycap = xxx_querycap,
.vidioc_enum_fmt_vid_cap = xxx_enum_fmt_vid_cap,
.vidioc_g_fmt_vid_cap = xxx_g_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = xxx_s_fmt_vid_cap,
.vidioc_reqbufs = vb2_ioctl_reqbufs,
.vidioc_querybuf = vb2_ioctl_querybuf,
.vidioc_qbuf = vb2_ioctl_qbuf,
.vidioc_dqbuf = vb2_ioctl_dqbuf,
.vidioc_streamon = vb2_ioctl_streamon,
.vidioc_streamoff = vb2_ioctl_streamoff,
};
void xxx_release(struct video_device *vdev)
{
}