From: John Tsiombikas Date: Thu, 11 May 2017 02:37:25 +0000 (+0300) Subject: initial commit X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=vdummy;a=commitdiff_plain;h=a1d08251c3da5c9751f3d662d75f45c0ebd1bee1 initial commit --- a1d08251c3da5c9751f3d662d75f45c0ebd1bee1 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..60277f8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +*.swp +*.o +*.ko +*.cmd +*.symvers +*.order +*.mod.* +.tmp_versions diff --git a/Makefile b/Makefile new file mode 100644 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 index 0000000..cde798d --- /dev/null +++ b/vdummy.c @@ -0,0 +1,206 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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