diff options
Diffstat (limited to 'linux')
-rw-r--r-- | linux/drivers/media/video/tuner-xc2028.c | 46 |
1 files changed, 38 insertions, 8 deletions
diff --git a/linux/drivers/media/video/tuner-xc2028.c b/linux/drivers/media/video/tuner-xc2028.c index 1017b1d10..131687ea4 100644 --- a/linux/drivers/media/video/tuner-xc2028.c +++ b/linux/drivers/media/video/tuner-xc2028.c @@ -392,9 +392,13 @@ static int seek_firmware(struct dvb_frontend *fe, unsigned int type, v4l2_std_id *id) { struct xc2028_data *priv = fe->tuner_priv; - int i; + int i, best_i = -1, best_nr_matches = 0; - tuner_dbg("%s called\n", __FUNCTION__); + tuner_dbg("%s called, want type=", __FUNCTION__); + if (debug) { + dump_firm_type(type); + printk("(%x), id %016llx.\n", type, (unsigned long long)*id); + } if (!priv->firm) { tuner_err("Error! firmware not loaded\n"); @@ -412,20 +416,45 @@ static int seek_firmware(struct dvb_frontend *fe, unsigned int type, /* Seek for generic video standard match */ for (i = 0; i < priv->firm_size; i++) { - if ((type == priv->firm[i].type) && (*id & priv->firm[i].id)) - goto found; + v4l2_std_id match_mask; + int nr_matches; + + if (type != priv->firm[i].type) + continue; + + match_mask = *id & priv->firm[i].id; + if (!match_mask) + continue; + + if ((*id & match_mask) == *id) + goto found; /* Supports all the requested standards */ + + nr_matches = hweight64(match_mask); + if (nr_matches > best_nr_matches) { + best_nr_matches = nr_matches; + best_i = i; + } + } + + if (best_nr_matches > 0) { + tuner_dbg("Selecting best matching firmware (%d bits) for " + "type=", best_nr_matches); + dump_firm_type(type); + printk("(%x), id %016llx:\n", type, (unsigned long long)*id); + i = best_i; + goto found; } /*FIXME: Would make sense to seek for type "hint" match ? */ - i = -EINVAL; + i = -ENOENT; goto ret; found: *id = priv->firm[i].id; ret: - tuner_dbg("%s firmware for type=", (i < 0)? "Can't find": "Found"); + tuner_dbg("%s firmware for type=", (i < 0) ? "Can't find" : "Found"); if (debug) { dump_firm_type(type); printk("(%x), id %016llx.\n", type, (unsigned long long)*id); @@ -447,8 +476,9 @@ static int load_firmware(struct dvb_frontend *fe, unsigned int type, return pos; tuner_info("Loading firmware for type="); - dump_firm_type(type); - printk("(%x), id %016llx.\n", type, (unsigned long long)*id); + dump_firm_type(priv->firm[pos].type); + printk("(%x), id %016llx.\n", priv->firm[pos].type, + (unsigned long long)*id); p = priv->firm[pos].ptr; endp = p + priv->firm[pos].size; |