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

📄 usbvideo.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * 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, 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. */#include <linux/kernel.h>#include <linux/sched.h>#include <linux/list.h>#include <linux/slab.h>#include <linux/module.h>#include <linux/mm.h>#include <linux/smp_lock.h>#include <linux/vmalloc.h>#include <linux/init.h>#include <linux/spinlock.h>#include <asm/io.h>#include "usbvideo.h"#if defined(MAP_NR)#define	virt_to_page(v)	MAP_NR(v)	/* Kernels 2.2.x */#endifstatic int video_nr = -1;module_param(video_nr, int, 0);/* * Local prototypes. */static void usbvideo_Disconnect(struct usb_interface *intf);static void usbvideo_CameraRelease(struct uvd *uvd);static int usbvideo_v4l_ioctl(struct inode *inode, struct file *file,			      unsigned int cmd, unsigned long arg);static int usbvideo_v4l_mmap(struct file *file, struct vm_area_struct *vma);static int usbvideo_v4l_open(struct inode *inode, struct file *file);static ssize_t usbvideo_v4l_read(struct file *file, char __user *buf,			     size_t count, loff_t *ppos);static int usbvideo_v4l_close(struct inode *inode, struct file *file);static int usbvideo_StartDataPump(struct uvd *uvd);static void usbvideo_StopDataPump(struct uvd *uvd);static int usbvideo_GetFrame(struct uvd *uvd, int frameNum);static int usbvideo_NewFrame(struct uvd *uvd, int framenum);static void usbvideo_SoftwareContrastAdjustment(struct uvd *uvd,						struct usbvideo_frame *frame);/*******************************//* Memory management functions *//*******************************/static void *usbvideo_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); /* Clear the ram out, no junk to the user */	adr = (unsigned long) mem;	while (size > 0) {		SetPageReserved(vmalloc_to_page((void *)adr));		adr += PAGE_SIZE;		size -= PAGE_SIZE;	}	return mem;}static void usbvideo_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 void RingQueue_Initialize(struct RingQueue *rq){	assert(rq != NULL);	init_waitqueue_head(&rq->wqh);}static void RingQueue_Allocate(struct RingQueue *rq, int rqLen){	/* Make sure the requested size is a power of 2 and	   round up if necessary. This allows index wrapping	   using masks rather than modulo */	int i = 1;	assert(rq != NULL);	assert(rqLen > 0);	while(rqLen >> i)		i++;	if(rqLen != 1 << (i-1))		rqLen = 1 << i;	rq->length = rqLen;	rq->ri = rq->wi = 0;	rq->queue = usbvideo_rvmalloc(rq->length);	assert(rq->queue != NULL);}static int RingQueue_IsAllocated(const struct RingQueue *rq){	if (rq == NULL)		return 0;	return (rq->queue != NULL) && (rq->length > 0);}static void RingQueue_Free(struct RingQueue *rq){	assert(rq != NULL);	if (RingQueue_IsAllocated(rq)) {		usbvideo_rvfree(rq->queue, rq->length);		rq->queue = NULL;		rq->length = 0;	}}int RingQueue_Dequeue(struct RingQueue *rq, unsigned char *dst, int len){	int rql, toread;	assert(rq != NULL);	assert(dst != NULL);	rql = RingQueue_GetLength(rq);	if(!rql)		return 0;	/* Clip requested length to available data */	if(len > rql)		len = rql;	toread = len;	if(rq->ri > rq->wi) {		/* Read data from tail */		int read = (toread < (rq->length - rq->ri)) ? toread : rq->length - rq->ri;		memcpy(dst, rq->queue + rq->ri, read);		toread -= read;		dst += read;		rq->ri = (rq->ri + read) & (rq->length-1);	}	if(toread) {		/* Read data from head */		memcpy(dst, rq->queue + rq->ri, toread);		rq->ri = (rq->ri + toread) & (rq->length-1);	}	return len;}EXPORT_SYMBOL(RingQueue_Dequeue);int RingQueue_Enqueue(struct RingQueue *rq, const unsigned char *cdata, int n){	int enqueued = 0;	assert(rq != NULL);	assert(cdata != NULL);	assert(rq->length > 0);	while (n > 0) {		int m, q_avail;		/* Calculate the largest chunk that fits the tail of the ring */		q_avail = rq->length - rq->wi;		if (q_avail <= 0) {			rq->wi = 0;			q_avail = rq->length;		}		m = n;		assert(q_avail > 0);		if (m > q_avail)			m = q_avail;		memcpy(rq->queue + rq->wi, cdata, m);		RING_QUEUE_ADVANCE_INDEX(rq, wi, m);		cdata += m;		enqueued += m;		n -= m;	}	return enqueued;}EXPORT_SYMBOL(RingQueue_Enqueue);static void RingQueue_InterruptibleSleepOn(struct RingQueue *rq){	assert(rq != NULL);	interruptible_sleep_on(&rq->wqh);}void RingQueue_WakeUpInterruptible(struct RingQueue *rq){	assert(rq != NULL);	if (waitqueue_active(&rq->wqh))		wake_up_interruptible(&rq->wqh);}EXPORT_SYMBOL(RingQueue_WakeUpInterruptible);void RingQueue_Flush(struct RingQueue *rq){	assert(rq != NULL);	rq->ri = 0;	rq->wi = 0;}EXPORT_SYMBOL(RingQueue_Flush);/* * usbvideo_VideosizeToString() * * This procedure converts given videosize value to readable string. * * History: * 07-Aug-2000 Created. * 19-Oct-2000 Reworked for usbvideo module. */static void usbvideo_VideosizeToString(char *buf, int bufLen, videosize_t vs){	char tmp[40];	int n;	n = 1 + sprintf(tmp, "%ldx%ld", VIDEOSIZE_X(vs), VIDEOSIZE_Y(vs));	assert(n < sizeof(tmp));	if ((buf == NULL) || (bufLen < n))		err("usbvideo_VideosizeToString: buffer is too small.");	else		memmove(buf, tmp, n);}/* * usbvideo_OverlayChar() * * History: * 01-Feb-2000 Created. */static void usbvideo_OverlayChar(struct uvd *uvd, struct usbvideo_frame *frame,				 int x, int y, int ch){	static const unsigned short digits[16] = {		0xF6DE, /* 0 */		0x2492, /* 1 */		0xE7CE, /* 2 */		0xE79E, /* 3 */		0xB792, /* 4 */		0xF39E, /* 5 */		0xF3DE, /* 6 */		0xF492, /* 7 */		0xF7DE, /* 8 */		0xF79E, /* 9 */		0x77DA, /* a */		0xD75C, /* b */		0xF24E, /* c */		0xD6DC, /* d */		0xF34E, /* e */		0xF348  /* f */	};	unsigned short digit;	int ix, iy;	if ((uvd == NULL) || (frame == NULL))		return;	if (ch >= '0' && ch <= '9')		ch -= '0';	else if (ch >= 'A' && ch <= 'F')		ch = 10 + (ch - 'A');	else if (ch >= 'a' && ch <= 'f')		ch = 10 + (ch - 'a');	else		return;	digit = digits[ch];	for (iy=0; iy < 5; iy++) {		for (ix=0; ix < 3; ix++) {			if (digit & 0x8000) {				if (uvd->paletteBits & (1L << VIDEO_PALETTE_RGB24)) {/* TODO */				RGB24_PUTPIXEL(frame, x+ix, y+iy, 0xFF, 0xFF, 0xFF);				}			}			digit = digit << 1;		}	}}/* * usbvideo_OverlayString() * * History: * 01-Feb-2000 Created. */static void usbvideo_OverlayString(struct uvd *uvd, struct usbvideo_frame *frame,				   int x, int y, const char *str){	while (*str) {		usbvideo_OverlayChar(uvd, frame, x, y, *str);		str++;		x += 4; /* 3 pixels character + 1 space */	}}/* * usbvideo_OverlayStats() * * Overlays important debugging information. * * History: * 01-Feb-2000 Created. */static void usbvideo_OverlayStats(struct uvd *uvd, struct usbvideo_frame *frame){	const int y_diff = 8;	char tmp[16];	int x = 10, y=10;	long i, j, barLength;	const int qi_x1 = 60, qi_y1 = 10;	const int qi_x2 = VIDEOSIZE_X(frame->request) - 10, qi_h = 10;	/* Call the user callback, see if we may proceed after that */	if (VALID_CALLBACK(uvd, overlayHook)) {		if (GET_CALLBACK(uvd, overlayHook)(uvd, frame) < 0)			return;	}	/*	 * We draw a (mostly) hollow rectangle with qi_xxx coordinates.	 * Left edge symbolizes the queue index 0; right edge symbolizes	 * the full capacity of the queue.	 */	barLength = qi_x2 - qi_x1 - 2;	if ((barLength > 10) && (uvd->paletteBits & (1L << VIDEO_PALETTE_RGB24))) {/* TODO */	long u_lo, u_hi, q_used;		long m_ri, m_wi, m_lo, m_hi;		/*		 * Determine fill zones (used areas of the queue):		 * 0 xxxxxxx u_lo ...... uvd->dp.ri xxxxxxxx u_hi ..... uvd->dp.length		 *		 * if u_lo < 0 then there is no first filler.		 */		q_used = RingQueue_GetLength(&uvd->dp);		if ((uvd->dp.ri + q_used) >= uvd->dp.length) {			u_hi = uvd->dp.length;			u_lo = (q_used + uvd->dp.ri) & (uvd->dp.length-1);		} else {			u_hi = (q_used + uvd->dp.ri);			u_lo = -1;		}		/* Convert byte indices into screen units */		m_ri = qi_x1 + ((barLength * uvd->dp.ri) / uvd->dp.length);		m_wi = qi_x1 + ((barLength * uvd->dp.wi) / uvd->dp.length);		m_lo = (u_lo > 0) ? (qi_x1 + ((barLength * u_lo) / uvd->dp.length)) : -1;		m_hi = qi_x1 + ((barLength * u_hi) / uvd->dp.length);		for (j=qi_y1; j < (qi_y1 + qi_h); j++) {			for (i=qi_x1; i < qi_x2; i++) {				/* Draw border lines */				if ((j == qi_y1) || (j == (qi_y1 + qi_h - 1)) ||				    (i == qi_x1) || (i == (qi_x2 - 1))) {					RGB24_PUTPIXEL(frame, i, j, 0xFF, 0xFF, 0xFF);					continue;				}				/* For all other points the Y coordinate does not matter */				if ((i >= m_ri) && (i <= (m_ri + 3))) {					RGB24_PUTPIXEL(frame, i, j, 0x00, 0xFF, 0x00);				} else if ((i >= m_wi) && (i <= (m_wi + 3))) {					RGB24_PUTPIXEL(frame, i, j, 0xFF, 0x00, 0x00);				} else if ((i < m_lo) || ((i > m_ri) && (i < m_hi)))					RGB24_PUTPIXEL(frame, i, j, 0x00, 0x00, 0xFF);			}		}	}	sprintf(tmp, "%8lx", uvd->stats.frame_num);	usbvideo_OverlayString(uvd, frame, x, y, tmp);	y += y_diff;	sprintf(tmp, "%8lx", uvd->stats.urb_count);	usbvideo_OverlayString(uvd, frame, x, y, tmp);	y += y_diff;	sprintf(tmp, "%8lx", uvd->stats.urb_length);	usbvideo_OverlayString(uvd, frame, x, y, tmp);	y += y_diff;	sprintf(tmp, "%8lx", uvd->stats.data_count);	usbvideo_OverlayString(uvd, frame, x, y, tmp);	y += y_diff;	sprintf(tmp, "%8lx", uvd->stats.header_count);	usbvideo_OverlayString(uvd, frame, x, y, tmp);	y += y_diff;	sprintf(tmp, "%8lx", uvd->stats.iso_skip_count);	usbvideo_OverlayString(uvd, frame, x, y, tmp);	y += y_diff;	sprintf(tmp, "%8lx", uvd->stats.iso_err_count);	usbvideo_OverlayString(uvd, frame, x, y, tmp);	y += y_diff;	sprintf(tmp, "%8x", uvd->vpic.colour);	usbvideo_OverlayString(uvd, frame, x, y, tmp);	y += y_diff;	sprintf(tmp, "%8x", uvd->vpic.hue);	usbvideo_OverlayString(uvd, frame, x, y, tmp);	y += y_diff;	sprintf(tmp, "%8x", uvd->vpic.brightness >> 8);	usbvideo_OverlayString(uvd, frame, x, y, tmp);	y += y_diff;	sprintf(tmp, "%8x", uvd->vpic.contrast >> 12);	usbvideo_OverlayString(uvd, frame, x, y, tmp);	y += y_diff;	sprintf(tmp, "%8d", uvd->vpic.whiteness >> 8);	usbvideo_OverlayString(uvd, frame, x, y, tmp);	y += y_diff;}/* * usbvideo_ReportStatistics() * * This procedure prints packet and transfer statistics. * * History: * 14-Jan-2000 Corrected default multiplier. */static void usbvideo_ReportStatistics(const struct uvd *uvd){	if ((uvd != NULL) && (uvd->stats.urb_count > 0)) {		unsigned long allPackets, badPackets, goodPackets, percent;		allPackets = uvd->stats.urb_count * CAMERA_URB_FRAMES;		badPackets = uvd->stats.iso_skip_count + uvd->stats.iso_err_count;		goodPackets = allPackets - badPackets;		/* Calculate percentage wisely, remember integer limits */		assert(allPackets != 0);		if (goodPackets < (((unsigned long)-1)/100))			percent = (100 * goodPackets) / allPackets;		else			percent = goodPackets / (allPackets / 100);		info("Packet Statistics: Total=%lu. Empty=%lu. Usage=%lu%%",		     allPackets, badPackets, percent);		if (uvd->iso_packet_len > 0) {			unsigned long allBytes, xferBytes;			char multiplier = ' ';			allBytes = allPackets * uvd->iso_packet_len;			xferBytes = uvd->stats.data_count;			assert(allBytes != 0);			if (xferBytes < (((unsigned long)-1)/100))				percent = (100 * xferBytes) / allBytes;			else				percent = xferBytes / (allBytes / 100);			/* Scale xferBytes for easy reading */			if (xferBytes > 10*1024) {				xferBytes /= 1024;				multiplier = 'K';				if (xferBytes > 10*1024) {					xferBytes /= 1024;					multiplier = 'M';					if (xferBytes > 10*1024) {						xferBytes /= 1024;						multiplier = 'G';						if (xferBytes > 10*1024) {							xferBytes /= 1024;							multiplier = 'T';						}					}				}			}			info("Transfer Statistics: Transferred=%lu%cB Usage=%lu%%",			     xferBytes, multiplier, percent);		}	}}/* * usbvideo_TestPattern() * * Procedure forms a test pattern (yellow grid on blue background). * * Parameters: * fullframe: if TRUE then entire frame is filled, otherwise the procedure *	      continues from the current scanline. * pmode      0: fill the frame with solid blue color (like on VCR or TV) *	      1: Draw a colored grid * * History: * 01-Feb-2000 Created. */void usbvideo_TestPattern(struct uvd *uvd, int fullframe, int pmode){	struct usbvideo_frame *frame;	int num_cell = 0;	int scan_length = 0;	static int num_pass = 0;	if (uvd == NULL) {		err("%s: uvd == NULL", __FUNCTION__);		return;	}	if ((uvd->curframe < 0) || (uvd->curframe >= USBVIDEO_NUMFRAMES)) {		err("%s: uvd->curframe=%d.", __FUNCTION__, uvd->curframe);		return;	}	/* Grab the current frame */	frame = &uvd->frame[uvd->curframe];	/* Optionally start at the beginning */	if (fullframe) {		frame->curline = 0;		frame->seqRead_Length = 0;	}#if 0	{	/* For debugging purposes only */		char tmp[20];		usbvideo_VideosizeToString(tmp, sizeof(tmp), frame->request);

⌨️ 快捷键说明

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