saa7191.c

来自「linux-2.4.29操作系统的源码」· C语言 代码 · 共 321 行

C
321
字号
/*  *  saa7191 - Philips SAA7191 video decoder driver * *  Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org> * *  This program is free software; you can redistribute it and/or modify *  it under the terms of the GNU General Public License version 2 as *  published by the Free Software Foundation. */#include <linux/module.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/errno.h>#include <linux/fs.h>#include <linux/kernel.h>#include <linux/major.h>#include <linux/slab.h>#include <linux/mm.h>#include <linux/sched.h>#include <linux/videodev.h>#include <linux/video_decoder.h>#include <linux/i2c.h>#include "saa7191.h"#define VINO_ADAPTER	(I2C_ALGO_SGI | I2C_HW_SGI_VINO)struct saa7191 {	struct i2c_client *client;	unsigned char reg[25];	unsigned char norm;	unsigned char input;	unsigned char bright;	unsigned char contrast;	unsigned char hue;	unsigned char sat;};static struct i2c_driver i2c_driver_saa7191;static int saa7191_attach(struct i2c_adapter *adap, int addr, int kind){	static const unsigned char initseq[] = {		0,		0x50,	/* SAA7191_REG_IDEL */		0x30,	/* SAA7191_REG_HSYB */		0x00,	/* SAA7191_REG_HSYS */		0xe8,	/* SAA7191_REG_HCLB */		0xb6,	/* SAA7191_REG_HCLS */		0xf4,	/* SAA7191_REG_HPHI */		0x01,	/* SAA7191_REG_LUMA */		0x00,	/* SAA7191_REG_HUEC */		0xf8,	/* SAA7191_REG_CKTQ */		0xf8,	/* SAA7191_REG_CKTS */		0x90,	/* SAA7191_REG_PLSE */		0x90,	/* SAA7191_REG_SESE */		0x00,	/* SAA7191_REG_GAIN */		0x8c,	/* SAA7191_REG_STDC */		0x78,	/* SAA7191_REG_IOCK */		0x99,	/* SAA7191_REG_CTL3 */		0x00,	/* SAA7191_REG_CTL4 */		0x2c,	/* SAA7191_REG_CHCV */		0x00,	/* unused */		0x00,	/* unused */		0x34,	/* SAA7191_REG_HS6B */		0x0a,	/* SAA7191_REG_HS6S */		0xf4,	/* SAA7191_REG_HC6B */		0xce,	/* SAA7191_REG_HC6S */		0xf4,	/* SAA7191_REG_HP6I */	};	int err = 0;	struct saa7191 *decoder;	struct i2c_client *client;	client = kmalloc(sizeof(*client), GFP_KERNEL);	if (!client) 		return -ENOMEM;	decoder = kmalloc(sizeof(*decoder), GFP_KERNEL);	if (!decoder) {		err = -ENOMEM;		goto out_free_client;	}	client->data = decoder;	client->adapter = adap;	client->addr = addr;	client->driver = &i2c_driver_saa7191;	strcpy(client->name, "saa7191 client");				decoder->client = client;	err = i2c_attach_client(client);	if (err)		goto out_free_decoder;	decoder->norm = VIDEO_DECODER_PAL | VIDEO_MODE_NTSC |			VIDEO_DECODER_AUTO;	decoder->input = 0;	/* Registers are 8bit wide and we are storing shifted values */	decoder->bright = 128;	decoder->contrast = 128;	decoder->hue = 128;	decoder->sat = 128;	memcpy(decoder->reg, initseq, sizeof(initseq));	err = i2c_master_send(client, initseq, sizeof(initseq));	if (err)		printk(KERN_INFO "saa7191 initialization failed (%d)\n", err);	MOD_INC_USE_COUNT;	return 0;out_free_decoder:	kfree(decoder);out_free_client:	kfree(client);	return err;}static int saa7191_probe(struct i2c_adapter *adap){	/* Always connected to VINO */	if (adap->id == VINO_ADAPTER)		return saa7191_attach(adap, SAA7191_ADDR, 0);	/* Feel free to add probe here :-) */	return -ENODEV;}static int saa7191_detach(struct i2c_client *client){	struct saa7191 *decoder = client->data;	i2c_detach_client(client);	kfree(decoder);	kfree(client);	MOD_DEC_USE_COUNT;	return 0;}static unsigned char saa7191_read(struct i2c_client *client,				  unsigned char command){	return ((struct saa7191 *)client->data)->reg[command];}static int saa7191_write(struct i2c_client *client, unsigned char command,			 unsigned char value){	((struct saa7191 *)client->data)->reg[command] = value;	return i2c_smbus_write_byte_data(client, command, value);}static int vino_set_input(struct i2c_client *client, int val){	unsigned char luma = saa7191_read(client, SAA7191_REG_LUMA);	unsigned char iock = saa7191_read(client, SAA7191_REG_IOCK);	switch (val) {	case 0: /* Set Composite input */		iock &= ~0x03;		/* Chrominance trap active */		luma |= ~SAA7191_LUMA_BYPS;		break;	case 1: /* Set S-Video input */		iock |= 2;		/* Chrominance trap bypassed */		luma |= SAA7191_LUMA_BYPS;		break;	default:		return -EINVAL;	}	saa7191_write(client, SAA7191_REG_LUMA, luma);	saa7191_write(client, SAA7191_REG_IOCK, iock);	return 0;}static int saa7191_command(struct i2c_client *client, unsigned int cmd,			   void *arg){	struct saa7191 *decoder = client->data;	switch (cmd) {	case DECODER_GET_CAPABILITIES: {		struct video_decoder_capability *cap = arg;		cap->flags  = VIDEO_DECODER_PAL | VIDEO_DECODER_NTSC |			      VIDEO_DECODER_AUTO;		cap->inputs = (client->adapter->id == VINO_ADAPTER) ? 2 : 1;		cap->outputs = 1;		break;	}	case DECODER_GET_STATUS: {		int *iarg = arg;		int status;		int res = 0;		status = i2c_smbus_read_byte_data(client, SAA7191_REG_STATUS);		if ((status & SAA7191_STATUS_HLCK) == 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_AUTO:		default:			if (status & SAA7191_STATUS_FIDT)				res |= DECODER_STATUS_NTSC;			else				res |= DECODER_STATUS_PAL;			if (status & SAA7191_STATUS_CODE)				res |= DECODER_STATUS_COLOR;			break;		}		*iarg = res;		break;	}	case DECODER_SET_NORM: {		int *iarg = arg;		switch (*iarg) {		case VIDEO_MODE_NTSC:			break;		case VIDEO_MODE_PAL:			break;		default:			return -EINVAL;		}		decoder->norm = *iarg;		break;	}	case DECODER_SET_INPUT:	{		int *iarg = arg;		switch (client->adapter->id) {		case VINO_ADAPTER:			return vino_set_input(client, *iarg);		default:			if (*iarg != 0)				return -EINVAL;		}		break;	}	case DECODER_SET_OUTPUT: {		int *iarg = arg;		/* not much choice of outputs */		if (*iarg != 0)			return -EINVAL;		break;	}	case DECODER_ENABLE_OUTPUT: {		/* Always enabled */		break;	}	case DECODER_SET_PICTURE: {		struct video_picture *pic = arg;		unsigned val;#if 0		/* TODO */		val = pic->brightness >> 8;		if (decoder->bright != val) {			decoder->bright = val;			i2c_smbus_write_byte_data(client, XXX, val);		}		val = pic->contrast >> 8;		if (decoder->contrast != val) {			decoder->contrast = val;			i2c_smbus_write_byte_data(client, XXX, val);		}		val = pic->colour >> 8;		if (decoder->sat != val) {			decoder->sat = val;			i2c_smbus_write_byte_data(client, XXX, val);		}#endif		val = (pic->hue >> 8) - 0x80;		if (decoder->hue != val) {			decoder->hue = val;			i2c_smbus_write_byte_data(client, SAA7191_REG_HUEC,						  val);		}		break;	}	default:		return -EINVAL;	}	return 0;}static struct i2c_driver i2c_driver_saa7191 = {	.name 		= "saa7191",	.id 		= I2C_DRIVERID_SAA7191,	.flags 		= I2C_DF_NOTIFY,	.attach_adapter = saa7191_probe,	.detach_client 	= saa7191_detach,	.command 	= saa7191_command};static int saa7191_init(void){	return i2c_add_driver(&i2c_driver_saa7191);}static void saa7191_exit(void){	i2c_del_driver(&i2c_driver_saa7191);}module_init(saa7191_init);module_exit(saa7191_exit);MODULE_DESCRIPTION("Philips SAA7191 video decoder driver");MODULE_AUTHOR("Ladislav Michl <ladis@linux-mips.org>");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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