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.c ivtv-0.3.7b/driver/tuner.c
--- org/ivtv-0.3.7b/driver/tuner.c	2005-07-25 15:08:08.000000000 +0200
+++ ivtv-0.3.7b/driver/tuner.c	2005-08-07 19:46:44.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:
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) {

Reply via email to