📄 vivi.c
字号:
/* * Virtual Video driver - This code emulates a real video device with v4l2 api * * Copyright (c) 2006 by: * Mauro Carvalho Chehab <mchehab--a.t--infradead.org> * Ted Walther <ted--a.t--enumera.com> * John Sokol <sokol--a.t--videotechnology.com> * http://v4l.videotechnology.com/ * * This program is free software; you can redistribute it and/or modify * it under the terms of the BSD Licence, GNU General Public License * as published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version */#include <linux/module.h>#include <linux/delay.h>#include <linux/errno.h>#include <linux/fs.h>#include <linux/kernel.h>#include <linux/slab.h>#include <linux/mm.h>#include <linux/ioport.h>#include <linux/init.h>#include <linux/sched.h>#include <linux/pci.h>#include <linux/random.h>#include <linux/version.h>#include <linux/mutex.h>#include "compat.h"#include <linux/videodev2.h>#include <linux/dma-mapping.h>#ifdef CONFIG_VIDEO_V4L1_COMPAT/* Include V4L1 specific functions. Should be removed soon */#include <linux/videodev.h>#endif#include <linux/interrupt.h>#include <media/videobuf-vmalloc.h>#include <media/v4l2-common.h>#include <media/v4l2-ioctl.h>#include <linux/kthread.h>#include <linux/highmem.h>#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)#include <linux/freezer.h>#endif#define VIVI_MODULE_NAME "vivi"/* Wake up at about 30 fps */#define WAKE_NUMERATOR 30#define WAKE_DENOMINATOR 1001#define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */#include "font.h"#define VIVI_MAJOR_VERSION 0#define VIVI_MINOR_VERSION 5#define VIVI_RELEASE 0#define VIVI_VERSION \ KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE)/* Declare static vars that will be used as parameters */static unsigned int vid_limit = 16; /* Video memory limit, in Mb */static int video_nr = -1; /* /dev/videoN, -1 for autodetect */static int n_devs = 1; /* Number of virtual devices *//* supported controls */static struct v4l2_queryctrl vivi_qctrl[] = { { .id = V4L2_CID_AUDIO_VOLUME, .name = "Volume", .minimum = 0, .maximum = 65535, .step = 65535/100, .default_value = 65535, .flags = 0, .type = V4L2_CTRL_TYPE_INTEGER, }, { .id = V4L2_CID_BRIGHTNESS, .type = V4L2_CTRL_TYPE_INTEGER, .name = "Brightness", .minimum = 0, .maximum = 255, .step = 1, .default_value = 127, .flags = 0, }, { .id = V4L2_CID_CONTRAST, .type = V4L2_CTRL_TYPE_INTEGER, .name = "Contrast", .minimum = 0, .maximum = 255, .step = 0x1, .default_value = 0x10, .flags = 0, }, { .id = V4L2_CID_SATURATION, .type = V4L2_CTRL_TYPE_INTEGER, .name = "Saturation", .minimum = 0, .maximum = 255, .step = 0x1, .default_value = 127, .flags = 0, }, { .id = V4L2_CID_HUE, .type = V4L2_CTRL_TYPE_INTEGER, .name = "Hue", .minimum = -128, .maximum = 127, .step = 0x1, .default_value = 0, .flags = 0, }};static int qctl_regs[ARRAY_SIZE(vivi_qctrl)];#define dprintk(dev, level, fmt, arg...) \ do { \ if (dev->vfd->debug >= (level)) \ printk(KERN_DEBUG "vivi: " fmt , ## arg); \ } while (0)/* ------------------------------------------------------------------ Basic structures ------------------------------------------------------------------*/struct vivi_fmt { char *name; u32 fourcc; /* v4l2 format id */ int depth;};static struct vivi_fmt formats[] = { { .name = "4:2:2, packed, YUYV", .fourcc = V4L2_PIX_FMT_YUYV, .depth = 16, }, { .name = "4:2:2, packed, UYVY", .fourcc = V4L2_PIX_FMT_UYVY, .depth = 16, }, { .name = "RGB565 (LE)", .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */ .depth = 16, }, { .name = "RGB565 (BE)", .fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */ .depth = 16, }, { .name = "RGB555 (LE)", .fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */ .depth = 16, }, { .name = "RGB555 (BE)", .fourcc = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */ .depth = 16, },};static struct vivi_fmt *get_format(struct v4l2_format *f){ struct vivi_fmt *fmt; unsigned int k; for (k = 0; k < ARRAY_SIZE(formats); k++) { fmt = &formats[k]; if (fmt->fourcc == f->fmt.pix.pixelformat) break; } if (k == ARRAY_SIZE(formats)) return NULL; return &formats[k];}struct sg_to_addr { int pos; struct scatterlist *sg;};/* buffer for one video frame */struct vivi_buffer { /* common v4l buffer stuff -- must be first */ struct videobuf_buffer vb; struct vivi_fmt *fmt;};struct vivi_dmaqueue { struct list_head active; /* thread for generating video stream*/ struct task_struct *kthread; wait_queue_head_t wq; /* Counters to control fps rate */ int frame; int ini_jiffies;};static LIST_HEAD(vivi_devlist);struct vivi_dev { struct list_head vivi_devlist; spinlock_t slock; struct mutex mutex; int users; /* various device info */ struct video_device *vfd; struct vivi_dmaqueue vidq; /* Several counters */ int h, m, s, ms; unsigned long jiffies; char timestr[13]; int mv_count; /* Controls bars movement */};struct vivi_fh { struct vivi_dev *dev; /* video capture */ struct vivi_fmt *fmt; unsigned int width, height; struct videobuf_queue vb_vidq; enum v4l2_buf_type type; unsigned char bars[8][3];};/* ------------------------------------------------------------------ DMA and thread functions ------------------------------------------------------------------*//* Bars and Colors should match positions */enum colors { WHITE, AMBAR, CYAN, GREEN, MAGENTA, RED, BLUE, BLACK,};static u8 bars[8][3] = { /* R G B */ {204, 204, 204}, /* white */ {208, 208, 0}, /* ambar */ { 0, 206, 206}, /* cyan */ { 0, 239, 0}, /* green */ {239, 0, 239}, /* magenta */ {205, 0, 0}, /* red */ { 0, 0, 255}, /* blue */ { 0, 0, 0}, /* black */};#define TO_Y(r, g, b) \ (((16829 * r + 33039 * g + 6416 * b + 32768) >> 16) + 16)/* RGB to V(Cr) Color transform */#define TO_V(r, g, b) \ (((28784 * r - 24103 * g - 4681 * b + 32768) >> 16) + 128)/* RGB to U(Cb) Color transform */#define TO_U(r, g, b) \ (((-9714 * r - 19070 * g + 28784 * b + 32768) >> 16) + 128)#define TSTAMP_MIN_Y 24#define TSTAMP_MAX_Y TSTAMP_MIN_Y+15#define TSTAMP_MIN_X 64static void gen_twopix(struct vivi_fh *fh, unsigned char *buf, int colorpos){ unsigned char r_y, g_u, b_v; unsigned char *p; int color; r_y = fh->bars[colorpos][0]; /* R or precalculated Y */ g_u = fh->bars[colorpos][1]; /* G or precalculated U */ b_v = fh->bars[colorpos][2]; /* B or precalculated V */ for (color = 0; color < 4; color++) { p = buf + color; switch (fh->fmt->fourcc) { case V4L2_PIX_FMT_YUYV: switch (color) { case 0: case 2: *p = r_y; break; case 1: *p = g_u; break; case 3: *p = b_v; break; } break; case V4L2_PIX_FMT_UYVY: switch (color) { case 1: case 3: *p = r_y; break; case 0: *p = g_u; break; case 2: *p = b_v; break; } break; case V4L2_PIX_FMT_RGB565: switch (color) { case 0: case 2: *p = (g_u << 5) | b_v; break; case 1: case 3: *p = (r_y << 3) | (g_u >> 3); break; } break; case V4L2_PIX_FMT_RGB565X: switch (color) { case 0: case 2: *p = (r_y << 3) | (g_u >> 3); break; case 1: case 3: *p = (g_u << 5) | b_v; break; } break; case V4L2_PIX_FMT_RGB555: switch (color) { case 0: case 2: *p = (g_u << 5) | b_v; break; case 1: case 3: *p = (r_y << 2) | (g_u >> 3); break; } break; case V4L2_PIX_FMT_RGB555X: switch (color) { case 0: case 2: *p = (r_y << 2) | (g_u >> 3); break; case 1: case 3: *p = (g_u << 5) | b_v; break; } break; } }}static void gen_line(struct vivi_fh *fh, char *basep, int inipos, int wmax, int hmax, int line, int count, char *timestr){ int w, i, j; int pos = inipos; char *s; u8 chr; /* We will just duplicate the second pixel at the packet */ wmax /= 2; /* Generate a standard color bar pattern */ for (w = 0; w < wmax; w++) { int colorpos = ((w + count) * 8/(wmax + 1)) % 8; gen_twopix(fh, basep + pos, colorpos); pos += 4; /* only 16 bpp supported for now */ } /* Checks if it is possible to show timestamp */ if (TSTAMP_MAX_Y >= hmax) goto end; if (TSTAMP_MIN_X + strlen(timestr) >= wmax) goto end; /* Print stream time */ if (line >= TSTAMP_MIN_Y && line <= TSTAMP_MAX_Y) { j = TSTAMP_MIN_X; for (s = timestr; *s; s++) { chr = rom8x16_bits[(*s-0x30)*16+line-TSTAMP_MIN_Y]; for (i = 0; i < 7; i++) { pos = inipos + j * 2; /* Draw white font on black background */ if (chr & 1 << (7 - i)) gen_twopix(fh, basep + pos, WHITE); else gen_twopix(fh, basep + pos, BLACK); j++; } } }end: return;}static void vivi_fillbuff(struct vivi_fh *fh, struct vivi_buffer *buf){ struct vivi_dev *dev = fh->dev; int h , pos = 0; int hmax = buf->vb.height; int wmax = buf->vb.width; struct timeval ts; char *tmpbuf; void *vbuf = videobuf_to_vmalloc(&buf->vb); if (!vbuf) return; tmpbuf = kmalloc(wmax * 2, GFP_ATOMIC); if (!tmpbuf) return; for (h = 0; h < hmax; h++) { gen_line(fh, tmpbuf, 0, wmax, hmax, h, dev->mv_count, dev->timestr); memcpy(vbuf + pos, tmpbuf, wmax * 2); pos += wmax*2; } dev->mv_count++; kfree(tmpbuf);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -