And now with the correct patch :-)

                Hans

On Sunday 07 August 2005 21:48, Hans Verkuil wrote:
> This patch adds support for the 2.6.13-rc4 kernel tuner code: changes are
> twofold: the old TUNER_SET_TYPE command is replaced by a
> TUNER_SET_TYPE_ADDR command, and the radio frequencies are now not
> multiplied by 16 but by 16000.
>
> This patch should still work for older kernels.
>
> Also the radio support has been improved somewhat: right after loading ivtv
> the radio wouldn't work until setting the TV frequency to a channel. During
> ivtv initialization I now run a VIDIOC_S_FREQUENCY ioctl that ensures that
> the audio support chips are also correctly setup, and the radio utility has
> also been adapted: it now contains a hack where it sets the frequency
> twice, which somehow forces the correct behavior.
>
> This still needs more research since all this shouldn't be necessary, but I
> haven't (yet) found the magic bullet.
>
> Regards,
>
>               Hans
diff -ru org/ivtv-0.3.7b/doc/README.radio ivtv-0.3.7b/doc/README.radio
--- org/ivtv-0.3.7b/doc/README.radio	2005-06-29 14:27:18.000000000 +0200
+++ ivtv-0.3.7b/doc/README.radio	2005-08-07 21:10:46.000000000 +0200
@@ -50,6 +50,11 @@
 when trying to read from /dev/video24. Using 'cat </dev/video0 >/dev/video16'
 for a few seconds seems to fix the problem and I can use /dev/video24 again.
 
+If you use the '-g' option and you select an out-of-range frequency (e.g. 0),
+then for some reason changing to a valid frequency will fail. The only solution
+I know is to break off the radio application and start it again. There is still
+something strange in the radio tuner support.
+
 Driver Implementation Details
 =============================
 
@@ -61,10 +66,6 @@
 The last selected TV and radio frequencies are remembered and restored when
 closing/opening the radio device.
 
-At the moment there is no passthrough mode yet, so the only way to get the
-audio is by using /dev/video0 (which gives an MPEG stream with black video)
-or by using /dev/video24 (PCM stream).
-
 For the FM tuner the msp device also maps the input to msp input 2 instead
 of 3, which is used by the TV tuner.
 
@@ -77,8 +78,5 @@
    are swapped or not? If they are, then the PCM stream must also use do byte
    swapping like the MPG and VBI streams.
 
-2) Is it possible to get RBDS / RDS data? If so, add functionality to display
-   that.
-
-3) Perhaps the 'video24' device should be turned into a ALSA driver with
+2) Perhaps the 'video24' device should be turned into a ALSA driver with
    mixer support, etc. I'm not sure if this is possible or desirable.
diff -ru org/ivtv-0.3.7b/driver/ivtv-driver.c ivtv-0.3.7b/driver/ivtv-driver.c
--- org/ivtv-0.3.7b/driver/ivtv-driver.c	2005-08-02 15:01:54.000000000 +0200
+++ ivtv-0.3.7b/driver/ivtv-driver.c	2005-08-07 21:04:44.000000000 +0200
@@ -873,7 +873,7 @@
 {
 	int retval = 0;
 	struct ivtv *itv;
-	int freq = 0;
+        struct v4l2_frequency vf;
 	int norm;
 
 	IVTV_DEBUG(IVTV_DEBUG_INFO, "Found card #%d\n", ivtv_cards_active);
@@ -1134,12 +1134,25 @@
 
 	if (itv->options.tuner > -1) {
 		IVTV_KERN_INFO("Setting Tuner %d\n", itv->options.tuner);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13)
+                {
+                        struct tuner_setup setup;
+
+                        setup.addr = ADDR_UNSET;
+                        setup.type = itv->options.tuner;
+                        setup.mode_mask = T_RADIO | T_ANALOG_TV;
+        		ivtv_tuner(itv, TUNER_SET_TYPE_ADDR, &setup);
+                }
+#else
 		ivtv_tuner(itv, TUNER_SET_TYPE, &(itv->options.tuner));
+#endif
 	}
 
