switching to videobuf2
[vdummy] / vdummy.c
1 #include <linux/module.h>
2 #include <linux/kernel.h>
3 #include <linux/mutex.h>
4 #include <linux/fs.h>
5 #include <linux/slab.h>
6 #include <asm/uaccess.h>
7 #include <linux/videodev2.h>
8 #include <media/videobuf2-vmalloc.h>
9 #include <media/v4l2-dev.h>
10 #include <media/v4l2-ioctl.h>
11 #include <media/v4l2-device.h>
12
13 struct buffer {
14         struct vb2_buffer vb;
15         struct buffer *next;
16 };
17
18 static int init(void);
19 static void shutdown(void);
20
21 static int ioctl_querycap(struct file *file, void *fh, struct v4l2_capability *cap);
22 static int ioctl_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *fdesc);
23 static int ioctl_get_fmt(struct file *file, void *fh, struct v4l2_format *fmt);
24 static int ioctl_set_fmt(struct file *file, void *fh, struct v4l2_format *fmt);
25 static int ioctl_get_parm(struct file *file, void *fh, struct v4l2_streamparm *fmt);
26 static int ioctl_set_parm(struct file *file, void *fh, struct v4l2_streamparm *fmt);
27 static int ioctl_queryctl(struct file *file, void *fh, struct v4l2_queryctrl *ctl);
28
29 static int queue_setup(struct vb2_queue *vbq, unsigned int *nbuf,
30                 unsigned int *nplanes, unsigned int *sizes, void **alloc_ctx);
31 static int buf_prepare(struct vb2_buffer *vb);
32 static void buf_queue(struct vb2_buffer *vb);
33 static int start_streaming(struct vb2_queue *vbq, unsigned int count);
34 static void stop_streaming(struct vb2_queue *vbq);
35
36
37 static int update_frame(int xsz, int ysz);
38
39
40 module_init(init);
41 module_exit(shutdown);
42
43 MODULE_LICENSE("GPL");
44 MODULE_AUTHOR("John Tsiombikas");
45 MODULE_DESCRIPTION("v4l2 test module");
46
47 static struct mutex mutex;
48 static struct video_device *vdev;
49
50 static struct v4l2_device v4l2_dev;
51 static struct v4l2_file_operations fops;
52 static struct v4l2_ioctl_ops iops;
53 static struct vb2_queue vbq;
54 static struct vb2_ops vbops;
55 static int width, height;
56 static unsigned char *frame;
57 static int frame_size;
58
59 static int streaming;
60 static struct buffer *buflist;
61 static int seqno;
62
63
64 static int init(void)
65 {
66         int res;
67
68         strcpy(v4l2_dev.name, "vdummy");
69         if((res = v4l2_device_register(0, &v4l2_dev)) != 0) {
70                 return res;
71         }
72
73         mutex_init(&mutex);
74
75         vbops.queue_setup = queue_setup;
76         vbops.buf_prepare = buf_prepare;
77         vbops.buf_queue = buf_queue;
78         vbops.start_streaming = start_streaming;
79         vbops.stop_streaming = stop_streaming;
80         vbops.wait_prepare = vb2_ops_wait_prepare;
81         vbops.wait_finish = vb2_ops_wait_finish;
82
83         vbq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
84         vbq.io_modes = VB2_MMAP | VB2_READ;
85         vbq.buf_struct_size = sizeof *buflist;
86         vbq.ops = &vbops;
87         vbq.mem_ops = &vb2_vmalloc_memops;
88         vbq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
89         vbq.min_buffers_needed = 1;
90         vbq.lock = &mutex;
91         vbq.gfp_flags = GFP_KERNEL;
92
93         if((res = vb2_queue_init(&vbq)) != 0) {
94                 printk(KERN_ALERT "vdummy: failed to initialize videobuf2 queue\n");
95                 v4l2_device_unregister(&v4l2_dev);
96                 return res;
97         }
98
99         if(!(vdev = video_device_alloc())) {
100                 return -ENOMEM;
101         }
102         vdev->release = video_device_release;
103         strcpy(vdev->name, KBUILD_MODNAME);
104         vdev->fops = &fops;
105         vdev->ioctl_ops = &iops;
106         vdev->vfl_type = VFL_TYPE_GRABBER;
107         vdev->v4l2_dev = &v4l2_dev;
108
109         fops.owner = THIS_MODULE;
110         fops.open = v4l2_fh_open;
111         fops.release = vb2_fop_release;
112         fops.read = vb2_fop_read;
113         fops.mmap = vb2_fop_mmap;
114         fops.poll = vb2_fop_poll;
115         fops.unlocked_ioctl = video_ioctl2;
116
117         iops.vidioc_querycap = ioctl_querycap;
118         iops.vidioc_enum_fmt_vid_cap = ioctl_enum_fmt;
119         iops.vidioc_g_fmt_vid_cap = ioctl_get_fmt;
120         iops.vidioc_s_fmt_vid_cap = ioctl_set_fmt;
121         iops.vidioc_g_parm = ioctl_get_parm;
122         iops.vidioc_s_parm = ioctl_set_parm;
123         iops.vidioc_queryctrl = ioctl_queryctl;
124         iops.vidioc_reqbufs = vb2_ioctl_reqbufs;
125         iops.vidioc_create_bufs = vb2_ioctl_create_bufs;
126         iops.vidioc_querybuf = vb2_ioctl_querybuf;
127         iops.vidioc_qbuf = vb2_ioctl_qbuf;
128         iops.vidioc_dqbuf = vb2_ioctl_dqbuf;
129         iops.vidioc_expbuf = vb2_ioctl_expbuf;
130         iops.vidioc_streamon = vb2_ioctl_streamon;
131         iops.vidioc_streamoff = vb2_ioctl_streamoff;
132
133         if((res = video_register_device(vdev, VFL_TYPE_GRABBER, -1)) != 0) {
134                 printk(KERN_ALERT "vdummy: failed to register video device\n");
135                 v4l2_device_unregister(&v4l2_dev);
136                 video_device_release(vdev);
137                 return res;
138         }
139
140         if((res = update_frame(640, 480)) != 0) {
141                 video_unregister_device(vdev);
142                 v4l2_device_unregister(&v4l2_dev);
143                 video_device_release(vdev);
144                 return res;
145         }
146
147         printk(KERN_INFO "vdummy device initialized\n");
148         return 0;
149 }
150
151 static void shutdown(void)
152 {
153         video_unregister_device(vdev);
154         v4l2_device_unregister(&v4l2_dev);
155         kfree(frame);
156 }
157
158 static int ioctl_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
159 {
160         strcpy(cap->driver, KBUILD_MODNAME);
161         strcpy(cap->card, "dummy v4l2 dev");
162         strcpy(cap->bus_info, "nobus");
163         cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
164         cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
165         return 0;
166 }
167
168 static int ioctl_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *fdesc)
169 {
170         if(fdesc->index != 0 || fdesc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
171                 return -EINVAL;
172         }
173         fdesc->flags = 0;
174         strcpy(fdesc->description, "RGB24");
175         fdesc->pixelformat = V4L2_PIX_FMT_RGB24;
176         return 0;
177 }
178
179 static int ioctl_get_fmt(struct file *file, void *fh, struct v4l2_format *fmt)
180 {
181         if(fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
182                 return -EINVAL;
183         }
184         fmt->fmt.pix.width = width;
185         fmt->fmt.pix.height = height;
186         fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24;
187         fmt->fmt.pix.field = V4L2_FIELD_NONE;
188         fmt->fmt.pix.bytesperline = 0;
189         fmt->fmt.pix.sizeimage = frame_size;
190         fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
191         fmt->fmt.pix.priv = 0;
192         fmt->fmt.pix.flags = 0;
193         fmt->fmt.pix.ycbcr_enc = 0;
194         fmt->fmt.pix.quantization = V4L2_QUANTIZATION_FULL_RANGE;
195         fmt->fmt.pix.xfer_func = V4L2_XFER_FUNC_NONE;
196         return 0;
197 }
198
199 static int ioctl_set_fmt(struct file *file, void *fh, struct v4l2_format *fmt)
200 {
201         int res;
202
203         if(fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
204                 return -EINVAL;
205         }
206         if((res = update_frame(fmt->fmt.pix.width, fmt->fmt.pix.height)) != 0) {
207                 return res;
208         }
209         return ioctl_get_fmt(file, fh, fmt);
210 }
211
212 static int ioctl_get_parm(struct file *file, void *fh, struct v4l2_streamparm *parm)
213 {
214         if(parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
215                 return -EINVAL;
216         }
217         parm->parm.capture.capability = 0;
218         parm->parm.capture.capturemode = 0;
219         parm->parm.capture.timeperframe.numerator = 1;
220         parm->parm.capture.timeperframe.denominator = 30;
221         parm->parm.capture.extendedmode = 0;
222         parm->parm.capture.readbuffers = 1;
223         return 0;
224 }
225
226 static int ioctl_set_parm(struct file *file, void *fh, struct v4l2_streamparm *parm)
227 {
228         if(parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
229                 return -EINVAL;
230         }
231         return ioctl_get_parm(file, fh, parm);
232 }
233
234 static int ioctl_queryctl(struct file *file, void *fh, struct v4l2_queryctrl *ctl)
235 {
236         return -EINVAL;
237 }
238
239 static int queue_setup(struct vb2_queue *vbq, unsigned int *nbuf,
240                 unsigned int *nplanes, unsigned int *sizes, void **alloc_ctx)
241 {
242         if(vbq->num_buffers + *nbuf < 2) {
243                 *nbuf = 2 - vbq->num_buffers;
244         }
245
246         *nplanes = 1;
247         sizes[0] = frame_size;
248         alloc_ctx[0] = 0;
249         return 0;
250 }
251
252 static int buf_prepare(struct vb2_buffer *vb)
253 {
254         if(vb2_plane_size(vb, 0) < frame_size) {
255                 printk(KERN_ALERT "vdummy: buffer too small\n");
256                 return -EINVAL;
257         }
258         vb2_set_plane_payload(vb, 0, frame_size);
259         return 0;
260 }
261
262 static void buf_queue(struct vb2_buffer *vb)
263 {
264         memcpy(vb2_plane_vaddr(vb, 0), frame, frame_size);
265         vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
266 }
267
268 static int start_streaming(struct vb2_queue *vbq, unsigned int count)
269 {
270         streaming = 1;
271         seqno = 0;
272         return 0;
273 }
274
275 static void stop_streaming(struct vb2_queue *vbq)
276 {
277         streaming = 0;
278 }
279
280 static int update_frame(int xsz, int ysz)
281 {
282         unsigned char *tmp;
283         int i, j;
284         int new_fsz = xsz * ysz * 3;
285
286         if(xsz == width && ysz == height) {
287                 return 0;
288         }
289
290         printk(KERN_INFO "vdummy: update_frame(%d, %d)\n", xsz, ysz);
291
292         if(!frame || frame_size < new_fsz) {
293                 if(!(tmp = kmalloc(new_fsz, GFP_KERNEL))) {
294                         return -ENOMEM;
295                 }
296                 kfree(frame);
297                 frame_size = new_fsz;
298                 width = xsz;
299                 height = ysz;
300                 frame = tmp;
301         }
302
303         tmp = frame;
304         for(i=0; i<height; i++) {
305                 for(j=0; j<width; j++) {
306                         int val = i ^ j;
307                         *tmp++ = val;
308                         *tmp++ = (val << 1) & 0xff;
309                         *tmp++ = (val << 2) & 0xff;
310                 }
311         }
312         return 0;
313 }