|
@@ -82,7 +82,7 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq)
|
|
|
tuner_warn ("tuner type not set\n");
|
|
|
return;
|
|
|
}
|
|
|
- if (NULL == t->tv_freq) {
|
|
|
+ if (NULL == t->set_tv_freq) {
|
|
|
tuner_warn ("Tuner has no way to set tv freq\n");
|
|
|
return;
|
|
|
}
|
|
@@ -90,8 +90,14 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq)
|
|
|
tuner_dbg ("TV freq (%d.%02d) out of range (%d-%d)\n",
|
|
|
freq / 16, freq % 16 * 100 / 16, tv_range[0],
|
|
|
tv_range[1]);
|
|
|
+ /* V4L2 spec: if the freq is not possible then the closest
|
|
|
+ possible value should be selected */
|
|
|
+ if (freq < tv_range[0] * 16)
|
|
|
+ freq = tv_range[0] * 16;
|
|
|
+ else
|
|
|
+ freq = tv_range[1] * 16;
|
|
|
}
|
|
|
- t->tv_freq(c, freq);
|
|
|
+ t->set_tv_freq(c, freq);
|
|
|
}
|
|
|
|
|
|
static void set_radio_freq(struct i2c_client *c, unsigned int freq)
|
|
@@ -102,18 +108,23 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq)
|
|
|
tuner_warn ("tuner type not set\n");
|
|
|
return;
|
|
|
}
|
|
|
- if (NULL == t->radio_freq) {
|
|
|
+ if (NULL == t->set_radio_freq) {
|
|
|
tuner_warn ("tuner has no way to set radio frequency\n");
|
|
|
return;
|
|
|
}
|
|
|
- if (freq <= radio_range[0] * 16000 || freq >= radio_range[1] * 16000) {
|
|
|
+ if (freq < radio_range[0] * 16000 || freq > radio_range[1] * 16000) {
|
|
|
tuner_dbg ("radio freq (%d.%02d) out of range (%d-%d)\n",
|
|
|
freq / 16000, freq % 16000 * 100 / 16000,
|
|
|
radio_range[0], radio_range[1]);
|
|
|
+ /* V4L2 spec: if the freq is not possible then the closest
|
|
|
+ possible value should be selected */
|
|
|
+ if (freq < radio_range[0] * 16000)
|
|
|
+ freq = radio_range[0] * 16000;
|
|
|
+ else
|
|
|
+ freq = radio_range[1] * 16000;
|
|
|
}
|
|
|
|
|
|
- t->radio_freq(c, freq);
|
|
|
- return;
|
|
|
+ t->set_radio_freq(c, freq);
|
|
|
}
|
|
|
|
|
|
static void set_freq(struct i2c_client *c, unsigned long freq)
|
|
@@ -125,15 +136,16 @@ static void set_freq(struct i2c_client *c, unsigned long freq)
|
|
|
tuner_dbg("radio freq set to %lu.%02lu\n",
|
|
|
freq / 16000, freq % 16000 * 100 / 16000);
|
|
|
set_radio_freq(c, freq);
|
|
|
+ t->radio_freq = freq;
|
|
|
break;
|
|
|
case V4L2_TUNER_ANALOG_TV:
|
|
|
case V4L2_TUNER_DIGITAL_TV:
|
|
|
tuner_dbg("tv freq set to %lu.%02lu\n",
|
|
|
freq / 16, freq % 16 * 100 / 16);
|
|
|
set_tv_freq(c, freq);
|
|
|
+ t->tv_freq = freq;
|
|
|
break;
|
|
|
}
|
|
|
- t->freq = freq;
|
|
|
}
|
|
|
|
|
|
static void set_type(struct i2c_client *c, unsigned int type,
|
|
@@ -212,7 +224,7 @@ static void set_type(struct i2c_client *c, unsigned int type,
|
|
|
if (t->mode_mask == T_UNINITIALIZED)
|
|
|
t->mode_mask = new_mode_mask;
|
|
|
|
|
|
- set_freq(c, t->freq);
|
|
|
+ set_freq(c, (V4L2_TUNER_RADIO == t->mode) ? t->radio_freq : t->tv_freq);
|
|
|
tuner_dbg("%s %s I2C addr 0x%02x with type %d used for 0x%02x\n",
|
|
|
c->adapter->name, c->driver->driver.name, c->addr << 1, type,
|
|
|
t->mode_mask);
|
|
@@ -377,11 +389,11 @@ static void tuner_status(struct i2c_client *client)
|
|
|
default: p = "undefined"; break;
|
|
|
}
|
|
|
if (t->mode == V4L2_TUNER_RADIO) {
|
|
|
- freq = t->freq / 16000;
|
|
|
- freq_fraction = (t->freq % 16000) * 100 / 16000;
|
|
|
+ freq = t->radio_freq / 16000;
|
|
|
+ freq_fraction = (t->radio_freq % 16000) * 100 / 16000;
|
|
|
} else {
|
|
|
- freq = t->freq / 16;
|
|
|
- freq_fraction = (t->freq % 16) * 100 / 16;
|
|
|
+ freq = t->tv_freq / 16;
|
|
|
+ freq_fraction = (t->tv_freq % 16) * 100 / 16;
|
|
|
}
|
|
|
tuner_info("Tuner mode: %s\n", p);
|
|
|
tuner_info("Frequency: %lu.%02lu MHz\n", freq, freq_fraction);
|
|
@@ -456,7 +468,7 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
|
|
|
t->type = TUNER_TEA5767;
|
|
|
t->mode_mask = T_RADIO;
|
|
|
t->mode = T_STANDBY;
|
|
|
- t->freq = 87.5 * 16; /* Sets freq to FM range */
|
|
|
+ t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */
|
|
|
default_mode_mask &= ~T_RADIO;
|
|
|
|
|
|
goto register_client;
|
|
@@ -469,7 +481,8 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
|
|
|
if (default_mode_mask != T_UNINITIALIZED) {
|
|
|
tuner_dbg ("Setting mode_mask to 0x%02x\n", default_mode_mask);
|
|
|
t->mode_mask = default_mode_mask;
|
|
|
- t->freq = 400 * 16; /* Sets freq to VHF High */
|
|
|
+ t->tv_freq = 400 * 16; /* Sets freq to VHF High */
|
|
|
+ t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */
|
|
|
default_mode_mask = T_UNINITIALIZED;
|
|
|
}
|
|
|
|
|
@@ -565,16 +578,18 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
|
|
|
set_addr(client, (struct tuner_setup *)arg);
|
|
|
break;
|
|
|
case AUDC_SET_RADIO:
|
|
|
- set_mode(client,t,V4L2_TUNER_RADIO, "AUDC_SET_RADIO");
|
|
|
+ if (set_mode(client, t, V4L2_TUNER_RADIO, "AUDC_SET_RADIO")
|
|
|
+ == EINVAL)
|
|
|
+ return 0;
|
|
|
+ if (t->radio_freq)
|
|
|
+ set_freq(client, t->radio_freq);
|
|
|
break;
|
|
|
case TUNER_SET_STANDBY:
|
|
|
- {
|
|
|
- if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL)
|
|
|
- return 0;
|
|
|
- if (t->standby)
|
|
|
- t->standby (client);
|
|
|
- break;
|
|
|
- }
|
|
|
+ if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL)
|
|
|
+ return 0;
|
|
|
+ if (t->standby)
|
|
|
+ t->standby (client);
|
|
|
+ break;
|
|
|
case VIDIOCSAUDIO:
|
|
|
if (check_mode(t, "VIDIOCSAUDIO") == EINVAL)
|
|
|
return 0;
|
|
@@ -583,7 +598,6 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
|
|
|
|
|
|
/* Should be implemented, since bttv calls it */
|
|
|
tuner_dbg("VIDIOCSAUDIO not implemented.\n");
|
|
|
-
|
|
|
break;
|
|
|
/* --- v4l ioctls --- */
|
|
|
/* take care: bttv does userspace copying, we'll get a
|
|
@@ -609,8 +623,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
|
|
|
if (vc->norm < ARRAY_SIZE(map))
|
|
|
t->std = map[vc->norm];
|
|
|
tuner_fixup_std(t);
|
|
|
- if (t->freq)
|
|
|
- set_tv_freq(client, t->freq);
|
|
|
+ if (t->tv_freq)
|
|
|
+ set_tv_freq(client, t->tv_freq);
|
|
|
return 0;
|
|
|
}
|
|
|
case VIDIOCSFREQ:
|
|
@@ -684,15 +698,14 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
|
|
|
|
|
|
t->std = *id;
|
|
|
tuner_fixup_std(t);
|
|
|
- if (t->freq)
|
|
|
- set_freq(client, t->freq);
|
|
|
+ if (t->tv_freq)
|
|
|
+ set_freq(client, t->tv_freq);
|
|
|
break;
|
|
|
}
|
|
|
case VIDIOC_S_FREQUENCY:
|
|
|
{
|
|
|
struct v4l2_frequency *f = arg;
|
|
|
|
|
|
- t->freq = f->frequency;
|
|
|
switch_v4l2();
|
|
|
if (V4L2_TUNER_RADIO == f->type &&
|
|
|
V4L2_TUNER_RADIO != t->mode) {
|
|
@@ -700,7 +713,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
|
|
|
== EINVAL)
|
|
|
return 0;
|
|
|
}
|
|
|
- set_freq(client,t->freq);
|
|
|
+ set_freq(client,f->frequency);
|
|
|
|
|
|
break;
|
|
|
}
|
|
@@ -712,7 +725,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
|
|
|
return 0;
|
|
|
switch_v4l2();
|
|
|
f->type = t->mode;
|
|
|
- f->frequency = t->freq;
|
|
|
+ f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
|
|
|
+ t->radio_freq : t->tv_freq;
|
|
|
break;
|
|
|
}
|
|
|
case VIDIOC_G_TUNER:
|
|
@@ -763,7 +777,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
|
|
|
|
|
|
if (V4L2_TUNER_RADIO == t->mode) {
|
|
|
t->audmode = tuner->audmode;
|
|
|
- set_radio_freq(client, t->freq);
|
|
|
+ set_radio_freq(client, t->radio_freq);
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
@@ -791,8 +805,13 @@ static int tuner_resume(struct device *dev)
|
|
|
struct tuner *t = i2c_get_clientdata (c);
|
|
|
|
|
|
tuner_dbg ("resume\n");
|
|
|
- if (t->freq)
|
|
|
- set_freq(c, t->freq);
|
|
|
+ if (V4L2_TUNER_RADIO == t->mode) {
|
|
|
+ if (t->radio_freq)
|
|
|
+ set_freq(c, t->radio_freq);
|
|
|
+ } else {
|
|
|
+ if (t->tv_freq)
|
|
|
+ set_freq(c, t->tv_freq);
|
|
|
+ }
|
|
|
return 0;
|
|
|
}
|
|
|
|