usbvision-core.c

来自「trident tm5600的linux驱动」· C语言 代码 · 共 2,344 行 · 第 1/5 页

C
2,344
字号
/* * usbvision-core.c - driver for NT100x USB video capture devices * * * Copyright (c) 1999-2005 Joerg Heckenbach <joerg@heckenbach-aw.de> *                         Dwaine Garden <dwainegarden@rogers.com> * * This module is part of usbvision driver project. * Updates to driver completed by Dwaine P. Garden * * 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. */#include <linux/kernel.h>#include <linux/list.h>#include <linux/timer.h>#include <linux/slab.h>#include <linux/mm.h>#include <linux/utsname.h>#include <linux/highmem.h>#include <linux/vmalloc.h>#include <linux/module.h>#include <linux/init.h>#include <linux/spinlock.h>#include <asm/io.h>#include <linux/videodev2.h>#include <linux/video_decoder.h>#include <linux/i2c.h>#include <media/saa7115.h>#include <media/v4l2-common.h>#include <media/tuner.h>#include <linux/workqueue.h>#include "usbvision.h"static unsigned int core_debug;module_param(core_debug,int,0644);MODULE_PARM_DESC(core_debug,"enable debug messages [core]");static unsigned int force_testpattern;module_param(force_testpattern,int,0644);MODULE_PARM_DESC(force_testpattern,"enable test pattern display [core]");static int adjustCompression = 1;	/* Set the compression to be adaptive */module_param(adjustCompression, int, 0444);MODULE_PARM_DESC(adjustCompression, " Set the ADPCM compression for the device.  Default: 1 (On)");/* To help people with Black and White output with using s-video input. * Some cables and input device are wired differently. */static int SwitchSVideoInput;module_param(SwitchSVideoInput, int, 0444);MODULE_PARM_DESC(SwitchSVideoInput, " Set the S-Video input.  Some cables and input device are wired differently. Default: 0 (Off)");static unsigned int adjust_X_Offset = -1;module_param(adjust_X_Offset, int, 0644);MODULE_PARM_DESC(adjust_X_Offset, "adjust X offset display [core]");static unsigned int adjust_Y_Offset = -1;module_param(adjust_Y_Offset, int, 0644);MODULE_PARM_DESC(adjust_Y_Offset, "adjust Y offset display [core]");#define	ENABLE_HEXDUMP	0	/* Enable if you need it */#ifdef USBVISION_DEBUG	#define PDEBUG(level, fmt, args...) { \		if (core_debug & (level)) \			printk(KERN_INFO KBUILD_MODNAME ":[%s:%d] " fmt, \				__func__, __LINE__ , ## args); \	}#else	#define PDEBUG(level, fmt, args...) do {} while(0)#endif#define DBG_HEADER	1<<0#define DBG_IRQ		1<<1#define DBG_ISOC	1<<2#define DBG_PARSE	1<<3#define DBG_SCRATCH	1<<4#define DBG_FUNC	1<<5static const int max_imgwidth = MAX_FRAME_WIDTH;static const int max_imgheight = MAX_FRAME_HEIGHT;static const int min_imgwidth = MIN_FRAME_WIDTH;static const int min_imgheight = MIN_FRAME_HEIGHT;/* The value of 'scratch_buf_size' affects quality of the picture * in many ways. Shorter buffers may cause loss of data when client * is too slow. Larger buffers are memory-consuming and take longer * to work with. This setting can be adjusted, but the default value * should be OK for most desktop users. */#define DEFAULT_SCRATCH_BUF_SIZE	(0x20000)		// 128kB memory scratch bufferstatic const int scratch_buf_size = DEFAULT_SCRATCH_BUF_SIZE;// Function prototypesstatic int usbvision_request_intra (struct usb_usbvision *usbvision);static int usbvision_unrequest_intra (struct usb_usbvision *usbvision);static int usbvision_adjust_compression (struct usb_usbvision *usbvision);static int usbvision_measure_bandwidth (struct usb_usbvision *usbvision);/*******************************//* Memory management functions *//*******************************//* * Here we want the physical address of the memory. * This is used when initializing the contents of the area. */static void *usbvision_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 usbvision_rvfree(void *mem, unsigned long size){	unsigned long adr;	if (!mem)		return;	size = PAGE_ALIGN(size);	adr = (unsigned long) mem;	while ((long) size > 0) {		ClearPageReserved(vmalloc_to_page((void *)adr));		adr += PAGE_SIZE;		size -= PAGE_SIZE;	}	vfree(mem);}#if ENABLE_HEXDUMPstatic void usbvision_hexdump(const unsigned char *data, int len){	char tmp[80];	int i, k;	for (i = k = 0; len > 0; i++, len--) {		if (i > 0 && (i % 16 == 0)) {			printk("%s\n", tmp);			k = 0;		}		k += sprintf(&tmp[k], "%02x ", data[i]);	}	if (k > 0)		printk("%s\n", tmp);}#endif/******************************** * scratch ring buffer handling ********************************/static int scratch_len(struct usb_usbvision *usbvision)    /*This returns the amount of data actually in the buffer */{	int len = usbvision->scratch_write_ptr - usbvision->scratch_read_ptr;	if (len < 0) {		len += scratch_buf_size;	}	PDEBUG(DBG_SCRATCH, "scratch_len() = %d\n", len);	return len;}/* This returns the free space left in the buffer */static int scratch_free(struct usb_usbvision *usbvision){	int free = usbvision->scratch_read_ptr - usbvision->scratch_write_ptr;	if (free <= 0) {		free += scratch_buf_size;	}	if (free) {		free -= 1;							/* at least one byte in the buffer must */										/* left blank, otherwise there is no chance to differ between full and empty */	}	PDEBUG(DBG_SCRATCH, "return %d\n", free);	return free;}/* This puts data into the buffer */static int scratch_put(struct usb_usbvision *usbvision, unsigned char *data,		       int len){	int len_part;	if (usbvision->scratch_write_ptr + len < scratch_buf_size) {		memcpy(usbvision->scratch + usbvision->scratch_write_ptr, data, len);		usbvision->scratch_write_ptr += len;	}	else {		len_part = scratch_buf_size - usbvision->scratch_write_ptr;		memcpy(usbvision->scratch + usbvision->scratch_write_ptr, data, len_part);		if (len == len_part) {			usbvision->scratch_write_ptr = 0;			/* just set write_ptr to zero */		}		else {			memcpy(usbvision->scratch, data + len_part, len - len_part);			usbvision->scratch_write_ptr = len - len_part;		}	}	PDEBUG(DBG_SCRATCH, "len=%d, new write_ptr=%d\n", len, usbvision->scratch_write_ptr);	return len;}/* This marks the write_ptr as position of new frame header */static void scratch_mark_header(struct usb_usbvision *usbvision){	PDEBUG(DBG_SCRATCH, "header at write_ptr=%d\n", usbvision->scratch_headermarker_write_ptr);	usbvision->scratch_headermarker[usbvision->scratch_headermarker_write_ptr] =				usbvision->scratch_write_ptr;	usbvision->scratch_headermarker_write_ptr += 1;	usbvision->scratch_headermarker_write_ptr %= USBVISION_NUM_HEADERMARKER;}/* This gets data from the buffer at the given "ptr" position */static int scratch_get_extra(struct usb_usbvision *usbvision,			     unsigned char *data, int *ptr, int len){	int len_part;	if (*ptr + len < scratch_buf_size) {		memcpy(data, usbvision->scratch + *ptr, len);		*ptr += len;	}	else {		len_part = scratch_buf_size - *ptr;		memcpy(data, usbvision->scratch + *ptr, len_part);		if (len == len_part) {			*ptr = 0;							/* just set the y_ptr to zero */		}		else {			memcpy(data + len_part, usbvision->scratch, len - len_part);			*ptr = len - len_part;		}	}	PDEBUG(DBG_SCRATCH, "len=%d, new ptr=%d\n", len, *ptr);	return len;}/* This sets the scratch extra read pointer */static void scratch_set_extra_ptr(struct usb_usbvision *usbvision, int *ptr,				  int len){	*ptr = (usbvision->scratch_read_ptr + len)%scratch_buf_size;	PDEBUG(DBG_SCRATCH, "ptr=%d\n", *ptr);}/*This increments the scratch extra read pointer */static void scratch_inc_extra_ptr(int *ptr, int len){	*ptr = (*ptr + len) % scratch_buf_size;	PDEBUG(DBG_SCRATCH, "ptr=%d\n", *ptr);}/* This gets data from the buffer */static int scratch_get(struct usb_usbvision *usbvision, unsigned char *data,		       int len){	int len_part;	if (usbvision->scratch_read_ptr + len < scratch_buf_size) {		memcpy(data, usbvision->scratch + usbvision->scratch_read_ptr, len);		usbvision->scratch_read_ptr += len;	}	else {		len_part = scratch_buf_size - usbvision->scratch_read_ptr;		memcpy(data, usbvision->scratch + usbvision->scratch_read_ptr, len_part);		if (len == len_part) {			usbvision->scratch_read_ptr = 0;				/* just set the read_ptr to zero */		}		else {			memcpy(data + len_part, usbvision->scratch, len - len_part);			usbvision->scratch_read_ptr = len - len_part;		}	}	PDEBUG(DBG_SCRATCH, "len=%d, new read_ptr=%d\n", len, usbvision->scratch_read_ptr);	return len;}/* This sets read pointer to next header and returns it */static int scratch_get_header(struct usb_usbvision *usbvision,			      struct usbvision_frame_header *header){	int errCode = 0;	PDEBUG(DBG_SCRATCH, "from read_ptr=%d", usbvision->scratch_headermarker_read_ptr);	while (usbvision->scratch_headermarker_write_ptr -		usbvision->scratch_headermarker_read_ptr != 0) {		usbvision->scratch_read_ptr =			usbvision->scratch_headermarker[usbvision->scratch_headermarker_read_ptr];		usbvision->scratch_headermarker_read_ptr += 1;		usbvision->scratch_headermarker_read_ptr %= USBVISION_NUM_HEADERMARKER;		scratch_get(usbvision, (unsigned char *)header, USBVISION_HEADER_LENGTH);		if ((header->magic_1 == USBVISION_MAGIC_1)			 && (header->magic_2 == USBVISION_MAGIC_2)			 && (header->headerLength == USBVISION_HEADER_LENGTH)) {			errCode = USBVISION_HEADER_LENGTH;			header->frameWidth  = header->frameWidthLo  + (header->frameWidthHi << 8);			header->frameHeight = header->frameHeightLo + (header->frameHeightHi << 8);			break;		}	}	return errCode;}/*This removes len bytes of old data from the buffer */static void scratch_rm_old(struct usb_usbvision *usbvision, int len){	usbvision->scratch_read_ptr += len;	usbvision->scratch_read_ptr %= scratch_buf_size;	PDEBUG(DBG_SCRATCH, "read_ptr is now %d\n", usbvision->scratch_read_ptr);}/*This resets the buffer - kills all data in it too */static void scratch_reset(struct usb_usbvision *usbvision){	PDEBUG(DBG_SCRATCH, "\n");	usbvision->scratch_read_ptr = 0;	usbvision->scratch_write_ptr = 0;	usbvision->scratch_headermarker_read_ptr = 0;	usbvision->scratch_headermarker_write_ptr = 0;	usbvision->isocstate = IsocState_NoFrame;}int usbvision_scratch_alloc(struct usb_usbvision *usbvision){	usbvision->scratch = vmalloc_32(scratch_buf_size);	scratch_reset(usbvision);	if(usbvision->scratch == NULL) {		err("%s: unable to allocate %d bytes for scratch",		    __func__, scratch_buf_size);		return -ENOMEM;	}	return 0;}void usbvision_scratch_free(struct usb_usbvision *usbvision){	if (usbvision->scratch != NULL) {		vfree(usbvision->scratch);		usbvision->scratch = NULL;	}}/* * usbvision_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 * */static void usbvision_testpattern(struct usb_usbvision *usbvision,				  int fullframe, int pmode){	static const char proc[] = "usbvision_testpattern";	struct usbvision_frame *frame;	unsigned char *f;	int num_cell = 0;	int scan_length = 0;	static int num_pass;	if (usbvision == NULL) {		printk(KERN_ERR "%s: usbvision == NULL\n", proc);		return;	}	if (usbvision->curFrame == NULL) {		printk(KERN_ERR "%s: usbvision->curFrame is NULL.\n", proc);		return;	}	/* Grab the current frame */	frame = usbvision->curFrame;	/* Optionally start at the beginning */	if (fullframe) {		frame->curline = 0;		frame->scanlength = 0;	}	/* Form every scan line */	for (; frame->curline < frame->frmheight; frame->curline++) {		int i;		f = frame->data + (usbvision->curwidth * 3 * frame->curline);		for (i = 0; i < usbvision->curwidth; i++) {			unsigned char cb = 0x80;			unsigned char cg = 0;			unsigned char cr = 0;			if (pmode == 1) {				if (frame->curline % 32 == 0)					cb = 0, cg = cr = 0xFF;				else if (i % 32 == 0) {					if (frame->curline % 32 == 1)						num_cell++;					cb = 0, cg = cr = 0xFF;				} else {					cb =					    ((num_cell * 7) +					     num_pass) & 0xFF;					cg =					    ((num_cell * 5) +					     num_pass * 2) & 0xFF;					cr =					    ((num_cell * 3) +					     num_pass * 3) & 0xFF;				}			} else {				/* Just the blue screen */			}

⌨️ 快捷键说明

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