+        vf.tuner = 0;
+        vf.frequency = 6400; /* the tuner 'baseline' frequency */
 	if (itv->std & V4L2_STD_NTSC) {
 		/* Why on earth? */
-		freq = 1076;	/* ch. 4 67250*16/1000 */
+		vf.frequency = 1076;	/* ch. 4 67250*16/1000 */
 	}
 
 	/* The tuner is fixed to the norm. The other inputs (e.g. S-Video)
@@ -1151,10 +1164,6 @@
         /* Digitizer */
 	itv->card->video_dec_func(itv, DECODER_SET_NORM, &norm);
 
-	/* set the channel */
-	if (freq)
-		ivtv_tuner(itv, VIDIOCSFREQ, &freq);
-
 	/* Change Input to active, 150 needs this, seems right */
 	itv->card->video_dec_func(itv, DECODER_SET_INPUT, &itv->active_input);
 
@@ -1165,6 +1174,7 @@
 	   in one place. */
 	itv->std++;		// Force full standard initialization
 	ivtv_v4l2_ioctls(itv, NULL, 0, VIDIOC_S_STD, &itv->tuner_std);
+	ivtv_v4l2_ioctls(itv, NULL, 0, VIDIOC_S_FREQUENCY, &vf);
 
 	IVTV_KERN_INFO("Initialized %s, card #%d\n", itv->card->name, itv->num);
 
diff -ru org/ivtv-0.3.7b/driver/ivtv-ioctl.c ivtv-0.3.7b/driver/ivtv-ioctl.c
--- org/ivtv-0.3.7b/driver/ivtv-ioctl.c	2005-08-02 15:01:54.000000000 +0200
+++ ivtv-0.3.7b/driver/ivtv-ioctl.c	2005-08-07 20:45:04.000000000 +0200
@@ -1800,7 +1800,11 @@
 			return -EINVAL;
 		if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) {
 			vf->type = V4L2_TUNER_RADIO;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13)
+			vf->frequency = itv->freq_radio / 1000;
+#else
 			vf->frequency = itv->freq_radio;
+#endif
 		} else {
 			vf->type = V4L2_TUNER_ANALOG_TV;
 			vf->frequency = itv->freq_tv;
@@ -1811,6 +1815,7 @@
 
 	case VIDIOC_S_FREQUENCY:{
 		struct v4l2_frequency *vf = arg;
+                int freq = vf->frequency;
 
 		IVTV_DEBUG(IVTV_DEBUG_INFO, "v4l2 ioctl: set frequency\n");
 
@@ -1822,17 +1827,20 @@
 		down(&stream->mlock);
 
 		if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) {
-			itv->freq_radio = vf->frequency;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13)
+                        freq *= 1000;
+#endif
+			itv->freq_radio = freq;
 			vf->type = V4L2_TUNER_RADIO; /* not always set, and needed by IF demod */
 		} else {
-			itv->freq_tv = vf->frequency;
+			itv->freq_tv = freq;
 			vf->type = V4L2_TUNER_ANALOG_TV;
 		}
 
 		mute_and_pause(itv);
 		IVTV_DEBUG(IVTV_DEBUG_INFO,
 			   "v4l2 ioctl: set frequency %d\n", vf->frequency);
-		ivtv_tuner(itv, VIDIOCSFREQ, &vf->frequency);
+		ivtv_tuner(itv, VIDIOCSFREQ, &freq);
 		if(tda9887 == 0) ivtv_tda9887(itv, VIDIOC_S_FREQUENCY, vf);
 		ivtv_audio_freq_changed(itv);
 		unmute_and_resume(itv, 1);
diff -ru org/ivtv-0.3.7b/driver/tuner.h ivtv-0.3.7b/driver/tuner.h
--- org/ivtv-0.3.7b/driver/tuner.h	2005-05-12 15:04:38.000000000 +0200
+++ ivtv-0.3.7b/driver/tuner.h	2005-08-07 19:46:10.000000000 +0200
@@ -102,9 +102,29 @@
 #define TCL     11
 #define THOMSON 12
 
+// For 2.6.13
+#define ADDR_UNSET (255)
+
+enum tuner_mode {
+	T_UNINITIALIZED = 0,
+	T_RADIO		= 1 << V4L2_TUNER_RADIO,
+	T_ANALOG_TV     = 1 << V4L2_TUNER_ANALOG_TV,
+	T_DIGITAL_TV    = 1 << V4L2_TUNER_DIGITAL_TV,
+	T_STANDBY	= 1 << 31
+};
+
+struct tuner_setup {
+	unsigned short		addr;
+	unsigned int		type;
+	unsigned int		mode_mask;
+};
+
+#define TUNER_SET_TYPE_ADDR          _IOW('T',3,int)
+// End of 2.6.13 section
+
 #define TUNER_SET_TYPE               _IOW('t',1,int)	/* set tuner type */
