Explorar o código

V4L/DVB: tlg2300: remove the country code for analog tv and radio

video :
	use the V4L2_STD macros to select the proper audio setting.

radio :
	add preemphasis ctr.
	test it by the command:
	v4l2-ctl -d /dev/radio0 --set-ctrl=pre_emphasis_settings=1

[mchehab@redhat.com: folded documentation patch]
Signed-off-by: Huang Shijie <shijie8@gmail.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Huang Shijie %!s(int64=15) %!d(string=hai) anos
pai
achega
007ad83036

+ 7 - 191
Documentation/video4linux/README.tlg2300

@@ -37,195 +37,11 @@ TESTED APPLICATIONS:
 
 ---------------------------------------------------------------------------
 KNOWN PROBLEMS:
+about preemphasis:
+	You can set the preemphasis for radio by the following command:
+	#v4l2-ctl -d /dev/radio0 --set-ctrl=pre_emphasis_settings=1
+
+	"pre_emphasis_settings=1" means that you select the 50us. If you want
+	to select the 75us, please use "pre_emphasis_settings=2"
+
 
-country code
-	- The firmware of the chip needs the country code to determine
-	the stardards of video and audio when it runs for analog TV or radio.
-	The DVB-T does not need the country code.
-
-	So you must set the country-code correctly. The V4L2 does not have
-	the interface,the driver has to provide a parameter `country_code'.
-
-	You could set the coutry code in two ways, take USA as example
-	(The USA's country code is 1):
-
-	[1] add the following line in /etc/modprobe.conf before you insert the
-	    card into USB hub's port :
-		poseidon country_code=1
-
-	[2] You can also modify the parameter at runtime (before you run the
-	    application such as VLC)
-		#echo 1 > /sys/module/poseidon/parameter/country_code
-
-	The known country codes show below:
-	country code :  country
-	93 		"Afghanistan"
-	355	 	"Albania"
-	213	 	"Algeria"
-	684	 	"American Samoa"
-	376	 	"Andorra"
-	244	 	"Angola"
-	54 		"Argentina"
-	374	 	"Armenia"
-	61 		"Australia"
-	43 		"Austria"
-	994	 	"Azerbaijan"
-	973	 	"Bahrain"
-	880	 	"Bangladesh"
-	375	 	"Belarus"
-	32 		"Belgium"
-	501	 	"Belize"
-	229	 	"Benin"
-	591	 	"Bolivia"
-	387	 	"Bosnia and Herzegovina"
-	267	 	"Botswana"
-	55 		"Brazil"
-	673	 	"Brunei Darussalam"
-	359	 	"Bulgalia"
-	226	 	"Burkina Faso"
-	257	 	"Burundi"
-	237	 	"Cameroon"
-	1		"Canada"
-	236	 	"Central African Republic"
-	235	 	"Chad"
-	56 		"Chile"
-	86 		"China"
-	57 		"Colombia"
-	242	 	"Congo"
-	243	 	"Congo, Dem. Rep. of "
-	506	 	"Costa Rica"
-	385	 	"Croatia"
-	53 		"Cuba or Guantanamo Bay"
-	357	 	"Cyprus"
-	420	 	"Czech Republic"
-	45 		"Denmark"
-	246	 	"Diego Garcia"
-	253	 	"Djibouti"
-	593	 	"Ecuador"
-	20 		"Egypt"
-	503	 	"El Salvador"
-	240	 	"Equatorial Guinea"
-	372	 	"Estonia"
-	251	 	"Ethiopia"
-	358	 	"Finland"
-	33 		"France"
-	594	 	"French Guiana"
-	689	 	"French Polynesia"
-	241	 	"Gabonese Republic"
-	220	 	"Gambia"
-	995	 	"Georgia"
-	49 		"Germany"
-	233	 	"Ghana"
-	350	 	"Gibraltar"
-	30 		"Greece"
-	299	 	"Greenland"
-	671	 	"Guam"
-	502		"Guatemala"
-	592	 	"Guyana"
-	509	 	"Haiti"
-	504	 	"Honduras"
-	852	 	"Hong Kong SAR, China"
-	36 		"Hungary"
-	354	 	"Iceland"
-	91 		"India"
-	98 		"Iran"
-	964	 	"Iraq"
-	353	 	"Ireland"
-	972	 	"Israel"
-	39 		"Italy or Vatican City"
-	225	 	"Ivory Coast"
-	81 		"Japan"
-	962	 	"Jordan"
-	7		"Kazakhstan or Kyrgyzstan"
-	254	 	"Kenya"
-	686	 	"Kiribati"
-	965	 	"Kuwait"
-	856	 	"Laos"
-	371	 	"Latvia"
-	961	 	"Lebanon"
-	266	 	"Lesotho"
-	231	 	"Liberia"
-	218	 	"Libya"
-	41 		"Liechtenstein or Switzerland"
-	370	 	"Lithuania"
-	352	 	"Luxembourg"
-	853	 	"Macau SAR, China"
-	261	 	"Madagascar"
-	60 		"Malaysia"
-	960	 	"Maldives"
-	223	 	"Mali Republic"
-	356	 	"Malta"
-	692	 	"Marshall Islands"
-	596	 	"Martinique"
-	222	 	"Mauritania"
-	230	 	"Mauritus"
-	52 		"Mexico"
-	691	 	"Micronesia"
-	373	 	"Moldova"
-	377	 	"Monaco"
-	976	 	"Mongolia"
-	212	 	"Morocco"
-	258	 	"Mozambique"
-	95 		"Myanmar"
-	264	 	"Namibia"
-	674	 	"Nauru"
-	31 		"Netherlands"
-	687	 	"New Caledonia"
-	64 		"New Zealand"
-	505	 	"Nicaragua"
-	227	 	"Niger"
-	234	 	"Nigeria"
-	850	 	"North Korea"
-	47 		"Norway"
-	968	 	"Oman"
-	92 		"Pakistan"
-	680	 	"Palau"
-	507	 	"Panama"
-	675	 	"Papua New Guinea"
-	595	 	"Paraguay"
-	51 		"Peru"
-	63 		"Philippines"
-	48 		"Poland"
-	351	 	"Portugal"
-	974	 	"Qatar"
-	262	 	"Reunion Island"
-	40 		"Romania"
-	7		"Russia"
-	378	 	"San Marino"
-	239	 	"Sao Tome and Principe"
-	966	 	"Saudi Arabia"
-	221	 	"Senegal"
-	248	 	"Seychelles Republic"
-	232	 	"Sierra Leone"
-	65 		"Singapore"
-	421	 	"Slovak Republic"
-	386	 	"Slovenia"
-	27 		"South Africa"
-	82 		"South Korea "
-	34 		"Spain"
-	94 		"Sri Lanka"
-	508	 	"St. Pierre and Miquelon"
-	249	 	"Sudan"
-	597	 	"Suriname"
-	268	 	"Swaziland"
-	46 		"Sweden"
-	963	 	"Syria"
-	886	 	"Taiwan Region"
-	255	 	"Tanzania"
-	66 		"Thailand"
-	228	 	"Togolese Republic"
-	216	 	"Tunisia"
-	90 		"Turkey"
-	993	 	"Turkmenistan"
-	256	 	"Uganda"
-	380	 	"Ukraine"
-	971	 	"United Arab Emirates"
-	44 		"United Kingdom"
-	1		"United States of America"
-	598	 	"Uruguay"
-	58 		"Venezuela"
-	84 		"Vietnam"
-	967	 	"Yemen"
-	260	 	"Zambia"
-	255	 	"Zanzibar"
-	263	 	"Zimbabwe"

+ 1 - 3
drivers/media/video/tlg2300/pd-common.h

@@ -118,6 +118,7 @@ struct radio_data {
 	__u32		fm_freq;
 	int		users;
 	unsigned int	is_radio_streaming;
+	int		pre_emphasis;
 	struct video_device *fm_dev;
 };
 
@@ -185,7 +186,6 @@ struct poseidon {
 	struct pd_dvb_adapter	dvb_data;	/* DVB	 */
 
 	u32			state;
-	int			country_code;
 	struct file		*file_for_stream; /* the active stream*/
 
 #ifdef CONFIG_PM
@@ -240,7 +240,6 @@ struct video_device *vdev_init(struct poseidon *, struct video_device *);
 int send_set_req(struct poseidon*, u8, s32, s32*);
 int send_get_req(struct poseidon*, u8, s32, void*, s32*, s32);
 s32 set_tuner_mode(struct poseidon*, unsigned char);
-enum tlg__analog_audio_standard get_audio_std(s32, s32);
 
 /* bulk urb alloc/free */
 int alloc_bulk_urbs_generic(struct urb **urb_array, int num,
@@ -252,7 +251,6 @@ void free_all_urb_generic(struct urb **urb_array, int num);
 /* misc */
 void poseidon_delete(struct kref *kref);
 void destroy_video_device(struct video_device **v_dev);
-extern int country_code;
 extern int debug_mode;
 void set_debug_mode(struct video_device *vfd, int debug_mode);
 

+ 0 - 36
drivers/media/video/tlg2300/pd-main.c

@@ -189,41 +189,6 @@ int set_tuner_mode(struct poseidon *pd, unsigned char mode)
 	return 0;
 }
 
-enum tlg__analog_audio_standard get_audio_std(s32 mode, s32 country_code)
-{
-	s32 nicam[] = {27, 32, 33, 34, 36, 44, 45, 46, 47, 48, 64,
-			65, 86, 351, 352, 353, 354, 358, 372, 852, 972};
-	s32 btsc[] = {1, 52, 54, 55, 886};
-	s32 eiaj[] = {81};
-	s32 i;
-
-	if (mode == TLG_MODE_FM_RADIO) {
-		if (country_code == 1)
-			return TLG_TUNE_ASTD_FM_US;
-		else
-			return TLG_TUNE_ASTD_FM_EUR;
-	} else if (mode == TLG_MODE_ANALOG_TV_UNCOMP) {
-		for (i = 0; i < sizeof(nicam) / sizeof(s32); i++) {
-			if (country_code == nicam[i])
-				return TLG_TUNE_ASTD_NICAM;
-		}
-
-		for (i = 0; i < sizeof(btsc) / sizeof(s32); i++) {
-			if (country_code == btsc[i])
-				return TLG_TUNE_ASTD_BTSC;
-		}
-
-		for (i = 0; i < sizeof(eiaj) / sizeof(s32); i++) {
-			if (country_code == eiaj[i])
-				return TLG_TUNE_ASTD_EIAJ;
-		}
-
-		return TLG_TUNE_ASTD_A2;
-	} else {
-		return TLG_TUNE_ASTD_NONE;
-	}
-}
-
 void poseidon_delete(struct kref *kref)
 {
 	struct poseidon *pd = container_of(kref, struct poseidon, kref);
@@ -462,7 +427,6 @@ static int poseidon_probe(struct usb_interface *interface,
 		struct device *dev = &interface->dev;
 
 		logpm(pd);
-		pd->country_code = 86;
 		mutex_init(&pd->lock);
 
 		/* register v4l2 device */

+ 88 - 19
drivers/media/video/tlg2300/pd-radio.c

@@ -22,9 +22,16 @@ static int poseidon_fm_open(struct file *filp);
 #define TUNER_FREQ_MIN_FM 76000000
 #define TUNER_FREQ_MAX_FM 108000000
 
+#define MAX_PREEMPHASIS (V4L2_PREEMPHASIS_75_uS + 1)
+static int preemphasis[MAX_PREEMPHASIS] = {
+	TLG_TUNE_ASTD_NONE,   /* V4L2_PREEMPHASIS_DISABLED */
+	TLG_TUNE_ASTD_FM_EUR, /* V4L2_PREEMPHASIS_50_uS    */
+	TLG_TUNE_ASTD_FM_US,  /* V4L2_PREEMPHASIS_75_uS    */
+};
+
 static int poseidon_check_mode_radio(struct poseidon *p)
 {
-	int ret, radiomode;
+	int ret;
 	u32 status;
 
 	set_current_state(TASK_INTERRUPTIBLE);
@@ -38,8 +45,8 @@ static int poseidon_check_mode_radio(struct poseidon *p)
 		goto out;
 
 	ret = send_set_req(p, SGNL_SRC_SEL, TLG_SIG_SRC_ANTENNA, &status);
-	radiomode = get_audio_std(TLG_MODE_FM_RADIO, p->country_code);
-	ret = send_set_req(p, TUNER_AUD_ANA_STD, radiomode, &status);
+	ret = send_set_req(p, TUNER_AUD_ANA_STD,
+				p->radio_data.pre_emphasis, &status);
 	ret |= send_set_req(p, TUNER_AUD_MODE,
 				TLG_TUNE_TVAUDIO_MODE_STEREO, &status);
 	ret |= send_set_req(p, AUDIO_SAMPLE_RATE_SEL,
@@ -91,7 +98,9 @@ static int poseidon_fm_open(struct file *filp)
 
 	usb_autopm_get_interface(p->interface);
 	if (0 == p->state) {
-		p->country_code = country_code;
+		/* default pre-emphasis */
+		if (p->radio_data.pre_emphasis == 0)
+			p->radio_data.pre_emphasis = TLG_TUNE_ASTD_FM_EUR;
 		set_debug_mode(vfd, debug_mode);
 
 		ret = poseidon_check_mode_radio(p);
@@ -205,13 +214,12 @@ int fm_get_freq(struct file *file, void *priv, struct v4l2_frequency *argp)
 static int set_frequency(struct poseidon *p, __u32 frequency)
 {
 	__u32 freq ;
-	int ret, status, radiomode;
+	int ret, status;
 
 	mutex_lock(&p->lock);
 
-	radiomode = get_audio_std(TLG_MODE_FM_RADIO, p->country_code);
-	/*NTSC 8,PAL 2 */
-	ret = send_set_req(p, TUNER_AUD_ANA_STD, radiomode, &status);
+	ret = send_set_req(p, TUNER_AUD_ANA_STD,
+				p->radio_data.pre_emphasis, &status);
 
 	freq =  (frequency * 125) * 500 / 1000;/* kHZ */
 	if (freq < TUNER_FREQ_MIN_FM/1000 || freq > TUNER_FREQ_MAX_FM/1000) {
@@ -253,27 +261,86 @@ int fm_set_freq(struct file *file, void *priv, struct v4l2_frequency *argp)
 int tlg_fm_vidioc_g_ctrl(struct file *file, void *priv,
 		struct v4l2_control *arg)
 {
-    return 0;
+	return 0;
+}
+
+int tlg_fm_vidioc_g_exts_ctrl(struct file *file, void *fh,
+				struct v4l2_ext_controls *ctrls)
+{
+	struct poseidon *p = file->private_data;
+	int i;
+
+	if (ctrls->ctrl_class != V4L2_CTRL_CLASS_FM_TX)
+		return -EINVAL;
+
+	for (i = 0; i < ctrls->count; i++) {
+		struct v4l2_ext_control *ctrl = ctrls->controls + i;
+
+		if (ctrl->id != V4L2_CID_TUNE_PREEMPHASIS)
+			continue;
+
+		if (i < MAX_PREEMPHASIS)
+			ctrl->value = p->radio_data.pre_emphasis;
+	}
+	return 0;
 }
 
-int tlg_fm_vidioc_exts_ctrl(struct file *file, void *fh,
-		struct v4l2_ext_controls *a)
+int tlg_fm_vidioc_s_exts_ctrl(struct file *file, void *fh,
+			struct v4l2_ext_controls *ctrls)
 {
-    return 0;
+	int i;
+
+	if (ctrls->ctrl_class != V4L2_CTRL_CLASS_FM_TX)
+		return -EINVAL;
+
+	for (i = 0; i < ctrls->count; i++) {
+		struct v4l2_ext_control *ctrl = ctrls->controls + i;
+
+		if (ctrl->id != V4L2_CID_TUNE_PREEMPHASIS)
+			continue;
+
+		if (ctrl->value >= 0 && ctrl->value < MAX_PREEMPHASIS) {
+			struct poseidon *p = file->private_data;
+			int pre_emphasis = preemphasis[ctrl->value];
+			u32 status;
+
+			send_set_req(p, TUNER_AUD_ANA_STD,
+						pre_emphasis, &status);
+			p->radio_data.pre_emphasis = pre_emphasis;
+		}
+	}
+	return 0;
 }
 
 int tlg_fm_vidioc_s_ctrl(struct file *file, void *priv,
-		struct v4l2_control *arg)
+		struct v4l2_control *ctrl)
 {
-    return 0;
+	return 0;
 }
 
 int tlg_fm_vidioc_queryctrl(struct file *file, void *priv,
-		struct v4l2_queryctrl *arg)
+		struct v4l2_queryctrl *ctrl)
 {
-	arg->minimum = 0;
-	arg->maximum = 65535;
-	return 0;
+	if (!(ctrl->id & V4L2_CTRL_FLAG_NEXT_CTRL))
+		return -EINVAL;
+
+	ctrl->id &= ~V4L2_CTRL_FLAG_NEXT_CTRL;
+	if (ctrl->id != V4L2_CID_TUNE_PREEMPHASIS) {
+		/* return the next supported control */
+		ctrl->id = V4L2_CID_TUNE_PREEMPHASIS;
+		v4l2_ctrl_query_fill(ctrl, V4L2_PREEMPHASIS_DISABLED,
+					V4L2_PREEMPHASIS_75_uS, 1,
+					V4L2_PREEMPHASIS_50_uS);
+		ctrl->flags = V4L2_CTRL_FLAG_UPDATE;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+int tlg_fm_vidioc_querymenu(struct file *file, void *fh,
+				struct v4l2_querymenu *qmenu)
+{
+	return v4l2_ctrl_query_menu(qmenu, NULL, NULL);
 }
 
 static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *vt)
@@ -311,9 +378,11 @@ static const struct v4l2_ioctl_ops poseidon_fm_ioctl_ops = {
 	.vidioc_g_input     = vidioc_g_input,
 	.vidioc_s_input     = vidioc_s_input,
 	.vidioc_queryctrl   = tlg_fm_vidioc_queryctrl,
+	.vidioc_querymenu   = tlg_fm_vidioc_querymenu,
 	.vidioc_g_ctrl      = tlg_fm_vidioc_g_ctrl,
 	.vidioc_s_ctrl      = tlg_fm_vidioc_s_ctrl,
-	.vidioc_s_ext_ctrls = tlg_fm_vidioc_exts_ctrl,
+	.vidioc_s_ext_ctrls = tlg_fm_vidioc_s_exts_ctrl,
+	.vidioc_g_ext_ctrls = tlg_fm_vidioc_g_exts_ctrl,
 	.vidioc_s_tuner     = vidioc_s_tuner,
 	.vidioc_g_tuner     = tlg_fm_vidioc_g_tuner,
 	.vidioc_g_frequency = fm_get_freq,

+ 39 - 20
drivers/media/video/tlg2300/pd-video.c

@@ -15,10 +15,6 @@ static int pm_video_suspend(struct poseidon *pd);
 static int pm_video_resume(struct poseidon *pd);
 static void iso_bubble_handler(struct work_struct *w);
 
-int country_code = 86;
-module_param(country_code, int, 0644);
-MODULE_PARM_DESC(country_code, "country code (e.g China is 86)");
-
 int usb_transfer_mode;
 module_param(usb_transfer_mode, int, 0644);
 MODULE_PARM_DESC(usb_transfer_mode, "0 = Bulk, 1 = Isochronous");
@@ -93,27 +89,53 @@ static struct poseidon_control controls[] = {
 		{ V4L2_CID_BRIGHTNESS, V4L2_CTRL_TYPE_INTEGER,
 			"brightness", 0, 10000, 1, 100, 0, },
 		CUST_PARM_ID_BRIGHTNESS_CTRL
-	},
-
-	{
+	}, {
 		{ V4L2_CID_CONTRAST, V4L2_CTRL_TYPE_INTEGER,
 			"contrast", 0, 10000, 1, 100, 0, },
 		CUST_PARM_ID_CONTRAST_CTRL,
-	},
-
-	{
+	}, {
 		{ V4L2_CID_HUE, V4L2_CTRL_TYPE_INTEGER,
 			"hue", 0, 10000, 1, 100, 0, },
 		CUST_PARM_ID_HUE_CTRL,
-	},
-
-	{
+	}, {
 		{ V4L2_CID_SATURATION, V4L2_CTRL_TYPE_INTEGER,
 			"saturation", 0, 10000, 1, 100, 0, },
 		CUST_PARM_ID_SATURATION_CTRL,
 	},
 };
 
+struct video_std_to_audio_std {
+	v4l2_std_id	video_std;
+	int 		audio_std;
+};
+
+static const struct video_std_to_audio_std video_to_audio_map[] = {
+	/* country : { 27, 32, 33, 34, 36, 44, 45, 46, 47, 48, 64,
+			65, 86, 351, 352, 353, 354, 358, 372, 852, 972 } */
+	{ (V4L2_STD_PAL_I | V4L2_STD_PAL_B | V4L2_STD_PAL_D |
+		V4L2_STD_SECAM_L | V4L2_STD_SECAM_D), TLG_TUNE_ASTD_NICAM },
+
+	/* country : { 1, 52, 54, 55, 886 } */
+	{V4L2_STD_NTSC_M | V4L2_STD_PAL_N | V4L2_STD_PAL_M, TLG_TUNE_ASTD_BTSC},
+
+	/* country : { 81 } */
+	{ V4L2_STD_NTSC_M_JP, TLG_TUNE_ASTD_EIAJ },
+
+	/* other country : TLG_TUNE_ASTD_A2 */
+};
+static const unsigned int map_size = ARRAY_SIZE(video_to_audio_map);
+
+static int get_audio_std(v4l2_std_id v4l2_std)
+{
+	int i = 0;
+
+	for (; i < map_size; i++) {
+		if (v4l2_std & video_to_audio_map[i].video_std)
+			return video_to_audio_map[i].audio_std;
+	}
+	return TLG_TUNE_ASTD_A2;
+}
+
 static int vidioc_querycap(struct file *file, void *fh,
 			struct v4l2_capability *cap)
 {
@@ -1067,7 +1089,7 @@ static int pd_vidioc_s_tuner(struct poseidon *pd, int index)
 	mutex_lock(&pd->lock);
 	param = pd_audio_modes[index].tlg_audio_mode;
 	ret = send_set_req(pd, TUNER_AUD_MODE, param, &cmd_status);
-	audiomode = get_audio_std(TLG_MODE_ANALOG_TV, pd->country_code);
+	audiomode = get_audio_std(pd->video_data.context.tvnormid);
 	ret |= send_set_req(pd, TUNER_AUD_ANA_STD, audiomode,
 				&cmd_status);
 	if (!ret)
@@ -1255,9 +1277,7 @@ static int vidioc_streamoff(struct file *file, void *fh,
 	return videobuf_streamoff(&front->q);
 }
 
-/*
- * Set the firmware' default values : need altersetting and country code
- */
+/* Set the firmware's default values : need altersetting */
 static int pd_video_checkmode(struct poseidon *pd)
 {
 	s32 ret = 0, cmd_status, audiomode;
@@ -1286,8 +1306,8 @@ static int pd_video_checkmode(struct poseidon *pd)
 	ret |= send_set_req(pd, TUNE_FREQ_SELECT, TUNER_FREQ_MIN, &cmd_status);
 	ret |= send_set_req(pd, VBI_DATA_SEL, 1, &cmd_status);/* enable vbi */
 
-	/* need country code to set the audio */
-	audiomode = get_audio_std(TLG_MODE_ANALOG_TV, pd->country_code);
+	/* set the audio */
+	audiomode = get_audio_std(pd->video_data.context.tvnormid);
 	ret |= send_set_req(pd, TUNER_AUD_ANA_STD, audiomode, &cmd_status);
 	ret |= send_set_req(pd, TUNER_AUD_MODE,
 				TLG_TUNE_TVAUDIO_MODE_STEREO, &cmd_status);
@@ -1392,7 +1412,6 @@ static int pd_video_open(struct file *file)
 			goto out;
 
 		pd->cur_transfer_mode	= usb_transfer_mode;/* bulk or iso */
-		pd->country_code	= country_code;
 		init_video_context(&pd->video_data.context);
 
 		ret = pd_video_checkmode(pd);