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

📄 qcamvc.c

📁 VC编写的USB QuickCam驱动程序,实现四种视频格式在linux下的编码,信号来自摄像源
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * *    Connectix USB QuickCam VC Video Camera driver * *    Copyright 2001 De Marchi Daniele *    Copyright 2004 Terry Mohan *    Copyright 2005 Troy Rollo * *    This program is free software; you can redistribute it and/or *    modify it under the terms of the GNU General Public License as *    published by the Free Software Foundation; either version 2 of the *    License, or (at your option) any later version. * *    This program is distributed in the hope that it will be useful, but *    WITHOUT ANY WARRANTY; without even the implied warranty of *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU *    General Public License for more details. * *    You should have received a copy of the GNU General Public License *    along with this program; if not, write to the Free Software *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * *    Jan 2001 This driver develop started on the linux  *            kernel 2.4.0. * */#include <linux/config.h>#include <linux/version.h>#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0))#include <linux/wrapper.h>#endif#ifdef CONFIG_KMOD#include <linux/kmod.h>#endif#include <linux/proc_fs.h>#include <linux/vmalloc.h>#include <linux/fs.h>#include <linux/kernel.h>#include <linux/slab.h>#include <linux/mm.h>#include <linux/sched.h>#include <linux/ctype.h>#include <linux/parport.h>#include <linux/delay.h>#include "qcamvc.h"//*#define _QCAMVC_DEBUG_//#define CONFIG_VIDEO_QCAMVC_PP_MODULE//#undef CONFIG_PROC_FSstatic int video_nr = -1;#ifdef MODULEMODULE_PARM(video_nr,"i");MODULE_AUTHOR("De Marchi Daniele <demarchidaniele@libero.it>");MODULE_DESCRIPTION("V4L-driver for QuickCam VC cameras");MODULE_LICENSE("GPL");MODULE_SUPPORTED_DEVICE("video");#endif#ifdef CONFIG_VIDEO_QCAMVC_PPextern int qcamvc_pp_init(void);#endif#ifdef CONFIG_VIDEO_QCAMVC_USBextern int qcamvc_usb_init(void);#endifstatic int		qcamvc_vopen(struct inode *inode, struct file *file);static int		qcamvc_vrelease(struct inode *inode, struct file *file);static int		qcamvc_vioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);static ssize_t	qcamvc_vread(struct file *file, char *data, size_t count, loff_t *ppos);static int		qcamvc_vmmap(struct file *file, struct vm_area_struct *vma);static int		qcamvc_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg);static void		qcamvc_parse(struct qcamvc_data *qcamvc, unsigned char *outbuf);static int		qcamvc_camera_init(struct qcamvc_data *qcamvc);static struct file_operations qcamvc_fops ={	.owner		= THIS_MODULE,	.open		= qcamvc_vopen,	.release	= qcamvc_vrelease,	.ioctl		= qcamvc_vioctl,	.llseek		= no_llseek,	.read		= qcamvc_vread,	.mmap		= qcamvc_vmmap,};static struct video_device qcamvc_template ={	.name		= "UNSET",	.type		= VID_TYPE_CAPTURE,	.hardware	= VID_HARDWARE_QCAM_C,	.fops		= &qcamvc_fops,	.minor		= -1,};#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,10)  /* For kernel 2.6.10 and above -- Vikram */ int remap_pfn_range(struct vm_area_struct *vma, unsigned long uvaddr, 		  unsigned long pfn, unsigned long size, pgprot_t prot);   static inline int remap_page_range(struct vm_area_struct *vma, 				unsigned long uvaddr, 				unsigned long paddr, 				unsigned long size, pgprot_t prot) { 	return remap_pfn_range(vma, uvaddr, paddr >> PAGE_SHIFT, size, prot); } #endif /********************************************************************** * * Memory management * **********************************************************************//* Here we want the physical address of the memory. * This is used when initializing the contents of the area. */static inline unsigned long kvirt_to_pa(unsigned long adr){	unsigned long kva, ret;	kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));	kva |= adr & (PAGE_SIZE-1);	ret = __pa(kva);	return ret;}static void *rvmalloc(unsigned long size){	void *mem;	unsigned long adr;	size = PAGE_ALIGN(size);	mem = vmalloc_32(size);	if (!mem)		return NULL;	memset(mem, 0, size);	adr = (unsigned long) mem;	while (size > 0) {		SetPageReserved(vmalloc_to_page((void *)adr));		adr += PAGE_SIZE;		size -= PAGE_SIZE;	}	return mem;}static void rvfree(void *mem, unsigned long size){	unsigned long adr;	if (!mem)		return;	adr = (unsigned long) mem;	while ((long) size > 0) {		ClearPageReserved(vmalloc_to_page((void *)adr));		adr += PAGE_SIZE;		size -= PAGE_SIZE;	}	vfree(mem);}static inline int allocate_raw_frame(struct qcamvc_data *qcamvc){	if (!qcamvc)		return -EFAULT;		if (!qcamvc->raw_frame)	{		qcamvc->raw_frame = kmalloc(MAX_RAW_IMAGE_SIZE, GFP_KERNEL);		if (!qcamvc->raw_frame)			return -ENOBUFS;	}		/*if ( (qcamvc->bpc == 6) && !qcamvc->raw_frame_temp )	{		qcamvc->raw_frame_temp = kmalloc(MAX_RAW_IMAGE_SIZE, GFP_KERNEL);		if (!qcamvc->raw_frame_temp)			return -ENOBUFS;	}*/	return 0;}static void free_raw_frame(struct qcamvc_data *qcamvc){	if (!qcamvc) return;		if (qcamvc->raw_frame)	{		kfree(qcamvc->raw_frame);		qcamvc->raw_frame = NULL;	}	/*if (qcamvc->raw_frame_temp)	{		kfree(qcamvc->raw_frame_temp);		qcamvc->raw_frame_temp = NULL;	}*/}static inline int allocate_frame_buf(struct qcamvc_data *qcamvc){	if (!qcamvc) return -EFAULT;	if (qcamvc->frame_buf) return 0; //already allocated	/* tries to allocate all the memory needed for frame buffers */	qcamvc->frame_buf = rvmalloc(QCAMVC_NUMFRAMES * MAX_FRAME_SIZE);	if (!qcamvc->frame_buf)		return -ENOBUFS;	int i;	for (i = 0; i < QCAMVC_NUMFRAMES; i++)	{		/* stores the starting addresses of each frame buffer in the		qcamvc->frame_buf */		qcamvc->frame[i].data = qcamvc->frame_buf + i * MAX_FRAME_SIZE;		qcamvc->frame[i].state = FRAME_READY;	}		return 0;}static void free_frame_buf(struct qcamvc_data *qcamvc){	if (!qcamvc) return;		if (qcamvc->frame_buf)	{		rvfree(qcamvc->frame_buf, QCAMVC_NUMFRAMES * MAX_FRAME_SIZE);		qcamvc->frame_buf = NULL;	}	int i;	for (i=0; i < QCAMVC_NUMFRAMES; i++)	{		qcamvc->frame[i].state = FRAME_UNUSED;		qcamvc->frame[i].data = NULL;	}}/********************************************************************** * * Camera Address Read/Write helpers * **********************************************************************/static int get_register(struct qcamvc_data *qcamvc, unsigned char reg, unsigned char *buf){	if (!qcamvc || !qcamvc->ops || !buf) return -1;	if (qcamvc->ops->qcamvc_get_reg(qcamvc->lowlevel_data, reg, buf, 1) != 1)		return -1;			return 0;}static int set_register(struct qcamvc_data *qcamvc, unsigned char reg, unsigned char buf){	if (!qcamvc || !qcamvc->ops) return -1;	if (qcamvc->ops->qcamvc_set_reg(qcamvc->lowlevel_data, reg, &buf, 1) != 1)		return -1;			return 0;}static int set_registers(struct qcamvc_data *qcamvc, unsigned char reg, unsigned char *buf, size_t size){	if (!qcamvc || !qcamvc->ops || !buf) return -1;	if (qcamvc->ops->qcamvc_set_reg(qcamvc->lowlevel_data, reg, buf, size) != size)		return -1;			return 0;}/********************************************************************** * * Image Grabbing * **********************************************************************/static int send_grab_image(struct qcamvc_data *qcamvc, int new_frame){	if (new_frame)		qcamvc->frame_count++; /*fresh frame */		if (set_register(qcamvc, QCAM_VC_GET_FRAME, qcamvc->frame_count))		return -ENODEV;		return 0;} /* interrogate the camera every 10ms while waiting for an image to be ready. *//* return 0 not ready, or >0 ready */static int frame_is_ready(struct qcamvc_data *qcamvc){#if 0	if (!qcamvc) return 0;	struct qcamvc_misc misc = {0};	int attempt = 200; /* 2 second timeout should be plenty */	/* send grab frame command with current frame count */	if (send_grab_image(qcamvc, 0))		return 0;		do	{		if (!get_register(qcamvc, QCAM_VC_SET_MISC, (unsigned char*)&misc))		{			/* bit 8 of MISC register is set if the camera has finished capturing a frame */			if (misc.frame_ready)			{				break;			}		}		else		{			/* failed reading from the camera. can't do much else here. */			return 0;		}		/* sleep 10ms. ie. about 1/3 of the time it takes to snap an image at 30fps */		__set_current_state (TASK_INTERRUPTIBLE);		schedule_timeout ((HZ + 99) / 100);		if (signal_pending (current))		{			return 0;		}	}while (--attempt);		return attempt;#else	return 1;#endif}/* gets a single raw frame from the camera - waits for it if necessary */static int get_raw_frame(struct qcamvc_data *qcamvc){ 	if (!qcamvc || !qcamvc->ops)		return -EINVAL;	unsigned long oldjif, rate, diff;	int err;	size_t size;	if ( (err=allocate_raw_frame(qcamvc)) )		return err;	oldjif = jiffies;		/* wait for it to become ready */	if (!frame_is_ready(qcamvc))	{ /* about 2 secounds has elapsed without the camera telling us a frame is ready... */		printk("Camera timed-out while grabbing frame #%d.\n", qcamvc->frame_count);		return -ENODEV;	}	/* now suck the image data from the camera */	if (set_register(qcamvc, QCAM_VC_GET_FRAME, qcamvc->frame_count))		return -ENODEV;		size = qcamvc->ops->qcamvc_stream_read(qcamvc->lowlevel_data, qcamvc->raw_frame, qcamvc->packet_len);	if (size == 0)	{		printk("Failed to read frame #%d from the camera.\n", qcamvc->frame_count);		return -1;	}	/* calc frame rate */	rate = qcamvc->packet_len * HZ / 1024;	diff = jiffies-oldjif;	qcamvc->transfer_rate = diff==0 ? rate : rate/diff;	return size;}/* V4L capture frame using mmap double buffering */static int capture_frame(struct qcamvc_data *qcamvc, int frame){	if (frame < 0 || frame >= QCAMVC_NUMFRAMES)		return -EINVAL;		qcamvc->curframe = frame;	if (qcamvc->frame[qcamvc->curframe].state == FRAME_READY)	{		/* nothing queued... send grab frame to camera now */		if (!qcamvc->frame_waiting)		{			if (send_grab_image(qcamvc, 1))				return -ENODEV;		}		else		{			/* queue this so that it can be captured immediately next */			qcamvc->frame_waiting++;		}				qcamvc->frame[qcamvc->curframe].state = FRAME_GRABBING;	}	else if (qcamvc->frame[qcamvc->curframe].state == FRAME_GRABBING)	{		int count = get_raw_frame(qcamvc);		/* send grab frame now for next frame */		if (qcamvc->frame_waiting)		{			qcamvc->frame_waiting--;			send_grab_image(qcamvc, 1);		}		if (count < 0)		{			qcamvc->frame_waiting = 0; /* clear queue on errors */			qcamvc->frame[qcamvc->curframe].state = FRAME_READY;			return count;		}				qcamvc_parse(qcamvc, qcamvc->frame[qcamvc->curframe].data);		qcamvc->frame[qcamvc->curframe].state = FRAME_DONE;	}	return 0;}/********************************************************************** * * Camera Settings * **********************************************************************/static inline void make_valid_res(int *width, int *height){	if (*width > MAX_WIDTH) *width = MAX_WIDTH;	else if (*width < MIN_WIDTH) *width = MIN_WIDTH;		if (*height > MAX_HEIGHT) *height = MAX_HEIGHT;	else if (*height < MIN_HEIGHT) *height = MIN_HEIGHT;} static inline int res_changed(struct qcamvc_data *qcamvc, int width, int height){	if (!qcamvc) return 0;		if (qcamvc->width != width) return 1;	if (qcamvc->height != height) return 1;	return 0;}static inline int valid_res(int width, int height){	if (width > MAX_WIDTH) return 0;	else if (width < MIN_WIDTH) return 0;		if (height > MAX_HEIGHT) return 0;	else if (height < MIN_HEIGHT) return 0;		return 1;}static int mode_depth(__u32 mode){	switch (mode)	{	case V4L2_PIX_FMT_RGB24:	case V4L2_PIX_FMT_BGR24:		return 24;	case V4L2_PIX_FMT_RGB32:	case V4L2_PIX_FMT_BGR32:		return 32;	case V4L2_PIX_FMT_RGB555:	case V4L2_PIX_FMT_RGB565:		return 16;	case V4L2_PIX_FMT_GREY:		return 8;	case V4L2_PIX_FMT_YUYV:	case V4L2_PIX_FMT_UYVY:		return 16;	}	return 0;}static int mode_bpc(__u32 mode){	switch (mode)	{	case V4L2_PIX_FMT_RGB555:	case V4L2_PIX_FMT_RGB565:		return 6;	}	return 8;}static enum v4l2_colorspace mode_colorspace(__u32 mode){	switch (mode)	{	case V4L2_PIX_FMT_RGB24:	case V4L2_PIX_FMT_BGR24:	case V4L2_PIX_FMT_RGB32:	case V4L2_PIX_FMT_BGR32:	case V4L2_PIX_FMT_RGB555:	case V4L2_PIX_FMT_RGB565:		return V4L2_COLORSPACE_SRGB;	case V4L2_PIX_FMT_GREY:	case V4L2_PIX_FMT_YUYV:	case V4L2_PIX_FMT_UYVY:		return V4L2_COLORSPACE_SMPTE170M;	}	return 0;}/* calculate the CCD area rows & cols, return final width and height */static unsigned int calc_CCD_area(int width, int height, struct qcamvc_ccd_area *ccd_area){	if (!ccd_area) return 0;		/* allow only even number of row/columns */	width &= ~1;	height &= ~1;		ccd_area->multiplier = 0;		/* sane values for width & height */	make_valid_res(&width, &height);		/* anything over 176x144 will be doubled by the camera */	if ( (width > 176) || (height > 144) )	{		ccd_area->multiplier = 1;		width = width >> 1;		height = height >> 1;		make_valid_res(&width, &height);	}		/* width center point is 180/2, +2 because of the left two optically black CCD cells */	ccd_area->first_col = 92 - (width >> 1);	ccd_area->last_col = ccd_area->first_col + width;		/* height center point is 144/2, +1 because of 1's based rows */	/* camera divides the start row when the height is multiplied, so double it here */	ccd_area->first_row = (73 - (height >> 1)) << ccd_area->multiplier;	ccd_area->last_row = ccd_area->first_row + height;		/* save the new width and height for no particular reason */	ccd_area->width = width << ccd_area->multiplier;	ccd_area->height = height << ccd_area->multiplier;	return ((width << 8)|(height));}/* calculate the packet size for the current image size & bpc */static inline int calc_packetlength(struct qcamvc_data *qcamvc, int bpc){	if (!qcamvc) return 0; /* let's not panic */		/* plus 2 is for the two packet length bytes at the start of the image data */	int pl = ((qcamvc->width * qcamvc->height * bpc) / 8) + 64;		if (pl > MAX_PACKET_LENGTH)	{ // this should never happen		pl = MAX_PACKET_LENGTH;	}		return pl;}/* raw is a pointer to the start of raw image data */static inline int header_packetlength(unsigned char *raw){	if (!raw) return 0;		/* the pl in raw data header is half the actual packet length. so x2. */	int pl = (int)(((int)raw[1] << 8) | raw[0]) * 2;	if (pl > MAX_PACKET_LENGTH)	{ // bad raw packet received?		return 0;	}		return pl;}/* raw is a pointer to the start of raw image data. packetsize to verify. */static inline int valid_packet(unsigned char *raw, int packetSize){	if (!raw) return 0;		return ( header_packetlength(raw) == packetSize );}static int qcamvc_set_ccd_area(struct qcamvc_data *qcamvc){	if (!qcamvc) return -1;	

⌨️ 快捷键说明

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