-#define TUNER_SET_TVFREQ             _IOW('t',2,int)	/* set tv freq */
 #if 0				/* obsolete */
+#define TUNER_SET_TVFREQ             _IOW('t',2,int)	/* set tv freq */
 # define TUNER_SET_RADIOFREQ         _IOW('t',3,int)	/* set radio freq */
 # define TUNER_SET_MODE              _IOW('t',4,int)	/* set tuner mode */
 #endif
diff -ru org/ivtv-0.3.7b/utils/radio.c ivtv-0.3.7b/utils/radio.c
--- org/ivtv-0.3.7b/utils/radio.c	2005-06-29 14:27:18.000000000 +0200
+++ ivtv-0.3.7b/utils/radio.c	2005-08-07 21:06:07.000000000 +0200
@@ -25,7 +25,6 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
@@ -249,7 +248,24 @@
 		}
 	}
 
-	cfg.fh = open(cfg.radio_dev, O_RDONLY);
+        /* There is still something weird when tuning the radio. If the
+           radio is started as the first thing after loading ivtv, then
+           we have to open the radio, set the frequency and close it again
+           once, otherwise frequency changes do not work.
+           I don't know if this is a tuner issue or an ivtv issue (or both),
+           but until someone gets to the bottom of this, this trick will suffice. */
+	cfg.fh = open(cfg.radio_dev, O_RDWR);
+	if (cfg.fh == -1) {
+		perror("radio");
+		fprintf(stderr, "cannot open %s\n", cfg.radio_dev);
+		exit(1);
+	}
+	cfg.freq.tuner = 0;
+	ioctl(cfg.fh, VIDIOC_S_FREQUENCY, &cfg.freq);
+        close(cfg.fh);
+
+
+	cfg.fh = open(cfg.radio_dev, O_RDWR);
 	if (cfg.fh == -1) {
 		perror("radio");
 		fprintf(stderr, "cannot open %s\n", cfg.radio_dev);
@@ -259,6 +275,7 @@
 	cfg.freq.tuner = 0;
 	printf("set to freq %3.2f\n", cfg.freq.frequency / 16.0);
 	ioctl(cfg.fh, VIDIOC_S_FREQUENCY, &cfg.freq);
+	ioctl(cfg.fh, VIDIOC_S_FREQUENCY, &cfg.freq);
 
 	if (cfg.passthrough) {
 		if (ioctl(cfg.fh, IVTV_IOC_PASSTHROUGH, &cfg.passthrough) < 0) {
diff -ru org/ivtv-0.3.7b/driver/tuner.c ivtv-0.3.7b/driver/tuner.c
--- ivtv/driver/tuner.c	2005-08-07 21:25:53.000000000 +0200
+++ ivtv-0.3.7b/driver/tuner.c	2005-08-07 21:44:48.000000000 +0200
@@ -1232,7 +1232,10 @@
 	switch (cmd) {
 
 		/* --- configuration --- */
-	case TUNER_SET_TYPE:
+	case TUNER_SET_TYPE_ADDR:  /* 2.6.13 API */
+                set_type(client, ((struct tuner_setup *)arg)->type, client->adapter->name);
+                break;
+	case TUNER_SET_TYPE:  /* 2.6.12 and lower API */
 		set_type(client, *iarg, client->adapter->name);
 		break;
 	case AUDC_SET_RADIO:
@@ -1283,10 +1283,15 @@
 	}
 	case VIDIOCSFREQ:
 	{
-		unsigned long *v = arg;
+		unsigned long v = *(unsigned long *)arg;
 
 		CHECK_V4L2;
-		set_freq(client, *v);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13)
+		if (t->radio) {
+                        v /= 1000;
+                }
+#endif
+		set_freq(client, v);
 		return 0;
 	}
 	case VIDIOCGTUNER:
@@ -1337,6 +1342,11 @@
 			}
 		}
 		t->freq = f->frequency;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13)
+		if (V4L2_TUNER_RADIO == f->type) {
+                        t->freq /= 1000;
+                }
+#endif
 		set_freq(client, t->freq);
 		break;
 	}

Reply via email to