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;
}