initial commit
authorJohn Tsiombikas <nuclear@mutantstargoat.com>
Thu, 11 May 2017 02:37:25 +0000 (05:37 +0300)
committerJohn Tsiombikas <nuclear@mutantstargoat.com>
Thu, 11 May 2017 02:37:25 +0000 (05:37 +0300)
.gitignore [new file with mode: 0644]
Makefile [new file with mode: 0644]
vdummy.c [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..60277f8
--- /dev/null
@@ -0,0 +1,8 @@
+*.swp
+*.o
+*.ko
+*.cmd
+*.symvers
+*.order
+*.mod.*
+.tmp_versions
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..68a99ed
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,9 @@
+obj-m += vdummy.o
+
+.PHONY: all
+all:
+       make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
+
+.PHONY: clean
+clean:
+       make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
diff --git a/vdummy.c b/vdummy.c
new file mode 100644 (file)
index 0000000..cde798d
--- /dev/null
+++ b/vdummy.c
@@ -0,0 +1,206 @@
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <asm/uaccess.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-ioctl.h>
+
+static int init(void);
+static void shutdown(void);
+static int open(struct file *file);
+static int close(struct file *file);
+static ssize_t read(struct file *file, char *ubuf, size_t bufsz, loff_t *offs);
+
+static int ioctl_querycap(struct file *file, void *fh, struct v4l2_capability *cap);
+static int ioctl_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *fdesc);
+static int ioctl_get_fmt(struct file *file, void *fh, struct v4l2_format *fmt);
+static int ioctl_set_fmt(struct file *file, void *fh, struct v4l2_format *fmt);
+static int ioctl_queryctl(struct file *file, void *fh, struct v4l2_queryctrl *ctl);
+
+static int update_frame(int xsz, int ysz);
+
+
+module_init(init);
+module_exit(shutdown);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("John Tsiombikas");
+MODULE_DESCRIPTION("v4l2 test module");
+
+#define DEVNAME        "video42"
+
+struct video_device *vdev;
+
+static struct v4l2_file_operations fops;
+static struct v4l2_ioctl_ops iops;
+static int width, height;
+static unsigned char *frame;
+static int frame_size;
+
+
+static int init(void)
+{
+       int res;
+
+       if(!(vdev = video_device_alloc())) {
+               return -ENOMEM;
+       }
+       vdev->release = video_device_release;
+       strcpy(vdev->name, "video test");
+       vdev->fops = &fops;
+       vdev->ioctl_ops = &iops;
+       vdev->vfl_type = VFL_TYPE_GRABBER;
+
+       fops.open = open;
+       fops.release = close;
+       fops.read = read;
+       fops.unlocked_ioctl = video_ioctl2;
+
+       iops.vidioc_querycap = ioctl_querycap;
+       iops.vidioc_enum_fmt_vid_cap = ioctl_enum_fmt;
+       iops.vidioc_g_fmt_vid_cap = ioctl_get_fmt;
+       iops.vidioc_s_fmt_vid_cap = ioctl_set_fmt;
+       iops.vidioc_queryctrl = ioctl_queryctl;
+
+       if((res = video_register_device(vdev, VFL_TYPE_GRABBER, -1)) != 0) {
+               video_device_release(vdev);
+               return res;
+       }
+
+       return 0;
+}
+
+static void shutdown(void)
+{
+       video_unregister_device(vdev);
+       kfree(frame);
+}
+
+static int open(struct file *file)
+{
+       int res;
+       try_module_get(THIS_MODULE);
+       if((res = update_frame(640, 480)) != 0) {
+               return res;
+       }
+       return 0;
+}
+
+static int close(struct file *file)
+{
+       module_put(THIS_MODULE);
+       return 0;
+}
+
+static ssize_t read(struct file *file, char *ubuf, size_t ubufsz, loff_t *offs)
+{
+       int sz = frame_size - *offs;
+
+       if(sz <= 0) return 0;
+       if(ubufsz < sz) sz = ubufsz;
+
+       if(copy_to_user(ubuf, frame + *offs, sz) != 0) {
+               return -EFAULT;
+       }
+
+       *offs += sz;
+       if(*offs >= frame_size) {
+               *offs = 0;
+       }
+       return sz;
+}
+
+static int ioctl_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
+{
+       strcpy(cap->driver, "vidtest");
+       strcpy(cap->card, "fake");
+       strcpy(cap->bus_info, "nobus");
+       cap->version = 0;
+       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
+       return 0;
+}
+
+static int ioctl_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *fdesc)
+{
+       if(fdesc->index != 0 || fdesc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               return -EINVAL;
+       }
+       fdesc->flags = 0;
+       strcpy(fdesc->description, "RGB24");
+       fdesc->pixelformat = V4L2_PIX_FMT_RGB24;
+       return 0;
+}
+
+static int ioctl_get_fmt(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+       if(fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               return -EINVAL;
+       }
+       fmt->fmt.pix.width = width;
+       fmt->fmt.pix.height = height;
+       fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24;
+       fmt->fmt.pix.field = V4L2_FIELD_NONE;
+       fmt->fmt.pix.bytesperline = 0;
+       fmt->fmt.pix.sizeimage = frame_size;
+       fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
+       fmt->fmt.pix.priv = 0;
+       fmt->fmt.pix.flags = 0;
+       fmt->fmt.pix.ycbcr_enc = 0;
+       fmt->fmt.pix.quantization = V4L2_QUANTIZATION_FULL_RANGE;
+       fmt->fmt.pix.xfer_func = V4L2_XFER_FUNC_NONE;
+       return 0;
+}
+
+static int ioctl_set_fmt(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+       int res;
+
+       if(fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               return -EINVAL;
+       }
+       if((res = update_frame(fmt->fmt.pix.width, fmt->fmt.pix.height)) != 0) {
+               return res;
+       }
+       return ioctl_get_fmt(file, fh, fmt);
+}
+
+static int ioctl_queryctl(struct file *file, void *fh, struct v4l2_queryctrl *ctl)
+{
+       return -EINVAL;
+}
+
+static int update_frame(int xsz, int ysz)
+{
+       unsigned char *tmp;
+       int i, j;
+       int new_fsz = xsz * ysz;
+
+       if(xsz == width && ysz == height) {
+               return 0;
+       }
+
+       if(!frame || frame_size < new_fsz) {
+               if(!(tmp = kmalloc(new_fsz, GFP_KERNEL))) {
+                       return -ENOMEM;
+               }
+               kfree(frame);
+               frame_size = new_fsz;
+               width = xsz;
+               height = ysz;
+               frame = tmp;
+       }
+
+       tmp = frame;
+       for(i=0; i<height; i++) {
+               for(j=0; j<width; j++) {
+                       int val = i ^ j;
+                       *tmp++ = val;
+                       *tmp++ = (val << 1) & 0xff;
+                       *tmp++ = (val << 2) & 0xff;
+               }
+       }
+       return 0;
+}