diff options
Diffstat (limited to 'drivers/media/video/tuner-xc2028.c')
-rw-r--r-- | drivers/media/video/tuner-xc2028.c | 88 |
1 files changed, 51 insertions, 37 deletions
diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index 9743331c895..cf72f22986a 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -50,6 +50,7 @@ static DEFINE_MUTEX(xc2028_list_mutex); struct firmware_description { unsigned int type; v4l2_std_id id; + __u16 int_freq; unsigned char *ptr; unsigned int size; }; @@ -58,6 +59,7 @@ struct firmware_properties { unsigned int type; v4l2_std_id id; v4l2_std_id std_req; + __u16 int_freq; unsigned int scode_table; int scode_nr; }; @@ -301,6 +303,7 @@ static int load_all_firmwares(struct dvb_frontend *fe) while (p < endp) { __u32 type, size; v4l2_std_id id; + __u16 int_freq = 0; n++; if (n >= n_array) { @@ -321,6 +324,11 @@ static int load_all_firmwares(struct dvb_frontend *fe) id = le64_to_cpu(*(v4l2_std_id *) p); p += sizeof(id); + if (type & HAS_IF) { + int_freq = le16_to_cpu(*(__u16 *) p); + p += sizeof(int_freq); + } + size = le32_to_cpu(*(__u32 *) p); p += sizeof(size); @@ -351,6 +359,7 @@ static int load_all_firmwares(struct dvb_frontend *fe) priv->firm[n].type = type; priv->firm[n].id = id; priv->firm[n].size = size; + priv->firm[n].int_freq = int_freq; p += size; } @@ -565,7 +574,7 @@ static int load_firmware(struct dvb_frontend *fe, unsigned int type, } static int load_scode(struct dvb_frontend *fe, unsigned int type, - v4l2_std_id *id, int scode) + v4l2_std_id *id, __u16 int_freq, int scode) { struct xc2028_data *priv = fe->tuner_priv; int pos, rc; @@ -573,17 +582,34 @@ static int load_scode(struct dvb_frontend *fe, unsigned int type, tuner_dbg("%s called\n", __FUNCTION__); - pos = seek_firmware(fe, type, id); - if (pos < 0) - return pos; + if (!int_freq) { + pos = seek_firmware(fe, type, id); + if (pos < 0) + return pos; + } else { + for (pos = 0; pos < priv->firm_size; pos++) { + if ((priv->firm[pos].int_freq == int_freq) && + (type & HAS_IF)) + break; + } + if (pos == priv->firm_size) + return -ENOENT; + } p = priv->firm[pos].ptr; - /* 16 SCODE entries per file; each SCODE entry is 12 bytes and - * has a 2-byte size header in the firmware format. */ - if (priv->firm[pos].size != 14 * 16 || scode >= 16 || - le16_to_cpu(*(__u16 *)(p + 14 * scode)) != 12) - return -EINVAL; + if (type & HAS_IF) { + if (priv->firm[pos].size != 12 * 16 || scode >= 16) + return -EINVAL; + p += 12 * scode; + } else { + /* 16 SCODE entries per file; each SCODE entry is 12 bytes and + * has a 2-byte size header in the firmware format. */ + if (priv->firm[pos].size != 14 * 16 || scode >= 16 || + le16_to_cpu(*(__u16 *)(p + 14 * scode)) != 12) + return -EINVAL; + p += 14 * scode + 2; + } tuner_info("Loading SCODE for type="); dump_firm_type(priv->firm[pos].type); @@ -597,7 +623,7 @@ static int load_scode(struct dvb_frontend *fe, unsigned int type, if (rc < 0) return -EIO; - rc = i2c_send(priv, p + 14 * scode + 2, 12); + rc = i2c_send(priv, p, 12); if (rc < 0) return -EIO; @@ -609,7 +635,7 @@ static int load_scode(struct dvb_frontend *fe, unsigned int type, } static int check_firmware(struct dvb_frontend *fe, unsigned int type, - v4l2_std_id std) + v4l2_std_id std, __u16 int_freq) { struct xc2028_data *priv = fe->tuner_priv; struct firmware_properties new_fw; @@ -639,6 +665,7 @@ retry: new_fw.std_req = std; new_fw.scode_table = SCODE | priv->ctrl.scode_table; new_fw.scode_nr = 0; + new_fw.int_freq = int_freq; tuner_dbg("checking firmware, user requested type="); if (debug) { @@ -719,8 +746,8 @@ skip_std_specific: /* Load SCODE firmware, if exists */ tuner_dbg("Trying to load scode %d\n", new_fw.scode_nr); - rc = load_scode(fe, new_fw.type | new_fw.scode_table, - &new_fw.id, new_fw.scode_nr); + rc = load_scode(fe, new_fw.type | new_fw.scode_table, &new_fw.id, + new_fw.int_freq, new_fw.scode_nr); check_device: if (xc2028_get_reg(priv, 0x0004, &version) < 0 || @@ -810,9 +837,10 @@ ret: #define DIV 15625 static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */, - enum tuner_mode new_mode, - unsigned int type, - v4l2_std_id std) + enum tuner_mode new_mode, + unsigned int type, + v4l2_std_id std, + u16 int_freq) { struct xc2028_data *priv = fe->tuner_priv; int rc = -EINVAL; @@ -825,7 +853,7 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */, tuner_dbg("should set frequency %d kHz\n", freq / 1000); - if (check_firmware(fe, type, std) < 0) + if (check_firmware(fe, type, std, int_freq) < 0) goto ret; /* On some cases xc2028 can disable video output, if @@ -896,7 +924,7 @@ static int xc2028_set_analog_freq(struct dvb_frontend *fe, if (priv->ctrl.input1) type |= INPUT1; return generic_set_freq(fe, (625l * p->frequency) / 10, - T_ANALOG_TV, type, 0); + T_ANALOG_TV, type, 0, 0); } /* if std is not defined, choose one */ @@ -911,22 +939,9 @@ static int xc2028_set_analog_freq(struct dvb_frontend *fe, p->std |= parse_audio_std_option(); return generic_set_freq(fe, 62500l * p->frequency, - T_ANALOG_TV, type, p->std); + T_ANALOG_TV, type, p->std, 0); } -static unsigned int demod_type [] = { - [XC3028_FE_DEFAULT] = 0, - [XC3028_FE_LG60] = LG60, - [XC3028_FE_ATI638] = ATI638, - [XC3028_FE_OREN538] = OREN538, - [XC3028_FE_OREN36] = OREN36, - [XC3028_FE_TOYOTA388] = TOYOTA388, - [XC3028_FE_TOYOTA794] = TOYOTA794, - [XC3028_FE_DIBCOM52] = DIBCOM52, - [XC3028_FE_ZARLINK456] = ZARLINK456, - [XC3028_FE_CHINA] = CHINA, -}; - static int xc2028_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) { @@ -978,13 +993,12 @@ static int xc2028_set_params(struct dvb_frontend *fe, tuner_err("error: bandwidth not supported.\n"); }; - if (priv->ctrl.demod < 0 || priv->ctrl.demod > ARRAY_SIZE(demod_type)) - tuner_err("error: demod type invalid. Assuming default.\n"); - else - type |= demod_type[priv->ctrl.demod]; + /* All S-code tables need a 200kHz shift */ + if (priv->ctrl.demod) + priv->ctrl.demod += 200; return generic_set_freq(fe, p->frequency, - T_DIGITAL_TV, type, 0); + T_DIGITAL_TV, type, 0, priv->ctrl.demod); } static int xc2028_sleep(struct dvb_frontend *fe) |