cde798d0a409a5bf3ce724df2bc1c9ca010e1cdd
[vdummy] / vdummy.c
1 #include <linux/module.h>
2 #include <linux/kernel.h>
3 #include <linux/version.h>
4 #include <linux/fs.h>
5 #include <linux/slab.h>
6 #include <asm/uaccess.h>
7 #include <linux/videodev2.h>
8 #include <media/v4l2-dev.h>
9 #include <media/v4l2-ioctl.h>
10
11 static int init(void);
12 static void shutdown(void);
13 static int open(struct file *file);
14 static int close(struct file *file);
15 static ssize_t read(struct file *file, char *ubuf, size_t bufsz, loff_t *offs);
16
17 static int ioctl_querycap(struct file *file, void *fh, struct v4l2_capability *cap);
18 static int ioctl_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *fdesc);
19 static int ioctl_get_fmt(struct file *file, void *fh, struct v4l2_format *fmt);
20 static int ioctl_set_fmt(struct file *file, void *fh, struct v4l2_format *fmt);
21 static int ioctl_queryctl(struct file *file, void *fh, struct v4l2_queryctrl *ctl);
22
23 static int update_frame(int xsz, int ysz);
24
25
26 module_init(init);
27 module_exit(shutdown);
28
29 MODULE_LICENSE("GPL");
30 MODULE_AUTHOR("John Tsiombikas");
31 MODULE_DESCRIPTION("v4l2 test module");
32
33 #define DEVNAME "video42"
34
35 struct video_device *vdev;
36
37 static struct v4l2_file_operations fops;
38 static struct v4l2_ioctl_ops iops;
39 static int width, height;
40 static unsigned char *frame;
41 static int frame_size;
42
43
44 static int init(void)
45 {
46         int res;
47
48         if(!(vdev = video_device_alloc())) {
49                 return -ENOMEM;
50         }
51         vdev->release = video_device_release;
52         strcpy(vdev->name, "video test");
53         vdev->fops = &fops;
54         vdev->ioctl_ops = &iops;
55         vdev->vfl_type = VFL_TYPE_GRABBER;
56
57         fops.open = open;
58         fops.release = close;
59         fops.read = read;
60         fops.unlocked_ioctl = video_ioctl2;
61
62         iops.vidioc_querycap = ioctl_querycap;
63         iops.vidioc_enum_fmt_vid_cap = ioctl_enum_fmt;
64         iops.vidioc_g_fmt_vid_cap = ioctl_get_fmt;
65         iops.vidioc_s_fmt_vid_cap = ioctl_set_fmt;
66         iops.vidioc_queryctrl = ioctl_queryctl;
67
68         if((res = video_register_device(vdev, VFL_TYPE_GRABBER, -1)) != 0) {
69                 video_device_release(vdev);
70                 return res;
71         }
72
73         return 0;
74 }
75
76 static void shutdown(void)
77 {
78         video_unregister_device(vdev);
79         kfree(frame);
80 }
81
82 static int open(struct file *file)
83 {
84         int res;
85         try_module_get(THIS_MODULE);
86         if((res = update_frame(640, 480)) != 0) {
87                 return res;
88         }
89         return 0;
90 }
91
92 static int close(struct file *file)
93 {
94         module_put(THIS_MODULE);
95         return 0;
96 }
97
98 static ssize_t read(struct file *file, char *ubuf, size_t ubufsz, loff_t *offs)
99 {
100         int sz = frame_size - *offs;
101
102         if(sz <= 0) return 0;
103         if(ubufsz < sz) sz = ubufsz;
104
105         if(copy_to_user(ubuf, frame + *offs, sz) != 0) {
106                 return -EFAULT;
107         }
108
109         *offs += sz;
110         if(*offs >= frame_size) {
111                 *offs = 0;
112         }
113         return sz;
114 }
115
116 static int ioctl_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
117 {
118         strcpy(cap->driver, "vidtest");
119         strcpy(cap->card, "fake");
120         strcpy(cap->bus_info, "nobus");
121         cap->version = 0;
122         cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
123         return 0;
124 }
125
126 static int ioctl_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *fdesc)
127 {
128         if(fdesc->index != 0 || fdesc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
129                 return -EINVAL;
130         }
131         fdesc->flags = 0;
132         strcpy(fdesc->description, "RGB24");
133         fdesc->pixelformat = V4L2_PIX_FMT_RGB24;
134         return 0;
135 }
136
137 static int ioctl_get_fmt(struct file *file, void *fh, struct v4l2_format *fmt)
138 {
139         if(fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
140                 return -EINVAL;
141         }
142         fmt->fmt.pix.width = width;
143         fmt->fmt.pix.height = height;
144         fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24;
145         fmt->fmt.pix.field = V4L2_FIELD_NONE;
146         fmt->fmt.pix.bytesperline = 0;
147         fmt->fmt.pix.sizeimage = frame_size;
148         fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
149         fmt->fmt.pix.priv = 0;
150         fmt->fmt.pix.flags = 0;
151         fmt->fmt.pix.ycbcr_enc = 0;
152         fmt->fmt.pix.quantization = V4L2_QUANTIZATION_FULL_RANGE;
153         fmt->fmt.pix.xfer_func = V4L2_XFER_FUNC_NONE;
154         return 0;
155 }
156
157 static int ioctl_set_fmt(struct file *file, void *fh, struct v4l2_format *fmt)
158 {
159         int res;
160
161         if(fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
162                 return -EINVAL;
163         }
164         if((res = update_frame(fmt->fmt.pix.width, fmt->fmt.pix.height)) != 0) {
165                 return res;
166         }
167         return ioctl_get_fmt(file, fh, fmt);
168 }
169
170 static int ioctl_queryctl(struct file *file, void *fh, struct v4l2_queryctrl *ctl)
171 {
172         return -EINVAL;
173 }
174
175 static int update_frame(int xsz, int ysz)
176 {
177         unsigned char *tmp;
178         int i, j;
179         int new_fsz = xsz * ysz;
180
181         if(xsz == width && ysz == height) {
182                 return 0;
183         }
184
185         if(!frame || frame_size < new_fsz) {
186                 if(!(tmp = kmalloc(new_fsz, GFP_KERNEL))) {
187                         return -ENOMEM;
188                 }
189                 kfree(frame);
190                 frame_size = new_fsz;
191                 width = xsz;
192                 height = ysz;
193                 frame = tmp;
194         }
195
196         tmp = frame;
197         for(i=0; i<height; i++) {
198                 for(j=0; j<width; j++) {
199                         int val = i ^ j;
200                         *tmp++ = val;
201                         *tmp++ = (val << 1) & 0xff;
202                         *tmp++ = (val << 2) & 0xff;
203                 }
204         }
205         return 0;
206 }