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

📄 tuner-core.c

📁 trident tm5600的linux驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
			} else {				vt->rangelow = tv_range[0] * 16;				vt->rangehigh = tv_range[1] * 16;			}			return 0;		}	case VIDIOCGAUDIO:		{			struct video_audio *va = arg;			if (check_mode(t, "VIDIOCGAUDIO") == -EINVAL)				return 0;			if (check_v4l2(t) == -EINVAL)				return 0;			if (V4L2_TUNER_RADIO == t->mode) {				if (fe_tuner_ops->get_status) {					u32 tuner_status;					fe_tuner_ops->get_status(&t->fe, &tuner_status);					va->mode = (tuner_status & TUNER_STATUS_STEREO)					    ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;				} else if (analog_ops->is_stereo)					va->mode = analog_ops->is_stereo(&t->fe)					    ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;			}			return 0;		}#endif	case TUNER_SET_CONFIG:	{		struct v4l2_priv_tun_config *cfg = arg;		if (t->type != cfg->tuner)			break;		if (analog_ops->set_config) {			analog_ops->set_config(&t->fe, cfg->priv);			break;		}		tuner_dbg("Tuner frontend module has no way to set config\n");		break;	}	/* --- v4l ioctls --- */	/* take care: bttv does userspace copying, we'll get a	   kernel pointer here... */	case VIDIOC_S_STD:		{			v4l2_std_id *id = arg;			if (set_mode (client, t, V4L2_TUNER_ANALOG_TV, "VIDIOC_S_STD")					== -EINVAL)				return 0;			switch_v4l2();			t->std = *id;			tuner_fixup_std(t);			if (t->tv_freq)				set_freq(client, t->tv_freq);			break;		}	case VIDIOC_S_FREQUENCY:		{			struct v4l2_frequency *f = arg;			if (set_mode (client, t, f->type, "VIDIOC_S_FREQUENCY")					== -EINVAL)				return 0;			switch_v4l2();			set_freq(client,f->frequency);			break;		}	case VIDIOC_G_FREQUENCY:		{			struct v4l2_frequency *f = arg;			if (check_mode(t, "VIDIOC_G_FREQUENCY") == -EINVAL)				return 0;			switch_v4l2();			f->type = t->mode;			if (fe_tuner_ops->get_frequency) {				u32 abs_freq;				fe_tuner_ops->get_frequency(&t->fe, &abs_freq);				f->frequency = (V4L2_TUNER_RADIO == t->mode) ?					(abs_freq * 2 + 125/2) / 125 :					(abs_freq + 62500/2) / 62500;				break;			}			f->frequency = (V4L2_TUNER_RADIO == t->mode) ?				t->radio_freq : t->tv_freq;			break;		}	case VIDIOC_G_TUNER:		{			struct v4l2_tuner *tuner = arg;			if (check_mode(t, "VIDIOC_G_TUNER") == -EINVAL)				return 0;			switch_v4l2();			tuner->type = t->mode;			if (analog_ops->get_afc)				tuner->afc = analog_ops->get_afc(&t->fe);			if (t->mode == V4L2_TUNER_ANALOG_TV)				tuner->capability |= V4L2_TUNER_CAP_NORM;			if (t->mode != V4L2_TUNER_RADIO) {				tuner->rangelow = tv_range[0] * 16;				tuner->rangehigh = tv_range[1] * 16;				break;			}			/* radio mode */			tuner->rxsubchans =				V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;			if (fe_tuner_ops->get_status) {				u32 tuner_status;				fe_tuner_ops->get_status(&t->fe, &tuner_status);				tuner->rxsubchans =					(tuner_status & TUNER_STATUS_STEREO) ?					V4L2_TUNER_SUB_STEREO :					V4L2_TUNER_SUB_MONO;			} else {				if (analog_ops->is_stereo) {					tuner->rxsubchans =						analog_ops->is_stereo(&t->fe) ?						V4L2_TUNER_SUB_STEREO :						V4L2_TUNER_SUB_MONO;				}			}			if (analog_ops->has_signal)				tuner->signal = analog_ops->has_signal(&t->fe);			tuner->capability |=			    V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;			tuner->audmode = t->audmode;			tuner->rangelow = radio_range[0] * 16000;			tuner->rangehigh = radio_range[1] * 16000;			break;		}	case VIDIOC_S_TUNER:		{			struct v4l2_tuner *tuner = arg;			if (check_mode(t, "VIDIOC_S_TUNER") == -EINVAL)				return 0;			switch_v4l2();			/* do nothing unless we're a radio tuner */			if (t->mode != V4L2_TUNER_RADIO)				break;			t->audmode = tuner->audmode;			set_radio_freq(client, t->radio_freq);			break;		}	case VIDIOC_LOG_STATUS:		if (analog_ops->tuner_status)			analog_ops->tuner_status(&t->fe);		break;	}	return 0;}static int tuner_suspend(struct i2c_client *c, pm_message_t state){	struct tuner *t = i2c_get_clientdata(c);	tuner_dbg("suspend\n");	/* FIXME: power down ??? */	return 0;}static int tuner_resume(struct i2c_client *c){	struct tuner *t = i2c_get_clientdata(c);	tuner_dbg("resume\n");	if (V4L2_TUNER_RADIO == t->mode) {		if (t->radio_freq)			set_freq(c, t->radio_freq);	} else {		if (t->tv_freq)			set_freq(c, t->tv_freq);	}	return 0;}/* ---------------------------------------------------------------------- */static LIST_HEAD(tuner_list);/* Search for existing radio and/or TV tuners on the given I2C adapter.   Note that when this function is called from tuner_probe you can be   certain no other devices will be added/deleted at the same time, I2C   core protects against that. */static void tuner_lookup(struct i2c_adapter *adap,		struct tuner **radio, struct tuner **tv){	struct tuner *pos;	*radio = NULL;	*tv = NULL;	list_for_each_entry(pos, &tuner_list, list) {		int mode_mask;		if (pos->i2c->adapter != adap ||		    pos->i2c->driver->id != I2C_DRIVERID_TUNER)			continue;		mode_mask = pos->mode_mask & ~T_STANDBY;		if (*radio == NULL && mode_mask == T_RADIO)			*radio = pos;		/* Note: currently TDA9887 is the only demod-only		   device. If other devices appear then we need to		   make this test more general. */		else if (*tv == NULL && pos->type != TUNER_TDA9887 &&			 (pos->mode_mask & (T_ANALOG_TV | T_DIGITAL_TV)))			*tv = pos;	}}/* During client attach, set_type is called by adapter's attach_inform callback.   set_type must then be completed by tuner_probe. */static int tuner_probe(struct i2c_client *client,		       const struct i2c_device_id *id){	struct tuner *t;	struct tuner *radio;	struct tuner *tv;	t = kzalloc(sizeof(struct tuner), GFP_KERNEL);	if (NULL == t)		return -ENOMEM;	t->i2c = client;	t->name = "(tuner unset)";	i2c_set_clientdata(client, t);	t->type = UNSET;	t->audmode = V4L2_TUNER_MODE_STEREO;	t->mode_mask = T_UNINITIALIZED;	if (show_i2c) {		unsigned char buffer[16];		int i, rc;		memset(buffer, 0, sizeof(buffer));		rc = i2c_master_recv(client, buffer, sizeof(buffer));		tuner_info("I2C RECV = ");		for (i = 0; i < rc; i++)			printk(KERN_CONT "%02x ", buffer[i]);		printk("\n");	}	/* HACK: This test was added to avoid tuner to probe tda9840 and	   tea6415c on the MXB card */	if (client->adapter->id == I2C_HW_SAA7146 && client->addr < 0x4a) {		kfree(t);		return -ENODEV;	}	/* autodetection code based on the i2c addr */	if (!no_autodetect) {		switch (client->addr) {		case 0x10:			if (tuner_symbol_probe(tea5761_autodetection,					       t->i2c->adapter,					       t->i2c->addr) >= 0) {				t->type = TUNER_TEA5761;				t->mode_mask = T_RADIO;				t->mode = T_STANDBY;				/* Sets freq to FM range */				t->radio_freq = 87.5 * 16000;				tuner_lookup(t->i2c->adapter, &radio, &tv);				if (tv)					tv->mode_mask &= ~T_RADIO;				goto register_client;			}			return -ENODEV;		case 0x42:		case 0x43:		case 0x4a:		case 0x4b:			/* If chip is not tda8290, don't register.			   since it can be tda9887*/			if (tuner_symbol_probe(tda829x_probe, t->i2c->adapter,					       t->i2c->addr) >= 0) {				tuner_dbg("tda829x detected\n");			} else {				/* Default is being tda9887 */				t->type = TUNER_TDA9887;				t->mode_mask = T_RADIO | T_ANALOG_TV |					       T_DIGITAL_TV;				t->mode = T_STANDBY;				goto register_client;			}			break;		case 0x60:			if (tuner_symbol_probe(tea5767_autodetection,					       t->i2c->adapter, t->i2c->addr)					>= 0) {				t->type = TUNER_TEA5767;				t->mode_mask = T_RADIO;				t->mode = T_STANDBY;				/* Sets freq to FM range */				t->radio_freq = 87.5 * 16000;				tuner_lookup(t->i2c->adapter, &radio, &tv);				if (tv)					tv->mode_mask &= ~T_RADIO;				goto register_client;			}			break;		}	}	/* Initializes only the first TV tuner on this adapter. Why only the	   first? Because there are some devices (notably the ones with TI	   tuners) that have more than one i2c address for the *same* device.	   Experience shows that, except for just one case, the first	   address is the right one. The exception is a Russian tuner	   (ACORP_Y878F). So, the desired behavior is just to enable the	   first found TV tuner. */	tuner_lookup(t->i2c->adapter, &radio, &tv);	if (tv == NULL) {		t->mode_mask = T_ANALOG_TV | T_DIGITAL_TV;		if (radio == NULL)			t->mode_mask |= T_RADIO;		tuner_dbg("Setting mode_mask to 0x%02x\n", t->mode_mask);		t->tv_freq = 400 * 16; /* Sets freq to VHF High */		t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */	}	/* Should be just before return */register_client:	tuner_info("chip found @ 0x%x (%s)\n", client->addr << 1,		       client->adapter->name);	/* Sets a default mode */	if (t->mode_mask & T_ANALOG_TV) {		t->mode = V4L2_TUNER_ANALOG_TV;	} else  if (t->mode_mask & T_RADIO) {		t->mode = V4L2_TUNER_RADIO;	} else {		t->mode = V4L2_TUNER_DIGITAL_TV;	}	set_type(client, t->type, t->mode_mask, t->config, t->fe.callback);	list_add_tail(&t->list, &tuner_list);	return 0;}static int tuner_legacy_probe(struct i2c_adapter *adap){	if (0 != addr) {		normal_i2c[0] = addr;		normal_i2c[1] = I2C_CLIENT_END;	}	if ((adap->class & I2C_CLASS_TV_ANALOG) == 0)		return 0;	/* HACK: Ignore 0x6b and 0x6f on cx88 boards.	 * FusionHDTV5 RT Gold has an ir receiver at 0x6b	 * and an RTC at 0x6f which can get corrupted if probed.	 */	if ((adap->id == I2C_HW_B_CX2388x) ||	    (adap->id == I2C_HW_B_CX23885)) {		unsigned int i = 0;		while (i < I2C_CLIENT_MAX_OPTS && ignore[i] != I2C_CLIENT_END)			i += 2;		if (i + 4 < I2C_CLIENT_MAX_OPTS) {			ignore[i+0] = adap->nr;			ignore[i+1] = 0x6b;			ignore[i+2] = adap->nr;			ignore[i+3] = 0x6f;			ignore[i+4] = I2C_CLIENT_END;		} else			printk(KERN_WARNING "tuner: "			       "too many options specified "			       "in i2c probe ignore list!\n");	}	return 1;}static int tuner_remove(struct i2c_client *client){	struct tuner *t = i2c_get_clientdata(client);	tuner_detach(&t->fe);	t->fe.analog_demod_priv = NULL;	list_del(&t->list);	kfree(t);	return 0;}/* ----------------------------------------------------------------------- */#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)/* This driver supports many devices and the idea is to let the driver   detect which device is present. So rather than listing all supported   devices here, we pretend to support a single, fake device type. */static const struct i2c_device_id tuner_id[] = {	{ "tuner", }, /* autodetect */	{ }};MODULE_DEVICE_TABLE(i2c, tuner_id);#endifstatic struct v4l2_i2c_driver_data v4l2_i2c_data = {	.name = "tuner",	.driverid = I2C_DRIVERID_TUNER,	.command = tuner_command,	.probe = tuner_probe,	.remove = tuner_remove,	.suspend = tuner_suspend,	.resume = tuner_resume,	.legacy_probe = tuner_legacy_probe,#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)	.id_table = tuner_id,#endif};/* * Overrides for Emacs so that we follow Linus's tabbing style. * --------------------------------------------------------------------------- * Local variables: * c-basic-offset: 8 * End: */

⌨️ 快捷键说明

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