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

📄 saa7113-new.c

📁 这是一个Linux下的USB摄像头捕捉程序
💻 C
字号:
/*    SAA7113 - Philips video decoder driver    Copyright (C) 2000 Ralph Metzler <ralph@convergence.de>                  for Convergence Integrated Media GmbH    based on the SAAA7110 and SAA7111 drivers by:    Copyright (C) 1998 Pauline Middelink <middelin@polyware.nl>    Copyright (C) 1998 Dave Perks <dperks@ibm.net>    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/errno.h>#include <linux/fs.h>#include <linux/kernel.h>#include <linux/major.h>#include <linux/mm.h>#include <linux/pci.h>#include <linux/signal.h>#include <linux/sched.h>#include <linux/types.h>#include <linux/video_decoder.h>#include <linux/module.h>#include <linux/delay.h>#include <linux/slab.h>#include <linux/poll.h>#include <linux/version.h>#include <asm/uaccess.h>#include <asm/io.h>#include <asm/pgtable.h>#include <asm/page.h>#include <asm/segment.h>#include <linux/videodev.h>#include <linux/i2c.h>#include <linux/video_decoder.h>#define DEBUG(x)			/* remove when no long debugging */#define	I2C_DELAY		10	/* 10 us or 100khz *///addresses to scanstatic unsigned short normal_i2c[]	  	= { I2C_CLIENT_END };static unsigned short normal_i2c_range[] 	= { 0x48>>1, 0x4A>>1, I2C_CLIENT_END };static unsigned short probe[2]		  	= { I2C_CLIENT_END, I2C_CLIENT_END };static unsigned short probe_range[2]  		= { I2C_CLIENT_END, I2C_CLIENT_END };static unsigned short ignore[2]	 	  	= { I2C_CLIENT_END, I2C_CLIENT_END };static unsigned short ignore_range[2] 		= { I2C_CLIENT_END, I2C_CLIENT_END };static unsigned short force[2]		  	= { I2C_CLIENT_END, I2C_CLIENT_END };static struct i2c_client_address_data addr_data = {	normal_i2c, normal_i2c_range,	probe, probe_range,	ignore, ignore_range,	force};static struct i2c_client client_template;struct saa7113 {        struct i2c_client *client;        int addr;	unsigned char reg[0x62];	int norm;	int input;	int enable;	int bright;	int contrast;	int hue;	int sat;};/* helper functions to access driver private data. */static inline void *i2c_get_clientdata(struct i2c_client *client){	return client->data;}static inline void i2c_set_clientdata(struct i2c_client *client, void *data){	client->data = data;}static int saa7113_write(struct i2c_client *client, unsigned char reg, unsigned char data){	struct saa7113 *decoder = i2c_get_clientdata(client);	int ret;	unsigned char msg[] = {0x1f, 0x00};	msg[0]=reg; msg[1]=data;	ret=i2c_master_send(client, msg, 2);	if (ret!=2) {		printk("saa7113_write error\n");	}	decoder->reg[reg]=data;	return ret;}static int saa7113_write_block(struct i2c_client *client, const unsigned char *regs){        unsigned char reg, data;        while (*regs!=0xff) {                reg =*(regs++);                data=*(regs++);                if (saa7113_write(client, reg, data)<0)                        return -1;        }        return 0;}static int saa7113_read(struct i2c_client *client, unsigned char subaddr){	unsigned char buffer;	if (1 != i2c_master_send(client, &subaddr, 1)) {		printk(KERN_WARNING		       "saa7113: I/O error, trying (write %d)\n", subaddr);		return -1;	}	if (1 != i2c_master_recv(client, &buffer, 1)) {		printk(KERN_WARNING "saa7113: I/O error, trying (read)\n");		return -1;	}	printk(KERN_WARNING "saa7113_read 0x%02X\n", buffer);	return (int)buffer;}static const unsigned char init_saa7113[] = {        0x01, 0x08,        0x02, 0xc0, /* c7 s-video */        0x03, 0x23,        0x04, 0x00,        0x05, 0x00,        0x06, 0xe9, /* Start of hsync */        0x07, 0x0d, /* End of hsync */        0x08, 0x88,        0x09, 0x00,        0x0a, 0x80,        0x0b, 0x47,        0x0c, 0x40,        0x0d, 0x00,        0x0e, 0x01,        0x0f, 0x2a, /* Use automatic chromance gain */        0x10, 0x28,        0x11, 0x1C,        0x12, 0xc8, /* RTS0 -> programmable HS, RTS1 -> V123., don't know about RTS1 */        0x13, 0x00,        0x15, 0x00,        0x16, 0x00,        0x17, 0x00,        0x40, 0x82,        0x58, 0x00,        0x59, 0x54,        0x5a, 0x0a,        0x5b, 0x83,        0x5e, 0x00,        0xff};void init(struct i2c_client *client){	struct saa7113 *decoder = i2c_get_clientdata(client);	decoder->addr = client->addr;	decoder->norm = VIDEO_MODE_AUTO;	decoder->input = 0;	decoder->enable = 1;	decoder->bright = 32768;	decoder->contrast = 32768;	decoder->hue = 32768;	decoder->sat = 32768;	decoder->client=client;	saa7113_write_block(client, init_saa7113);	printk("saa7113: status=%02x\n", saa7113_read(client, 0x1f));}static int saa7113_attach(struct i2c_adapter *adap, int addr, unsigned short flags, int kind){	struct saa7113 *decoder;	struct i2c_client *client;	client = kmalloc(sizeof *client, GFP_KERNEL);	if (!client)		return -ENOMEM;	memcpy(client, &client_template, sizeof(struct i2c_client));	client->adapter = adap;	client->addr = addr;	strcpy(client->name, "saa7113");	decoder=kmalloc(sizeof(struct saa7113),GFP_KERNEL);	if (decoder==NULL) {		kfree(client);		return -ENOMEM;	}	i2c_set_clientdata(client, decoder);	memset(decoder, 0, sizeof(struct saa7113));	init(client);	printk("saa7113: version=%02x\n", saa7113_read(client, 0x00));	MOD_INC_USE_COUNT;	printk("saa7113: attaching SAA7113 at 0x%02x\n", (client->addr)<<1);	i2c_attach_client(client);	printk("saa7113: attached to adapter %s\n", adap->name);	return 0;}/* ----------------------------------------------------------------------- */static int saa7113_probe(struct i2c_adapter *adap){	return i2c_probe(adap, &addr_data, saa7113_attach);}int saa7113_detach(struct i2c_client *client){	i2c_detach_client(client);	kfree(i2c_get_clientdata(client));	kfree(client);	MOD_DEC_USE_COUNT;	return 0;}static int saa7113_command(struct i2c_client *client, unsigned int cmd, void *arg){	struct saa7113 *decoder = i2c_get_clientdata(client);	int v;	switch (cmd) {		case DECODER_GET_CAPABILITIES:		{			struct video_decoder_capability *dc = arg;			dc->flags = VIDEO_DECODER_PAL				  | VIDEO_DECODER_NTSC				  | VIDEO_DECODER_SECAM				  | VIDEO_DECODER_AUTO				  | VIDEO_DECODER_CCIR;			dc->inputs = 8;			dc->outputs = 1;			break;		}		case DECODER_GET_STATUS:		{			int *iarg = arg;			int status;			int res;			status = saa7113_read(client, 0x1f);			res = 0;			if ((status & (1 << 6)) == 0) {				res |= DECODER_STATUS_GOOD;			}			switch (decoder->norm) {			case VIDEO_MODE_NTSC:				res |= DECODER_STATUS_NTSC;				break;			case VIDEO_MODE_PAL:				res |= DECODER_STATUS_PAL;				break;			case VIDEO_MODE_SECAM:				res |= DECODER_STATUS_SECAM;				break;			default:			case VIDEO_MODE_AUTO:				if ((status & (1 << 5)) != 0) {					res |= DECODER_STATUS_NTSC;				} else {					res |= DECODER_STATUS_PAL;				}				break;			}			if ((status & (1 << 0)) != 0) {				res |= DECODER_STATUS_COLOR;			}			*iarg = res;			break;		}		case DECODER_SET_NORM:		{			v = *(int*)arg;			switch (v) {				case VIDEO_MODE_NTSC:				{					//Field selection 60Hz					saa7113_write(client, 0x08, (decoder->reg[0x08] & 0x3f) | 0x40);					//Colour standard NTSC_MJ					saa7113_write(client, 0x0E, (decoder->reg[0x0E] & 0x8F) | 0x00);					break;				}				case VIDEO_MODE_PAL:				{					//Field selection 50Hz					saa7113_write(client, 0x08, (decoder->reg[0x08] & 0x3f) | 0x00);					//Colour standard PAL_BGHI					saa7113_write(client, 0x0E, (decoder->reg[0x0E] & 0x8F) | 0x00);					break;				}				case VIDEO_MODE_SECAM:				{					//Field selection 50Hz					saa7113_write(client, 0x08, (decoder->reg[0x08] & 0x3F) | 0x00);					//Colour standard PAL/SECAM					saa7113_write(client, 0x0E, (decoder->reg[0x0E] & 0x8F) | 0x50);					break;				}				case VIDEO_MODE_AUTO:				{					//Field selection auto					saa7113_write(client, 0x08, (decoder->reg[0x08] & 0x3f) | 0x80);					//Colour standard PAL_BGHI/NTSC_MJ					saa7113_write(client, 0x0E, (decoder->reg[0x0E] & 0x8F) | 0x00);					break;				}                default:					printk(KERN_WARNING "Could not determine video mode for usbvision device");					return -EINVAL;			}			decoder->norm = v;			break;		}		case DECODER_SET_INPUT:		{			int *iarg = arg;			if (*iarg < 0 || *iarg > 7) {				return -EINVAL;			}			if (decoder->input != *iarg) {				decoder->input = *iarg;				/* select mode */				saa7113_write(client, 0x02, (decoder->reg[0x02] & 0xf8) | decoder->input);				/* bypass chrominance trap for modes 4..7 */				saa7113_write(client, 0x09, (decoder->reg[0x09] & 0x7f) | ((decoder->input > 3) ? 0x80 : 0));			}			break;		}		case DECODER_SET_OUTPUT:		{			v = *(int*)arg;			// not much choice of outputs			if (v != 0) {				return -EINVAL;			}			break;		}		case DECODER_ENABLE_OUTPUT:		{			int *iarg = arg;			int enable = (*iarg != 0);			if (decoder->enable != enable) {				decoder->enable = enable;				// RJ: If output should be disabled (for playing videos), we also need a open PLL.				//     The input is set to 0 (where no input source is connected), although this				//     is not necessary.				//				//     If output should be enabled, we have to reverse the above.				if (decoder->enable) {					saa7113_write(client, 0x02, (decoder->reg[0x02] & 0xf8) | decoder->input);					saa7113_write(client, 0x08, (decoder->reg[0x08] & 0xfb));					saa7113_write(client, 0x11, (decoder->reg[0x11] & 0xf3) | 0x0c);				} else {					saa7113_write(client, 0x02, (decoder->reg[0x02] & 0xf8));					saa7113_write(client, 0x08, (decoder->reg[0x08] & 0xfb) | 0x04);					saa7113_write(client, 0x11, (decoder->reg[0x11] & 0xf3));				}			}			break;		}		case DECODER_SET_PICTURE:		{			struct video_picture *pic = arg;			if (decoder->bright != pic->brightness) {				/* We want 0 to 255 we get 0-65535 */				decoder->bright = pic->brightness;				saa7113_write(client, 0x0a, decoder->bright >> 8);			}			if (decoder->contrast != pic->contrast) {				/* We want 0 to 127 we get 0-65535 */				decoder->contrast = pic->contrast;				saa7113_write(client, 0x0b, decoder->contrast >> 9);			}			if (decoder->sat != pic->colour) {				/* We want 0 to 127 we get 0-65535 */				decoder->sat = pic->colour;				saa7113_write(client, 0x0c, decoder->sat >> 9);			}			if (decoder->hue != pic->hue) {				/* We want -128 to 127 we get 0-65535 */				decoder->hue = pic->hue;				saa7113_write(client, 0x0d, (decoder->hue - 32768) >> 8);			}			break;		}		default:			return -EINVAL;	}	return 0;}static struct i2c_driver saa7113_driver = {	.name           = "SAA7113",	.id             = I2C_DRIVERID_SAA7113,	.flags          = I2C_DF_NOTIFY,	.attach_adapter = saa7113_probe,	.detach_client  = saa7113_detach,	.command        = saa7113_command,};static struct i2c_client client_template = {	.name			= "(unset)",	.id			= I2C_DRIVERID_SAA7113,	.flags			= 0,	.addr			= 0,	.adapter		= NULL,	.driver			= &saa7113_driver,};#ifdef MODULEint init_module(void)#elseint saa7113_init(void)#endif{	int res;	if ((res = i2c_add_driver(&saa7113_driver))) {		printk("saa7113: Driver registration failed, module not inserted.\n");		return res;	}	printk("saa7113: init_module\n");	return 0;}#ifdef MODULEvoid cleanup_module(void){        int res;                if ((res = i2c_del_driver(&saa7113_driver)))         {                printk("saa7113: Driver deregistration failed, "                       "module not removed.\n");        }}#endifMODULE_LICENSE("GPL");

⌨️ 快捷键说明

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