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

📄 stv680.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *  STV0680 USB Camera Driver, by Kevin Sisson (kjsisson@bellsouth.net) *   * Thanks to STMicroelectronics for information on the usb commands, and  * to Steve Miller at STM for his help and encouragement while I was  * writing this driver. * * This driver is based heavily on the  * Endpoints (formerly known as AOX) se401 USB Camera Driver * Copyright (c) 2000 Jeroen B. Vreeken (pe1rxq@amsat.org) * * Still somewhat based on the Linux ov511 driver. *  * 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. * * History:  * ver 0.1 October, 2001. Initial attempt.  * * ver 0.2 November, 2001. Fixed asbility to resize, added brightness *                         function, made more stable (?) * * ver 0.21 Nov, 2001.     Added gamma correction and white balance,  *                         due to Alexander Schwartz. Still trying to  *                         improve stablility. Moved stuff into stv680.h * * ver 0.22 Nov, 2001.	   Added sharpen function (by Michael Sweet,  *                         mike@easysw.com) from GIMP, also used in pencam.  *                         Simple, fast, good integer math routine. * * ver 0.23 Dec, 2001 (gkh) * 			   Took out sharpen function, ran code through * 			   Lindent, and did other minor tweaks to get * 			   things to work properly with 2.5.1 * * ver 0.24 Jan, 2002 (kjs)  *                         Fixed the problem with webcam crashing after *                         two pictures. Changed the way pic is halved to  *                         improve quality. Got rid of green line around  *                         frame. Fix brightness reset when changing size  *                         bug. Adjusted gamma filters slightly. * * ver 0.25 Jan, 2002 (kjs) *			   Fixed a bug in which the driver sometimes attempted *			   to set to a non-supported size. This allowed *			   gnomemeeting to work. *			   Fixed proc entry removal bug. */#include <linux/config.h>#include <linux/module.h>#include <linux/init.h>#include <linux/vmalloc.h>#include <linux/slab.h>#include <linux/pagemap.h>#include <linux/errno.h>#include <linux/videodev.h>#include <linux/usb.h>#include "stv680.h"static int video_nr = -1;static int swapRGB = 0;   /* default for auto sleect */static int swapRGB_on = 0; /* default to allow auto select; -1=swap never, +1= swap always */static unsigned int debug = 0;#define PDEBUG(level, fmt, args...) \	do { \	if (debug >= level)	\		info("[%s:%d] " fmt, __FUNCTION__, __LINE__ , ## args);	\	} while (0)/* * Version Information */#define DRIVER_VERSION "v0.25"#define DRIVER_AUTHOR "Kevin Sisson <kjsisson@bellsouth.net>"#define DRIVER_DESC "STV0680 USB Camera Driver"MODULE_AUTHOR (DRIVER_AUTHOR);MODULE_DESCRIPTION (DRIVER_DESC);MODULE_LICENSE ("GPL");module_param(debug, int, S_IRUGO | S_IWUSR);MODULE_PARM_DESC (debug, "Debug enabled or not");module_param(swapRGB_on, int, 0);MODULE_PARM_DESC (swapRGB_on, "Red/blue swap: 1=always, 0=auto, -1=never");module_param(video_nr, int, 0);/******************************************************************** * * Memory management * * This is a shameless copy from the USB-cpia driver (linux kernel * version 2.3.29 or so, I have no idea what this code actually does ;). * Actually it seems to be a copy of a shameless copy of the bttv-driver. * Or that is a copy of a shameless copy of ... (To the powers: is there * no generic kernel-function to do this sort of stuff?) * * Yes, it was a shameless copy from the bttv-driver. IIRC, Alan says * there will be one, but apparentely not yet -jerdfelt * * So I copied it again for the ov511 driver -claudio * * Same for the se401 driver -Jeroen * * And the STV0680 driver - Kevin ********************************************************************/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);	/* 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 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);}/********************************************************************* * pencam read/write functions ********************************************************************/static int stv_sndctrl (int set, struct usb_stv *stv680, unsigned short req, unsigned short value, unsigned char *buffer, int size){	int ret = -1;	switch (set) {	case 0:		/*  0xc1  */		ret = usb_control_msg (stv680->udev,				       usb_rcvctrlpipe (stv680->udev, 0),				       req,				       (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT),				       value, 0, buffer, size, PENCAM_TIMEOUT);		break;	case 1:		/*  0x41  */		ret = usb_control_msg (stv680->udev,				       usb_sndctrlpipe (stv680->udev, 0),				       req,				       (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT),				       value, 0, buffer, size, PENCAM_TIMEOUT);		break;	case 2:		/*  0x80  */		ret = usb_control_msg (stv680->udev,				       usb_rcvctrlpipe (stv680->udev, 0),				       req,				       (USB_DIR_IN | USB_RECIP_DEVICE),				       value, 0, buffer, size, PENCAM_TIMEOUT);		break;	case 3:		/*  0x40  */		ret = usb_control_msg (stv680->udev,				       usb_sndctrlpipe (stv680->udev, 0),				       req,				       (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE),				       value, 0, buffer, size, PENCAM_TIMEOUT);		break;	}	if ((ret < 0) && (req != 0x0a)) {		PDEBUG (1, "STV(e): usb_control_msg error %i, request = 0x%x, error = %i", set, req, ret);	}	return ret;}static int stv_set_config (struct usb_stv *dev, int configuration, int interface, int alternate){	if (configuration != dev->udev->actconfig->desc.bConfigurationValue			|| usb_reset_configuration (dev->udev) < 0) {		PDEBUG (1, "STV(e): FAILED to reset configuration %i", configuration);		return -1;	}	if (usb_set_interface (dev->udev, interface, alternate) < 0) {		PDEBUG (1, "STV(e): FAILED to set alternate interface %i", alternate);		return -1;	}	return 0;}static int stv_stop_video (struct usb_stv *dev){	int i;	unsigned char *buf;	buf = kmalloc (40, GFP_KERNEL);	if (buf == NULL) {		PDEBUG (0, "STV(e): Out of (small buf) memory");		return -1;	}	/* this is a high priority command; it stops all lower order commands */	if ((i = stv_sndctrl (1, dev, 0x04, 0x0000, buf, 0x0)) < 0) {		i = stv_sndctrl (0, dev, 0x80, 0, buf, 0x02);	/* Get Last Error; 2 = busy */		PDEBUG (1, "STV(i): last error: %i,  command = 0x%x", buf[0], buf[1]);	} else {		PDEBUG (1, "STV(i): Camera reset to idle mode.");	}	if ((i = stv_set_config (dev, 1, 0, 0)) < 0)		PDEBUG (1, "STV(e): Reset config during exit failed");	/*  get current mode  */	buf[0] = 0xf0;	if ((i = stv_sndctrl (0, dev, 0x87, 0, buf, 0x08)) != 0x08)	/* get mode */		PDEBUG (0, "STV(e): Stop_video: problem setting original mode");	if (dev->origMode != buf[0]) {		memset (buf, 0, 8);		buf[0] = (unsigned char) dev->origMode;		if ((i = stv_sndctrl (3, dev, 0x07, 0x0100, buf, 0x08)) != 0x08) {			PDEBUG (0, "STV(e): Stop_video: Set_Camera_Mode failed");			i = -1;		}		buf[0] = 0xf0;		i = stv_sndctrl (0, dev, 0x87, 0, buf, 0x08);		if ((i != 0x08) || (buf[0] != dev->origMode)) {			PDEBUG (0, "STV(e): camera NOT set to original resolution.");			i = -1;		} else			PDEBUG (0, "STV(i): Camera set to original resolution");	}	/* origMode */	kfree(buf);	return i;}static int stv_set_video_mode (struct usb_stv *dev){	int i, stop_video = 1;	unsigned char *buf;	buf = kmalloc (40, GFP_KERNEL);	if (buf == NULL) {		PDEBUG (0, "STV(e): Out of (small buf) memory");		return -1;	}	if ((i = stv_set_config (dev, 1, 0, 0)) < 0) {		kfree(buf);		return i;	}	i = stv_sndctrl (2, dev, 0x06, 0x0100, buf, 0x12);	if (!(i > 0) && (buf[8] == 0x53) && (buf[9] == 0x05)) {		PDEBUG (1, "STV(e): Could not get descriptor 0100.");		goto error;	}	/*  set alternate interface 1 */	if ((i = stv_set_config (dev, 1, 0, 1)) < 0)		goto error;	if ((i = stv_sndctrl (0, dev, 0x85, 0, buf, 0x10)) != 0x10)		goto error;	PDEBUG (1, "STV(i): Setting video mode.");	/*  Switch to Video mode: 0x0100 = VGA (640x480), 0x0000 = CIF (352x288) 0x0300 = QVGA (320x240)  */	if ((i = stv_sndctrl (1, dev, 0x09, dev->VideoMode, buf, 0x0)) < 0) {		stop_video = 0;		goto error;	}	goto exit;error:	kfree(buf);	if (stop_video == 1)		stv_stop_video (dev);	return -1;exit:	kfree(buf);	return 0;}static int stv_init (struct usb_stv *stv680){	int i = 0;	unsigned char *buffer;	unsigned long int bufsize;	buffer = kmalloc (40, GFP_KERNEL);	if (buffer == NULL) {		PDEBUG (0, "STV(e): Out of (small buf) memory");		return -1;	}	memset (buffer, 0, 40);	udelay (100);	/* set config 1, interface 0, alternate 0 */	if ((i = stv_set_config (stv680, 1, 0, 0)) < 0) {		kfree(buffer);		PDEBUG (0, "STV(e): set config 1,0,0 failed");		return -1;	}	/* ping camera to be sure STV0680 is present */	if ((i = stv_sndctrl (0, stv680, 0x88, 0x5678, buffer, 0x02)) != 0x02)		goto error;	if ((buffer[0] != 0x56) || (buffer[1] != 0x78)) {		PDEBUG (1, "STV(e): camera ping failed!!");		goto error;	}	/* get camera descriptor */	if ((i = stv_sndctrl (2, stv680, 0x06, 0x0200, buffer, 0x09)) != 0x09)		goto error;	i = stv_sndctrl (2, stv680, 0x06, 0x0200, buffer, 0x22);	if (!(i >= 0) && (buffer[7] == 0xa0) && (buffer[8] == 0x23)) {		PDEBUG (1, "STV(e): Could not get descriptor 0200.");		goto error;	}	if ((i = stv_sndctrl (0, stv680, 0x8a, 0, buffer, 0x02)) != 0x02)		goto error;	if ((i = stv_sndctrl (0, stv680, 0x8b, 0, buffer, 0x24)) != 0x24)		goto error;	if ((i = stv_sndctrl (0, stv680, 0x85, 0, buffer, 0x10)) != 0x10)		goto error;	stv680->SupportedModes = buffer[7];	i = stv680->SupportedModes;	stv680->CIF = 0;	stv680->VGA = 0;	stv680->QVGA = 0;	if (i & 1)		stv680->CIF = 1;	if (i & 2)		stv680->VGA = 1;	if (i & 8)		stv680->QVGA = 1;	if (stv680->SupportedModes == 0) {		PDEBUG (0, "STV(e): There are NO supported STV680 modes!!");		i = -1;		goto error;	} else {		if (stv680->CIF)			PDEBUG (0, "STV(i): CIF is supported");		if (stv680->QVGA)			PDEBUG (0, "STV(i): QVGA is supported");	}	/* FW rev, ASIC rev, sensor ID  */	PDEBUG (1, "STV(i): Firmware rev is %i.%i", buffer[0], buffer[1]);	PDEBUG (1, "STV(i): ASIC rev is %i.%i", buffer[2], buffer[3]);	PDEBUG (1, "STV(i): Sensor ID is %i", (buffer[4]*16) + (buffer[5]>>4));	/*  set alternate interface 1 */	if ((i = stv_set_config (stv680, 1, 0, 1)) < 0)		goto error;	if ((i = stv_sndctrl (0, stv680, 0x85, 0, buffer, 0x10)) != 0x10)		goto error;	if ((i = stv_sndctrl (0, stv680, 0x8d, 0, buffer, 0x08)) != 0x08)		goto error;	i = buffer[3];	PDEBUG (0, "STV(i): Camera has %i pictures.", i);	/*  get current mode */	if ((i = stv_sndctrl (0, stv680, 0x87, 0, buffer, 0x08)) != 0x08)		goto error;	stv680->origMode = buffer[0];	/* 01 = VGA, 03 = QVGA, 00 = CIF */	/* This will attemp CIF mode, if supported. If not, set to QVGA  */	memset (buffer, 0, 8);	if (stv680->CIF)		buffer[0] = 0x00;	else if (stv680->QVGA)		buffer[0] = 0x03;	if ((i = stv_sndctrl (3, stv680, 0x07, 0x0100, buffer, 0x08)) != 0x08) {		PDEBUG (0, "STV(i): Set_Camera_Mode failed");		i = -1;		goto error;	}	buffer[0] = 0xf0;	stv_sndctrl (0, stv680, 0x87, 0, buffer, 0x08);	if (((stv680->CIF == 1) && (buffer[0] != 0x00)) || ((stv680->QVGA == 1) && (buffer[0] != 0x03))) {		PDEBUG (0, "STV(e): Error setting camera video mode!");		i = -1;		goto error;	} else {		if (buffer[0] == 0) {			stv680->VideoMode = 0x0000;			PDEBUG (0, "STV(i): Video Mode set to CIF");		}		if (buffer[0] == 0x03) {			stv680->VideoMode = 0x0300;			PDEBUG (0, "STV(i): Video Mode set to QVGA");		}	}	if ((i = stv_sndctrl (0, stv680, 0x8f, 0, buffer, 0x10)) != 0x10)		goto error;	bufsize = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | (buffer[3]);	stv680->cwidth = (buffer[4] << 8) | (buffer[5]);	/* ->camera = 322, 356, 644  */	stv680->cheight = (buffer[6] << 8) | (buffer[7]);	/* ->camera = 242, 292, 484  */	stv680->origGain = buffer[12];	goto exit;error:	i = stv_sndctrl (0, stv680, 0x80, 0, buffer, 0x02);	/* Get Last Error */	PDEBUG (1, "STV(i): last error: %i,  command = 0x%x", buffer[0], buffer[1]);	kfree(buffer);	return -1;exit:	kfree(buffer);	/* video = 320x240, 352x288 */	if (stv680->CIF == 1) {		stv680->maxwidth = 352;		stv680->maxheight = 288;		stv680->vwidth = 352;		stv680->vheight = 288;	}	if (stv680->QVGA == 1) {		stv680->maxwidth = 320;		stv680->maxheight = 240;		stv680->vwidth = 320;		stv680->vheight = 240;	}	stv680->rawbufsize = bufsize;	/* must be ./. by 8 */	stv680->maxframesize = bufsize * 3;	/* RGB size */	PDEBUG (2, "STV(i): cwidth = %i, cheight = %i", stv680->cwidth, stv680->cheight);	PDEBUG (1, "STV(i): width = %i, height = %i, rawbufsize = %li", stv680->vwidth, stv680->vheight, stv680->rawbufsize);	/* some default values */	stv680->bulk_in_endpointAddr = 0x82;	stv680->dropped = 0;	stv680->error = 0;	stv680->framecount = 0;	stv680->readcount = 0;	stv680->streaming = 0;	/* bright, white, colour, hue, contrast are set by software, not in stv0680 */	stv680->brightness = 32767;	stv680->chgbright = 0;	stv680->whiteness = 0;	/* only for greyscale */	stv680->colour = 32767;	stv680->contrast = 32767;	stv680->hue = 32767;	stv680->palette = STV_VIDEO_PALETTE;	stv680->depth = 24;	/* rgb24 bits */	if ((swapRGB_on == 0) && (swapRGB == 0))		PDEBUG (1, "STV(i): swapRGB is (auto) OFF");	else if ((swapRGB_on == 0) && (swapRGB == 1))		PDEBUG (1, "STV(i): swapRGB is (auto) ON");	else if (swapRGB_on == 1)		PDEBUG (1, "STV(i): swapRGB is (forced) ON");	else if (swapRGB_on == -1)		PDEBUG (1, "STV(i): swapRGB is (forced) OFF");		if (stv_set_video_mode (stv680) < 0) {		PDEBUG (0, "STV(e): Could not set video mode in stv_init");		return -1;	}	return 0;}/***************** last of pencam  routines  *******************//**************************************************************************** *  sysfs ***************************************************************************/#define stv680_file(name, variable, field)				\static ssize_t show_##name(struct class_device *class_dev, char *buf)	\{									\	struct video_device *vdev = to_video_device(class_dev);		\

⌨️ 快捷键说明

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