⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vivi.c

📁 V4l driver for DVB HD
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * 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/videodev2.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/video-buf.h>#include <media/v4l2-common.h>#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)#include <linux/kthread.h>#endif#include <linux/highmem.h>/* Wake up at about 30 fps */#define WAKE_NUMERATOR 30#define WAKE_DENOMINATOR 1001#define BUFFER_TIMEOUT     msecs_to_jiffies(500)  /* 0.5 seconds *//* These timers are for 1 fps - used only for testing *///#define WAKE_DENOMINATOR 30 /* hack for testing purposes *///#define BUFFER_TIMEOUT     msecs_to_jiffies(5000)  /* 5 seconds */#include "font.h"#ifndef kzalloc#define kzalloc(size, flags)                            \({                                                      \	void *__ret = kmalloc(size, flags);             \	if (__ret)                                      \		memset(__ret, 0, size);                 \	__ret;                                          \})#endifMODULE_DESCRIPTION("Video Technology Magazine Virtual Video Capture Board");MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol");MODULE_LICENSE("Dual BSD/GPL");#define VIVI_MAJOR_VERSION 0#define VIVI_MINOR_VERSION 4#define VIVI_RELEASE 0#define VIVI_VERSION KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE)static int video_nr = -1;        /* /dev/videoN, -1 for autodetect */module_param(video_nr, int, 0);static int debug = 0;module_param(debug, int, 0);static unsigned int vid_limit = 16;module_param(vid_limit,int,0644);MODULE_PARM_DESC(vid_limit,"capture memory limit in megabytes");/* 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(level,fmt, arg...)			     \	do { 						     \		if (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 format = {	.name     = "4:2:2, packed, YUYV",	.fourcc   = V4L2_PIX_FMT_YUYV,	.depth    = 16,};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 sg_to_addr      *to_addr;};struct vivi_dmaqueue {	struct list_head       active;	struct list_head       queued;	struct timer_list      timeout;	/* thread for generating video stream*/	struct task_struct         *kthread;	wait_queue_head_t          wq;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)	struct semaphore           *notify;	int                        rmmod:1;#endif	/* Counters to control fps rate */	int                        frame;	int                        ini_jiffies;};static LIST_HEAD(vivi_devlist);struct vivi_dev {	struct list_head           vivi_devlist;	struct semaphore           lock;	int                        users;	/* various device info */	unsigned int               resources;	struct video_device        video_dev;	struct vivi_dmaqueue       vidq;	/* Several counters */	int                        h,m,s,us,jiffies;	char                       timestr[13];};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;};/* ------------------------------------------------------------------	DMA and thread functions   ------------------------------------------------------------------*//* Bars and Colors should match positions */enum colors {	WHITE,	AMBAR,	CYAN,	GREEN,	MAGENTA,	RED,	BLUE};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}};#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 64void prep_to_addr(struct sg_to_addr to_addr[],struct videobuf_buffer *vb){	int i, pos=0;	for (i=0;i<vb->dma.nr_pages;i++) {		to_addr[i].sg=&vb->dma.sglist[i];		to_addr[i].pos=pos;		pos += vb->dma.sglist[i].length;	}}inline int get_addr_pos(int pos, int pages, struct sg_to_addr to_addr[]){	int p1=0,p2=pages-1,p3=pages/2;	/* Sanity test */	BUG_ON (pos>=to_addr[p2].pos+to_addr[p2].sg->length);	while (p1+1<p2) {		if (pos < to_addr[p3].pos) {			p2=p3;		} else {			p1=p3;		}		p3=(p1+p2)/2;	}	if (pos >= to_addr[p2].pos)		p1=p2;	return (p1);}void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,					int hmax, int line, char *timestr){	int  w,i,j,pos=inipos,pgpos,oldpg,y;	char *p,*s,*basep;	struct page *pg;	u8   chr,r,g,b,color;	/* Get first addr pointed to pixel position */	oldpg=get_addr_pos(pos,pages,to_addr);	pg=pfn_to_page(to_addr[oldpg].sg->dma_address >> PAGE_SHIFT);	basep = kmap_atomic(pg, KM_BOUNCE_READ)+to_addr[oldpg].sg->offset;	/* We will just duplicate the second pixel at the packet */	wmax/=2;	/* Generate a standard color bar pattern */	for (w=0;w<wmax;w++) {		r=bars[w*7/wmax][0];		g=bars[w*7/wmax][1];		b=bars[w*7/wmax][2];		for (color=0;color<4;color++) {			pgpos=get_addr_pos(pos,pages,to_addr);			if (pgpos!=oldpg) {				pg=pfn_to_page(to_addr[pgpos].sg->dma_address >> PAGE_SHIFT);				kunmap_atomic(basep, KM_BOUNCE_READ);				basep= kmap_atomic(pg, KM_BOUNCE_READ)+to_addr[pgpos].sg->offset;				oldpg=pgpos;			}			p=basep+pos-to_addr[pgpos].pos;			switch (color) {				case 0:				case 2:					*p=TO_Y(r,g,b);		/* Luminance */					break;				case 1:					*p=TO_U(r,g,b);		/* Cb */					break;				case 3:					*p=TO_V(r,g,b);		/* Cr */					break;			}			pos++;		}	}	/* 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++) {				if (chr&1<<(7-i)) { /* Font color*/					r=bars[BLUE][0];					g=bars[BLUE][1];					b=bars[BLUE][2];					r=g=b=0;					g=198;				} else { /* Background color */					r=bars[WHITE][0];					g=bars[WHITE][1];					b=bars[WHITE][2];					r=g=b=0;				}				pos=inipos+j*2;				for (color=0;color<4;color++) {					pgpos=get_addr_pos(pos,pages,to_addr);					if (pgpos!=oldpg) {						pg=pfn_to_page(to_addr[pgpos].								sg->dma_address								>> PAGE_SHIFT);						kunmap_atomic(basep,								KM_BOUNCE_READ);						basep= kmap_atomic(pg,							KM_BOUNCE_READ)+							to_addr[pgpos].sg->offset;						oldpg=pgpos;					}					p=basep+pos-to_addr[pgpos].pos;					y=TO_Y(r,g,b);					switch (color) {						case 0:						case 2:							*p=TO_Y(r,g,b);		/* Luminance */							break;						case 1:							*p=TO_U(r,g,b);		/* Cb */							break;						case 3:							*p=TO_V(r,g,b);		/* Cr */							break;					}					pos++;				}				j++;			}		}	}#if 0 /* This will require a different logic */	/* Generate random noise */	if (line>6*hmax/7) {		if (line>6*hmax/7) {			p=get_addr_pos(inipos+j/2,pages,to_addr);//			get_random_bytes(buf+wmax-(wmax/7), wmax/7);			kunmap_atomic(p, KM_BOUNCE_READ);		}	}#endifend:	kunmap_atomic(basep, KM_BOUNCE_READ);}static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf){	int h,pos=0;	int hmax  = buf->vb.height;	int wmax  = buf->vb.width;	struct videobuf_buffer *vb=&buf->vb;	struct sg_to_addr *to_addr=buf->to_addr;	struct timeval ts;	/* Test if DMA mapping is ready */	if (!vb->dma.sglist[0].dma_address)		return;	prep_to_addr(to_addr,vb);	/* Check if there is enough memory */	BUG_ON(buf->vb.dma.nr_pages << PAGE_SHIFT < (buf->vb.width*buf->vb.height)*2);	for (h=0;h<hmax;h++) {		gen_line(to_addr,pos,vb->dma.nr_pages,wmax,hmax,h,dev->timestr);		pos += wmax*2;	}	/* Updates stream time */	dev->us+=jiffies_to_usecs(jiffies-dev->jiffies);	dev->jiffies=jiffies;	if (dev->us>=1000000) {		dev->us-=1000000;		dev->s++;		if (dev->s>=60) {			dev->s-=60;			dev->m++;			if (dev->m>60) {				dev->m-=60;				dev->h++;				if (dev->h>24)					dev->h-=24;			}		}	}	sprintf(dev->timestr,"%02d:%02d:%02d:%03d",			dev->h,dev->m,dev->s,(dev->us+500)/1000);	dprintk(2,"vivifill at %s: Buffer 0x%08lx size= %d\n",dev->timestr,			(unsigned long)buf->vb.dma.vmalloc,pos);	/* Advice that buffer was filled */	buf->vb.state = STATE_DONE;	buf->vb.field_count++;	do_gettimeofday(&ts);	buf->vb.ts = ts;	list_del(&buf->vb.queue);	wake_up(&buf->vb.done);}static int restart_video_queue(struct vivi_dmaqueue *dma_q);static void vivi_thread_tick(struct vivi_dmaqueue  *dma_q){	struct vivi_buffer    *buf;	struct vivi_dev *dev= container_of(dma_q,struct vivi_dev,vidq);	int bc;	/* Announces videobuf that all went ok */	for (bc = 0;; bc++) {		if (list_empty(&dma_q->active)) {			dprintk(1,"No active queue to serve\n");			break;		}		buf = list_entry(dma_q->active.next,				 struct vivi_buffer, vb.queue);		/* Nobody is waiting something to be done, just return */		if (!waitqueue_active(&buf->vb.done)) {			mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);			return;		}		do_gettimeofday(&buf->vb.ts);		dprintk(2,"[%p/%d] wakeup\n",buf,buf->vb.i);		/* Fill buffer */		vivi_fillbuff(dev,buf);	}	if (list_empty(&dma_q->active)) {		del_timer(&dma_q->timeout);	} else {		mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);	}	if (bc != 1)		dprintk(1,"%s: %d buffers handled (should be 1)\n",__FUNCTION__,bc);}void vivi_sleep(struct vivi_dmaqueue  *dma_q){	int timeout;	DECLARE_WAITQUEUE(wait, current);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -