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

📄 tuner-core.c

📁 trident tm5600的linux驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * * i2c tv tuner chip device driver * core core, i.e. kernel interfaces, registering and so on */#include <linux/module.h>#include <linux/kernel.h>#include <linux/string.h>#include <linux/timer.h>#include <linux/delay.h>#include <linux/errno.h>#include <linux/slab.h>#include <linux/poll.h>#include <linux/i2c.h>#include <linux/types.h>#include <linux/init.h>#include "compat.h"#include <linux/videodev.h>#include <media/tuner.h>#include <media/tuner-types.h>#include <media/v4l2-common.h>#include <media/v4l2-ioctl.h>#include <media/v4l2-i2c-drv-legacy.h>#include "mt20xx.h"#include "tda8290.h"#include "tea5761.h"#include "tea5767.h"#include "tuner-xc2028.h"#include "tuner-simple.h"#include "tda9887.h"#include "xc5000.h"#define UNSET (-1U)#define PREFIX t->i2c->driver->driver.name/** This macro allows us to probe dynamically, avoiding static links */#ifdef CONFIG_MEDIA_ATTACH#define tuner_symbol_probe(FUNCTION, ARGS...) ({ \	int __r = -EINVAL; \	typeof(&FUNCTION) __a = symbol_request(FUNCTION); \	if (__a) { \		__r = (int) __a(ARGS); \		symbol_put(FUNCTION); \	} else { \		printk(KERN_ERR "TUNER: Unable to find " \				"symbol "#FUNCTION"()\n"); \	} \	__r; \})static void tuner_detach(struct dvb_frontend *fe){	if (fe->ops.tuner_ops.release) {		fe->ops.tuner_ops.release(fe);		symbol_put_addr(fe->ops.tuner_ops.release);	}	if (fe->ops.analog_ops.release) {		fe->ops.analog_ops.release(fe);		symbol_put_addr(fe->ops.analog_ops.release);	}}#else#define tuner_symbol_probe(FUNCTION, ARGS...) ({ \	FUNCTION(ARGS); \})static void tuner_detach(struct dvb_frontend *fe){	if (fe->ops.tuner_ops.release)		fe->ops.tuner_ops.release(fe);	if (fe->ops.analog_ops.release)		fe->ops.analog_ops.release(fe);}#endifstruct tuner {	/* device */	struct dvb_frontend fe;	struct i2c_client   *i2c;	struct list_head    list;	unsigned int        using_v4l2:1;	/* keep track of the current settings */	v4l2_std_id         std;	unsigned int        tv_freq;	unsigned int        radio_freq;	unsigned int        audmode;	unsigned int        mode;	unsigned int        mode_mask; /* Combination of allowable modes */	unsigned int        type; /* chip type id */	unsigned int        config;	const char          *name;};/* standard i2c insmod options */static unsigned short normal_i2c[] = {#if defined(CONFIG_MEDIA_TUNER_TEA5761) || (defined(CONFIG_MEDIA_TUNER_TEA5761_MODULE) && defined(MODULE))	0x10,#endif	0x42, 0x43, 0x4a, 0x4b,			/* tda8290 */	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,	I2C_CLIENT_END};I2C_CLIENT_INSMOD;/* insmod options used at init time => read/only */static unsigned int addr;static unsigned int no_autodetect;static unsigned int show_i2c;/* insmod options used at runtime => read/write */static int tuner_debug;#define tuner_warn(fmt, arg...) do {			\	printk(KERN_WARNING "%s %d-%04x: " fmt, PREFIX, \	       i2c_adapter_id(t->i2c->adapter),		\	       t->i2c->addr, ##arg);			\	 } while (0)#define tuner_info(fmt, arg...) do {			\	printk(KERN_INFO "%s %d-%04x: " fmt, PREFIX,	\	       i2c_adapter_id(t->i2c->adapter),		\	       t->i2c->addr, ##arg);			\	 } while (0)#define tuner_err(fmt, arg...) do {			\	printk(KERN_ERR "%s %d-%04x: " fmt, PREFIX,	\	       i2c_adapter_id(t->i2c->adapter),		\	       t->i2c->addr, ##arg);			\	 } while (0)#define tuner_dbg(fmt, arg...) do {				\	if (tuner_debug)					\		printk(KERN_DEBUG "%s %d-%04x: " fmt, PREFIX,	\		       i2c_adapter_id(t->i2c->adapter),		\		       t->i2c->addr, ##arg);			\	 } while (0)/* ------------------------------------------------------------------------ */static unsigned int tv_range[2] = { 44, 958 };static unsigned int radio_range[2] = { 65, 108 };static char pal[] = "--";static char secam[] = "--";static char ntsc[] = "-";module_param(addr, int, 0444);module_param(no_autodetect, int, 0444);module_param(show_i2c, int, 0444);module_param_named(debug,tuner_debug, int, 0644);module_param_string(pal, pal, sizeof(pal), 0644);module_param_string(secam, secam, sizeof(secam), 0644);module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);module_param_array(tv_range, int, NULL, 0644);module_param_array(radio_range, int, NULL, 0644);MODULE_DESCRIPTION("device driver for various TV and TV+FM radio tuners");MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");MODULE_LICENSE("GPL");/* ---------------------------------------------------------------------- */static void fe_set_params(struct dvb_frontend *fe,			  struct analog_parameters *params){	struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;	struct tuner *t = fe->analog_demod_priv;	if (NULL == fe_tuner_ops->set_analog_params) {		tuner_warn("Tuner frontend module has no way to set freq\n");		return;	}	fe_tuner_ops->set_analog_params(fe, params);}static void fe_standby(struct dvb_frontend *fe){	struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;	if (fe_tuner_ops->sleep)		fe_tuner_ops->sleep(fe);}static int fe_has_signal(struct dvb_frontend *fe){	u16 strength = 0;	if (fe->ops.tuner_ops.get_rf_strength)		fe->ops.tuner_ops.get_rf_strength(fe, &strength);	return strength;}static int fe_set_config(struct dvb_frontend *fe, void *priv_cfg){	struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;	struct tuner *t = fe->analog_demod_priv;	if (fe_tuner_ops->set_config)		return fe_tuner_ops->set_config(fe, priv_cfg);	tuner_warn("Tuner frontend module has no way to set config\n");	return 0;}static void tuner_status(struct dvb_frontend *fe);static struct analog_demod_ops tuner_core_ops = {	.set_params     = fe_set_params,	.standby        = fe_standby,	.has_signal     = fe_has_signal,	.set_config     = fe_set_config,	.tuner_status   = tuner_status};/* Set tuner frequency,  freq in Units of 62.5kHz = 1/16MHz */static void set_tv_freq(struct i2c_client *c, unsigned int freq){	struct tuner *t = i2c_get_clientdata(c);	struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;	struct analog_parameters params = {		.mode      = t->mode,		.audmode   = t->audmode,		.std       = t->std	};	if (t->type == UNSET) {		tuner_warn ("tuner type not set\n");		return;	}	if (NULL == analog_ops->set_params) {		tuner_warn ("Tuner has no way to set tv freq\n");		return;	}	if (freq < tv_range[0] * 16 || freq > tv_range[1] * 16) {		tuner_dbg ("TV freq (%d.%02d) out of range (%d-%d)\n",			   freq / 16, freq % 16 * 100 / 16, tv_range[0],			   tv_range[1]);		/* V4L2 spec: if the freq is not possible then the closest		   possible value should be selected */		if (freq < tv_range[0] * 16)			freq = tv_range[0] * 16;		else			freq = tv_range[1] * 16;	}	params.frequency = freq;	analog_ops->set_params(&t->fe, &params);}static void set_radio_freq(struct i2c_client *c, unsigned int freq){	struct tuner *t = i2c_get_clientdata(c);	struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;	struct analog_parameters params = {		.mode      = t->mode,		.audmode   = t->audmode,		.std       = t->std	};	if (t->type == UNSET) {		tuner_warn ("tuner type not set\n");		return;	}	if (NULL == analog_ops->set_params) {		tuner_warn ("tuner has no way to set radio frequency\n");		return;	}	if (freq < radio_range[0] * 16000 || freq > radio_range[1] * 16000) {		tuner_dbg ("radio freq (%d.%02d) out of range (%d-%d)\n",			   freq / 16000, freq % 16000 * 100 / 16000,			   radio_range[0], radio_range[1]);		/* V4L2 spec: if the freq is not possible then the closest		   possible value should be selected */		if (freq < radio_range[0] * 16000)			freq = radio_range[0] * 16000;		else			freq = radio_range[1] * 16000;	}	params.frequency = freq;	analog_ops->set_params(&t->fe, &params);}static void set_freq(struct i2c_client *c, unsigned long freq){	struct tuner *t = i2c_get_clientdata(c);	switch (t->mode) {	case V4L2_TUNER_RADIO:		tuner_dbg("radio freq set to %lu.%02lu\n",			  freq / 16000, freq % 16000 * 100 / 16000);		set_radio_freq(c, freq);		t->radio_freq = freq;		break;	case V4L2_TUNER_ANALOG_TV:	case V4L2_TUNER_DIGITAL_TV:		tuner_dbg("tv freq set to %lu.%02lu\n",			  freq / 16, freq % 16 * 100 / 16);		set_tv_freq(c, freq);		t->tv_freq = freq;		break;	default:		tuner_dbg("freq set: unknown mode: 0x%04x!\n",t->mode);	}}static void tuner_i2c_address_check(struct tuner *t){	if ((t->type == UNSET || t->type == TUNER_ABSENT) ||	    ((t->i2c->addr < 0x64) || (t->i2c->addr > 0x6f)))		return;	/* We already know that the XC5000 can only be located at	 * i2c address 0x61, 0x62, 0x63 or 0x64 */	if ((t->type == TUNER_XC5000) &&	    ((t->i2c->addr <= 0x64)) && (t->i2c->addr >= 0x61))		return;	tuner_warn("====================== WARNING! ======================\n");	tuner_warn("Support for tuners in i2c address range 0x64 thru 0x6f\n");	tuner_warn("will soon be dropped. This message indicates that your\n");	tuner_warn("hardware has a %s tuner at i2c address 0x%02x.\n",		   t->name, t->i2c->addr);	tuner_warn("To ensure continued support for your device, please\n");	tuner_warn("send a copy of this message, along with full dmesg\n");	tuner_warn("output to v4l-dvb-maintainer@linuxtv.org\n");	tuner_warn("Please use subject line: \"obsolete tuner i2c address.\"\n");	tuner_warn("driver: %s, addr: 0x%02x, type: %d (%s)\n",		   t->i2c->adapter->name, t->i2c->addr, t->type, t->name);	tuner_warn("====================== WARNING! ======================\n");}static struct xc5000_config xc5000_cfg;static void set_type(struct i2c_client *c, unsigned int type,		     unsigned int new_mode_mask, unsigned int new_config,		     int (*tuner_callback) (void *dev, int component, int cmd, int arg)){	struct tuner *t = i2c_get_clientdata(c);	struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;	struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;	unsigned char buffer[4];	if (type == UNSET || type == TUNER_ABSENT) {		tuner_dbg ("tuner 0x%02x: Tuner type absent\n",c->addr);		return;	}	t->type = type;	t->config = new_config;	if (tuner_callback != NULL) {		tuner_dbg("defining GPIO callback\n");		t->fe.callback = tuner_callback;	}	if (t->mode == T_UNINITIALIZED) {		tuner_dbg ("tuner 0x%02x: called during i2c_client register by adapter's attach_inform\n", c->addr);		return;	}	/* discard private data, in case set_type() was previously called */	tuner_detach(&t->fe);	t->fe.analog_demod_priv = NULL;	switch (t->type) {	case TUNER_MT2032:		if (!dvb_attach(microtune_attach,			   &t->fe, t->i2c->adapter, t->i2c->addr))			goto attach_failed;		break;	case TUNER_PHILIPS_TDA8290:	{		struct tda829x_config cfg = {			.lna_cfg        = t->config,		};		if (!dvb_attach(tda829x_attach, &t->fe, t->i2c->adapter,				t->i2c->addr, &cfg))			goto attach_failed;		break;	}	case TUNER_TEA5767:		if (!dvb_attach(tea5767_attach, &t->fe,				t->i2c->adapter, t->i2c->addr))			goto attach_failed;		t->mode_mask = T_RADIO;		break;	case TUNER_TEA5761:		if (!dvb_attach(tea5761_attach, &t->fe,				t->i2c->adapter, t->i2c->addr))			goto attach_failed;		t->mode_mask = T_RADIO;		break;	case TUNER_PHILIPS_FMD1216ME_MK3:		buffer[0] = 0x0b;		buffer[1] = 0xdc;		buffer[2] = 0x9c;		buffer[3] = 0x60;		i2c_master_send(c, buffer, 4);		mdelay(1);		buffer[2] = 0x86;		buffer[3] = 0x54;		i2c_master_send(c, buffer, 4);		if (!dvb_attach(simple_tuner_attach, &t->fe,				t->i2c->adapter, t->i2c->addr, t->type))			goto attach_failed;		break;	case TUNER_PHILIPS_TD1316:		buffer[0] = 0x0b;		buffer[1] = 0xdc;		buffer[2] = 0x86;		buffer[3] = 0xa4;		i2c_master_send(c, buffer, 4);		if (!dvb_attach(simple_tuner_attach, &t->fe,				t->i2c->adapter, t->i2c->addr, t->type))			goto attach_failed;		break;	case TUNER_XC2028:	{		struct xc2028_config cfg = {			.i2c_adap  = t->i2c->adapter,			.i2c_addr  = t->i2c->addr,		};		if (!dvb_attach(xc2028_attach, &t->fe, &cfg))			goto attach_failed;		break;	}	case TUNER_TDA9887:

⌨️ 快捷键说明

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