Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[media] tuner-core/simple: get_rf_strength can be tuner mode specific

The get_rf_strength op in tuner-simple is valid only for the radio mode.
But due to the way get_signal in analog_demod_ops was designed it would
overwrite the signal value with a bogus value when in TV mode.
Pass a pointer to the signal value instead, and when not in radio mode
leave it alone in the tuner-simple.
This broke in commit 030755bde42bbed133182b0ece7c7a9c759478e8
(tuner-core: call has_signal for both TV and radio) in kernel 3.6. Before
that this was working correctly. That commit did the right thing, but what
wasn't realized at the time was that tuner-simple should have been updated
as well to restrict setting the signal strength to the radio mode only.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

authored by

Hans Verkuil and committed by
Mauro Carvalho Chehab
dfc2e12d a2192cf4

+27 -24
+1 -1
drivers/media/dvb-core/dvb_frontend.h
··· 245 245 246 246 void (*set_params)(struct dvb_frontend *fe, 247 247 struct analog_parameters *params); 248 - int (*has_signal)(struct dvb_frontend *fe); 248 + int (*has_signal)(struct dvb_frontend *fe, u16 *signal); 249 249 int (*get_afc)(struct dvb_frontend *fe, s32 *afc); 250 250 void (*tuner_status)(struct dvb_frontend *fe); 251 251 void (*standby)(struct dvb_frontend *fe);
+9 -6
drivers/media/tuners/tda8290.c
··· 391 391 tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_val, 2); 392 392 } 393 393 394 - static int tda8295_has_signal(struct dvb_frontend *fe) 394 + static int tda8295_has_signal(struct dvb_frontend *fe, u16 *signal) 395 395 { 396 396 struct tda8290_priv *priv = fe->analog_demod_priv; 397 397 ··· 399 399 unsigned char ret; 400 400 401 401 tuner_i2c_xfer_send_recv(&priv->i2c_props, &hvpll_stat, 1, &ret, 1); 402 - return (ret & 0x01) ? 65535 : 0; 402 + *signal = (ret & 0x01) ? 65535 : 0; 403 + return 0; 403 404 } 404 405 405 406 /*---------------------------------------------------------------------*/ ··· 409 408 struct analog_parameters *params) 410 409 { 411 410 struct tda8290_priv *priv = fe->analog_demod_priv; 412 - 411 + u16 signal = 0; 413 412 unsigned char blanking_mode[] = { 0x1d, 0x00 }; 414 413 415 414 set_audio(fe, params); ··· 437 436 if (priv->cfg.agcf) 438 437 priv->cfg.agcf(fe); 439 438 440 - if (tda8295_has_signal(fe)) 439 + tda8295_has_signal(fe, &signal); 440 + if (signal) 441 441 tuner_dbg("tda8295 is locked\n"); 442 442 else 443 443 tuner_dbg("tda8295 not locked, no signal?\n"); ··· 449 447 450 448 /*---------------------------------------------------------------------*/ 451 449 452 - static int tda8290_has_signal(struct dvb_frontend *fe) 450 + static int tda8290_has_signal(struct dvb_frontend *fe, u16 *signal) 453 451 { 454 452 struct tda8290_priv *priv = fe->analog_demod_priv; 455 453 ··· 458 456 459 457 tuner_i2c_xfer_send_recv(&priv->i2c_props, 460 458 i2c_get_afc, ARRAY_SIZE(i2c_get_afc), &afc, 1); 461 - return (afc & 0x80)? 65535:0; 459 + *signal = (afc & 0x80) ? 65535 : 0; 460 + return 0; 462 461 } 463 462 464 463 /*---------------------------------------------------------------------*/
+4 -1
drivers/media/tuners/tuner-simple.c
··· 115 115 116 116 u32 frequency; 117 117 u32 bandwidth; 118 + bool radio_mode; 118 119 }; 119 120 120 121 /* ---------------------------------------------------------------------- */ ··· 190 189 struct tuner_simple_priv *priv = fe->tuner_priv; 191 190 int signal; 192 191 193 - if (priv->i2c_props.adap == NULL) 192 + if (priv->i2c_props.adap == NULL || !priv->radio_mode) 194 193 return -EINVAL; 195 194 196 195 signal = tuner_signal(tuner_read_status(fe)); ··· 777 776 778 777 switch (params->mode) { 779 778 case V4L2_TUNER_RADIO: 779 + priv->radio_mode = true; 780 780 ret = simple_set_radio_freq(fe, params); 781 781 priv->frequency = params->frequency * 125 / 2; 782 782 break; 783 783 case V4L2_TUNER_ANALOG_TV: 784 784 case V4L2_TUNER_DIGITAL_TV: 785 + priv->radio_mode = false; 785 786 ret = simple_set_tv_freq(fe, params); 786 787 priv->frequency = params->frequency * 62500; 787 788 break;
+13 -16
drivers/media/v4l2-core/tuner-core.c
··· 218 218 fe_tuner_ops->sleep(fe); 219 219 } 220 220 221 - static int fe_has_signal(struct dvb_frontend *fe) 222 - { 223 - u16 strength; 224 - 225 - if (fe->ops.tuner_ops.get_rf_strength(fe, &strength) < 0) 226 - return 0; 227 - 228 - return strength; 229 - } 230 - 231 221 static int fe_set_config(struct dvb_frontend *fe, void *priv_cfg) 232 222 { 233 223 struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops; ··· 426 436 sizeof(struct analog_demod_ops)); 427 437 428 438 if (fe_tuner_ops->get_rf_strength) 429 - analog_ops->has_signal = fe_has_signal; 439 + analog_ops->has_signal = fe_tuner_ops->get_rf_strength; 430 440 if (fe_tuner_ops->get_afc) 431 441 analog_ops->get_afc = fe_tuner_ops->get_afc; 432 442 ··· 1050 1060 if (tuner_status & TUNER_STATUS_STEREO) 1051 1061 tuner_info("Stereo: yes\n"); 1052 1062 } 1053 - if (analog_ops->has_signal) 1054 - tuner_info("Signal strength: %d\n", 1055 - analog_ops->has_signal(fe)); 1063 + if (analog_ops->has_signal) { 1064 + u16 signal; 1065 + 1066 + if (!analog_ops->has_signal(fe, &signal)) 1067 + tuner_info("Signal strength: %hu\n", signal); 1068 + } 1056 1069 } 1057 1070 1058 1071 /* ··· 1174 1181 return 0; 1175 1182 if (vt->type == t->mode && analog_ops->get_afc) 1176 1183 analog_ops->get_afc(&t->fe, &vt->afc); 1177 - if (analog_ops->has_signal) 1178 - vt->signal = analog_ops->has_signal(&t->fe); 1184 + if (vt->type == t->mode && analog_ops->has_signal) { 1185 + u16 signal = (u16)vt->signal; 1186 + 1187 + if (!analog_ops->has_signal(&t->fe, &signal)) 1188 + vt->signal = signal; 1189 + } 1179 1190 if (vt->type != V4L2_TUNER_RADIO) { 1180 1191 vt->capability |= V4L2_TUNER_CAP_NORM; 1181 1192 vt->rangelow = tv_range[0] * 16;