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) {