diff options
Diffstat (limited to 'drivers/media/video/tuner-xc2028.c')
-rw-r--r-- | drivers/media/video/tuner-xc2028.c | 165 |
1 files changed, 88 insertions, 77 deletions
diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index 50cf876f020..9e9003cffc7 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -1,6 +1,6 @@ /* tuner-xc2028 * - * Copyright (c) 2007 Mauro Carvalho Chehab (mchehab@infradead.org) + * Copyright (c) 2007-2008 Mauro Carvalho Chehab (mchehab@infradead.org) * * Copyright (c) 2007 Michel Ludwig (michel.ludwig@gmail.com) * - frontend interface @@ -23,8 +23,6 @@ #include "dvb_frontend.h" -#define PREFIX "xc2028" - static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "enable verbose debug messages"); @@ -43,6 +41,11 @@ MODULE_PARM_DESC(audio_std, "NICAM/A\n" "NICAM/B\n"); +static char firmware_name[FIRMWARE_NAME_MAX]; +module_param_string(firmware_name, firmware_name, sizeof(firmware_name), 0); +MODULE_PARM_DESC(firmware_name, "Firmware file name. Allows overriding the " + "default firmware name\n"); + static LIST_HEAD(xc2028_list); static DEFINE_MUTEX(xc2028_list_mutex); @@ -127,12 +130,12 @@ struct xc2028_data { _rc; \ }) -static unsigned int xc2028_get_reg(struct xc2028_data *priv, u16 reg, u16 *val) +static int xc2028_get_reg(struct xc2028_data *priv, u16 reg, u16 *val) { unsigned char buf[2]; unsigned char ibuf[2]; - tuner_dbg("%s %04x called\n", __FUNCTION__, reg); + tuner_dbg("%s %04x called\n", __func__, reg); buf[0] = reg >> 8; buf[1] = (unsigned char) reg; @@ -145,7 +148,7 @@ static unsigned int xc2028_get_reg(struct xc2028_data *priv, u16 reg, u16 *val) } #define dump_firm_type(t) dump_firm_type_and_int_freq(t, 0) -void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq) +static void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq) { if (type & BASE) printk("BASE "); @@ -232,6 +235,7 @@ static v4l2_std_id parse_audio_std_option(void) static void free_firmware(struct xc2028_data *priv) { int i; + tuner_dbg("%s called\n", __func__); if (!priv->firm) return; @@ -255,19 +259,24 @@ static int load_all_firmwares(struct dvb_frontend *fe) int rc = 0; int n, n_array; char name[33]; + char *fname; + + tuner_dbg("%s called\n", __func__); - tuner_dbg("%s called\n", __FUNCTION__); + if (!firmware_name[0]) + fname = priv->ctrl.fname; + else + fname = firmware_name; - tuner_dbg("Reading firmware %s\n", priv->ctrl.fname); - rc = request_firmware(&fw, priv->ctrl.fname, - &priv->i2c_props.adap->dev); + tuner_dbg("Reading firmware %s\n", fname); + rc = request_firmware(&fw, fname, &priv->i2c_props.adap->dev); if (rc < 0) { if (rc == -ENOENT) tuner_err("Error: firmware %s not found.\n", - priv->ctrl.fname); + fname); else tuner_err("Error %d while requesting firmware %s \n", - rc, priv->ctrl.fname); + rc, fname); return rc; } @@ -276,7 +285,7 @@ static int load_all_firmwares(struct dvb_frontend *fe) if (fw->size < sizeof(name) - 1 + 2 + 2) { tuner_err("Error: firmware file %s has invalid size!\n", - priv->ctrl.fname); + fname); goto corrupt; } @@ -291,7 +300,7 @@ static int load_all_firmwares(struct dvb_frontend *fe) p += 2; tuner_info("Loading %d firmware images from %s, type: %s, ver %d.%d\n", - n_array, priv->ctrl.fname, name, + n_array, fname, name, priv->firm_version >> 8, priv->firm_version & 0xff); priv->firm = kzalloc(sizeof(*priv->firm) * n_array, GFP_KERNEL); @@ -395,9 +404,9 @@ static int seek_firmware(struct dvb_frontend *fe, unsigned int type, { struct xc2028_data *priv = fe->tuner_priv; int i, best_i = -1, best_nr_matches = 0; - unsigned int ign_firm_type_mask = 0; + unsigned int type_mask = 0; - tuner_dbg("%s called, want type=", __FUNCTION__); + tuner_dbg("%s called, want type=", __func__); if (debug) { dump_firm_type(type); printk("(%x), id %016llx.\n", type, (unsigned long long)*id); @@ -412,18 +421,23 @@ static int seek_firmware(struct dvb_frontend *fe, unsigned int type, *id = V4L2_STD_PAL; if (type & BASE) - type &= BASE_TYPES; + type_mask = BASE_TYPES; else if (type & SCODE) { type &= SCODE_TYPES; - ign_firm_type_mask = HAS_IF; + type_mask = SCODE_TYPES & ~HAS_IF; } else if (type & DTV_TYPES) - type &= DTV_TYPES; + type_mask = DTV_TYPES; else if (type & STD_SPECIFIC_TYPES) - type &= STD_SPECIFIC_TYPES; + type_mask = STD_SPECIFIC_TYPES; + + type &= type_mask; + + if (!(type & SCODE)) + type_mask = ~0; /* Seek for exact match */ for (i = 0; i < priv->firm_size; i++) { - if ((type == (priv->firm[i].type & ~ign_firm_type_mask)) && + if ((type == (priv->firm[i].type & type_mask)) && (*id == priv->firm[i].id)) goto found; } @@ -433,7 +447,7 @@ static int seek_firmware(struct dvb_frontend *fe, unsigned int type, v4l2_std_id match_mask; int nr_matches; - if (type != (priv->firm[i].type & ~ign_firm_type_mask)) + if (type != (priv->firm[i].type & type_mask)) continue; match_mask = *id & priv->firm[i].id; @@ -483,7 +497,7 @@ static int load_firmware(struct dvb_frontend *fe, unsigned int type, int pos, rc; unsigned char *p, *endp, buf[priv->ctrl.max_len]; - tuner_dbg("%s called\n", __FUNCTION__); + tuner_dbg("%s called\n", __func__); pos = seek_firmware(fe, type, id); if (pos < 0) @@ -586,7 +600,7 @@ static int load_scode(struct dvb_frontend *fe, unsigned int type, int pos, rc; unsigned char *p; - tuner_dbg("%s called\n", __FUNCTION__); + tuner_dbg("%s called\n", __func__); if (!int_freq) { pos = seek_firmware(fe, type, id); @@ -650,7 +664,7 @@ static int check_firmware(struct dvb_frontend *fe, unsigned int type, u16 version, hwmodel; v4l2_std_id std0; - tuner_dbg("%s called\n", __FUNCTION__); + tuner_dbg("%s called\n", __func__); if (!priv->firm) { if (!priv->ctrl.fname) { @@ -770,10 +784,10 @@ check_device: goto fail; } - tuner_info("Device is Xceive %d version %d.%d, " - "firmware version %d.%d\n", - hwmodel, (version & 0xf000) >> 12, (version & 0xf00) >> 8, - (version & 0xf0) >> 4, version & 0xf); + tuner_dbg("Device is Xceive %d version %d.%d, " + "firmware version %d.%d\n", + hwmodel, (version & 0xf000) >> 12, (version & 0xf00) >> 8, + (version & 0xf0) >> 4, version & 0xf); /* Check firmware version against what we downloaded. */ if (priv->firm_version != ((version & 0xf0) << 4 | (version & 0x0f))) { @@ -824,27 +838,34 @@ static int xc2028_signal(struct dvb_frontend *fe, u16 *strength) u16 frq_lock, signal = 0; int rc; - tuner_dbg("%s called\n", __FUNCTION__); + tuner_dbg("%s called\n", __func__); mutex_lock(&priv->lock); /* Sync Lock Indicator */ rc = xc2028_get_reg(priv, 0x0002, &frq_lock); - if (rc < 0 || frq_lock == 0) + if (rc < 0) goto ret; - /* Frequency is locked. Return signal quality */ + /* Frequency is locked */ + if (frq_lock == 1) + signal = 32768; /* Get SNR of the video signal */ rc = xc2028_get_reg(priv, 0x0040, &signal); if (rc < 0) - signal = -frq_lock; + goto ret; + + /* Use both frq_lock and signal to generate the result */ + signal = signal || ((signal & 0x07) << 12); ret: mutex_unlock(&priv->lock); *strength = signal; + tuner_dbg("signal strength is %d\n", signal); + return rc; } @@ -861,7 +882,7 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */, unsigned char buf[4]; u32 div, offset = 0; - tuner_dbg("%s called\n", __FUNCTION__); + tuner_dbg("%s called\n", __func__); mutex_lock(&priv->lock); @@ -906,9 +927,11 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */, if (rc < 0) goto ret; - rc = priv->tuner_callback(priv->video_dev, XC2028_RESET_CLK, 1); - if (rc < 0) - goto ret; + /* Return code shouldn't be checked. + The reset CLK is needed only with tm6000. + Driver should work fine even if this fails. + */ + priv->tuner_callback(priv->video_dev, XC2028_RESET_CLK, 1); msleep(10); @@ -942,7 +965,7 @@ static int xc2028_set_analog_freq(struct dvb_frontend *fe, struct xc2028_data *priv = fe->tuner_priv; unsigned int type=0; - tuner_dbg("%s called\n", __FUNCTION__); + tuner_dbg("%s called\n", __func__); if (p->mode == V4L2_TUNER_RADIO) { type |= FM; @@ -975,7 +998,7 @@ static int xc2028_set_params(struct dvb_frontend *fe, fe_bandwidth_t bw = BANDWIDTH_8_MHZ; u16 demod = 0; - tuner_dbg("%s called\n", __FUNCTION__); + tuner_dbg("%s called\n", __func__); if (priv->ctrl.d2633) type |= D2633; @@ -1040,33 +1063,12 @@ static int xc2028_set_params(struct dvb_frontend *fe, T_DIGITAL_TV, type, 0, demod); } -static int xc2028_sleep(struct dvb_frontend *fe) -{ - struct xc2028_data *priv = fe->tuner_priv; - int rc = 0; - - tuner_dbg("%s called\n", __FUNCTION__); - - mutex_lock(&priv->lock); - - if (priv->firm_version < 0x0202) - rc = send_seq(priv, {0x00, 0x08, 0x00, 0x00}); - else - rc = send_seq(priv, {0x80, 0x08, 0x00, 0x00}); - - priv->cur_fw.type = 0; /* need firmware reload */ - - mutex_unlock(&priv->lock); - - return rc; -} - static int xc2028_dvb_release(struct dvb_frontend *fe) { struct xc2028_data *priv = fe->tuner_priv; - tuner_dbg("%s called\n", __FUNCTION__); + tuner_dbg("%s called\n", __func__); mutex_lock(&xc2028_list_mutex); @@ -1091,7 +1093,7 @@ static int xc2028_get_frequency(struct dvb_frontend *fe, u32 *frequency) { struct xc2028_data *priv = fe->tuner_priv; - tuner_dbg("%s called\n", __FUNCTION__); + tuner_dbg("%s called\n", __func__); *frequency = priv->frequency; @@ -1104,25 +1106,25 @@ static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg) struct xc2028_ctrl *p = priv_cfg; int rc = 0; - tuner_dbg("%s called\n", __FUNCTION__); + tuner_dbg("%s called\n", __func__); mutex_lock(&priv->lock); - kfree(priv->ctrl.fname); - free_firmware(priv); - memcpy(&priv->ctrl, p, sizeof(priv->ctrl)); - priv->ctrl.fname = NULL; + if (priv->ctrl.max_len < 9) + priv->ctrl.max_len = 13; if (p->fname) { + if (priv->ctrl.fname && strcmp(p->fname, priv->ctrl.fname)) { + kfree(priv->ctrl.fname); + free_firmware(priv); + } + priv->ctrl.fname = kstrdup(p->fname, GFP_KERNEL); if (priv->ctrl.fname == NULL) rc = -ENOMEM; } - if (priv->ctrl.max_len < 9) - priv->ctrl.max_len = 13; - mutex_unlock(&priv->lock); return rc; @@ -1142,8 +1144,6 @@ static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = { .get_frequency = xc2028_get_frequency, .get_rf_strength = xc2028_signal, .set_params = xc2028_set_params, - .sleep = xc2028_sleep, - }; struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe, @@ -1153,23 +1153,29 @@ struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe, void *video_dev; if (debug) - printk(KERN_DEBUG PREFIX ": Xcv2028/3028 init called!\n"); + printk(KERN_DEBUG "xc2028: Xcv2028/3028 init called!\n"); - if (NULL == cfg || NULL == cfg->video_dev) + if (NULL == cfg) return NULL; if (!fe) { - printk(KERN_ERR PREFIX ": No frontend!\n"); + printk(KERN_ERR "xc2028: No frontend!\n"); return NULL; } - video_dev = cfg->video_dev; + video_dev = cfg->i2c_adap->algo_data; + + if (debug) + printk(KERN_DEBUG "xc2028: video_dev =%p\n", video_dev); mutex_lock(&xc2028_list_mutex); list_for_each_entry(priv, &xc2028_list, xc2028_list) { - if (priv->video_dev == cfg->video_dev) { + if (&priv->i2c_props.adap->dev == &cfg->i2c_adap->dev) { video_dev = NULL; + if (debug) + printk(KERN_DEBUG "xc2028: reusing device\n"); + break; } } @@ -1183,6 +1189,8 @@ struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe, priv->i2c_props.addr = cfg->i2c_addr; priv->i2c_props.adap = cfg->i2c_adap; + priv->i2c_props.name = "xc2028"; + priv->video_dev = video_dev; priv->tuner_callback = cfg->callback; priv->ctrl.max_len = 13; @@ -1195,6 +1203,9 @@ struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe, fe->tuner_priv = priv; priv->count++; + if (debug) + printk(KERN_DEBUG "xc2028: usage count is %i\n", priv->count); + memcpy(&fe->ops.tuner_ops, &xc2028_dvb_tuner_ops, sizeof(xc2028_dvb_tuner_ops)); |