--- zzzz-none-000/linux-3.10.107/drivers/media/tuners/tuner-xc2028.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/media/tuners/tuner-xc2028.c 2021-02-04 17:41:59.000000000 +0000 @@ -134,15 +134,6 @@ _rc; \ }) -#define i2c_rcv(priv, buf, size) ({ \ - int _rc; \ - _rc = tuner_i2c_xfer_recv(&priv->i2c_props, buf, size); \ - if (size != _rc) \ - tuner_err("i2c input error: rc = %d (should be %d)\n", \ - _rc, (int)size); \ - _rc; \ -}) - #define i2c_send_recv(priv, obuf, osize, ibuf, isize) ({ \ int _rc; \ _rc = tuner_i2c_xfer_send_recv(&priv->i2c_props, obuf, osize, \ @@ -187,67 +178,67 @@ #define dump_firm_type(t) dump_firm_type_and_int_freq(t, 0) static void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq) { - if (type & BASE) + if (type & BASE) printk("BASE "); - if (type & INIT1) + if (type & INIT1) printk("INIT1 "); - if (type & F8MHZ) + if (type & F8MHZ) printk("F8MHZ "); - if (type & MTS) + if (type & MTS) printk("MTS "); - if (type & D2620) + if (type & D2620) printk("D2620 "); - if (type & D2633) + if (type & D2633) printk("D2633 "); - if (type & DTV6) + if (type & DTV6) printk("DTV6 "); - if (type & QAM) + if (type & QAM) printk("QAM "); - if (type & DTV7) + if (type & DTV7) printk("DTV7 "); - if (type & DTV78) + if (type & DTV78) printk("DTV78 "); - if (type & DTV8) + if (type & DTV8) printk("DTV8 "); - if (type & FM) + if (type & FM) printk("FM "); - if (type & INPUT1) + if (type & INPUT1) printk("INPUT1 "); - if (type & LCD) + if (type & LCD) printk("LCD "); - if (type & NOGD) + if (type & NOGD) printk("NOGD "); - if (type & MONO) + if (type & MONO) printk("MONO "); - if (type & ATSC) + if (type & ATSC) printk("ATSC "); - if (type & IF) + if (type & IF) printk("IF "); - if (type & LG60) + if (type & LG60) printk("LG60 "); - if (type & ATI638) + if (type & ATI638) printk("ATI638 "); - if (type & OREN538) + if (type & OREN538) printk("OREN538 "); - if (type & OREN36) + if (type & OREN36) printk("OREN36 "); - if (type & TOYOTA388) + if (type & TOYOTA388) printk("TOYOTA388 "); - if (type & TOYOTA794) + if (type & TOYOTA794) printk("TOYOTA794 "); - if (type & DIBCOM52) + if (type & DIBCOM52) printk("DIBCOM52 "); - if (type & ZARLINK456) + if (type & ZARLINK456) printk("ZARLINK456 "); - if (type & CHINA) + if (type & CHINA) printk("CHINA "); - if (type & F6MHZ) + if (type & F6MHZ) printk("F6MHZ "); - if (type & INPUT2) + if (type & INPUT2) printk("INPUT2 "); - if (type & SCODE) + if (type & SCODE) printk("SCODE "); - if (type & HAS_IF) + if (type & HAS_IF) printk("HAS_IF_%d ", int_freq); } @@ -276,6 +267,7 @@ case XC2028_WAITING_FIRMWARE: return -EAGAIN; case XC2028_ACTIVE: + return 1; case XC2028_SLEEP: return 0; case XC2028_NODEV: @@ -289,14 +281,6 @@ int i; tuner_dbg("%s called\n", __func__); - /* free allocated f/w string */ - if (priv->fname != firmware_name) - kfree(priv->fname); - priv->fname = NULL; - - priv->state = XC2028_NO_FIRMWARE; - memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); - if (!priv->firm) return; @@ -307,6 +291,9 @@ priv->firm = NULL; priv->firm_size = 0; + priv->state = XC2028_NO_FIRMWARE; + + memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); } static int load_all_firmwares(struct dvb_frontend *fe, @@ -583,7 +570,7 @@ return -EINVAL; } - size = le16_to_cpu(*(__u16 *) p); + size = le16_to_cpu(*(__le16 *) p); p += sizeof(size); if (size == 0xffff) @@ -694,7 +681,7 @@ /* 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) + le16_to_cpu(*(__le16 *)(p + 14 * scode)) != 12) return -EINVAL; p += 14 * scode + 2; } @@ -723,6 +710,8 @@ return 0; } +static int xc2028_sleep(struct dvb_frontend *fe); + static int check_firmware(struct dvb_frontend *fe, unsigned int type, v4l2_std_id std, __u16 int_freq) { @@ -895,9 +884,9 @@ return 0; fail: - free_firmware(priv); - priv->state = XC2028_SLEEP; + priv->state = XC2028_NO_FIRMWARE; + memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); if (retry_count < 8) { msleep(50); retry_count++; @@ -905,6 +894,9 @@ goto retry; } + /* Firmware didn't load. Put the device to sleep */ + xc2028_sleep(fe); + if (rc == -ENOENT) rc = -EINVAL; return rc; @@ -922,6 +914,12 @@ if (rc < 0) return rc; + /* If the device is sleeping, no channel is tuned */ + if (!rc) { + *strength = 0; + return 0; + } + mutex_lock(&priv->lock); /* Sync Lock Indicator */ @@ -969,6 +967,12 @@ if (rc < 0) return rc; + /* If the device is sleeping, no channel is tuned */ + if (!rc) { + *afc = 0; + return 0; + } + mutex_lock(&priv->lock); /* Sync Lock Indicator */ @@ -1090,7 +1094,7 @@ * Still need tests for XC3028L (firmware 3.2 or upper) * So, for now, let's just comment the per-firmware * version of this change. Reports with xc3028l working - * with and without the lines bellow are welcome + * with and without the lines below are welcome */ if (priv->firm_version < 0x0302) { @@ -1103,6 +1107,10 @@ offset += 200000; } #endif + break; + default: + tuner_err("Unsupported tuner type %d.\n", new_type); + break; } div = (freq - offset + DIV / 2) / DIV; @@ -1286,6 +1294,10 @@ if (rc < 0) return rc; + /* Device is already in sleep mode */ + if (!rc) + return 0; + /* Avoid firmware reload on slow devices or if PM disabled */ if (no_poweroff || priv->ctrl.disable_power_mgmt) return 0; @@ -1303,7 +1315,8 @@ else rc = send_seq(priv, {0x80, XREG_POWER_DOWN, 0x00, 0x00}); - priv->state = XC2028_SLEEP; + if (rc >= 0) + priv->state = XC2028_SLEEP; mutex_unlock(&priv->lock); @@ -1319,8 +1332,11 @@ mutex_lock(&xc2028_list_mutex); /* only perform final cleanup if this is the last instance */ - if (hybrid_tuner_report_instance_count(priv) == 1) + if (hybrid_tuner_report_instance_count(priv) == 1) { free_firmware(priv); + kfree(priv->ctrl.fname); + priv->ctrl.fname = NULL; + } if (priv) hybrid_tuner_release_state(priv); @@ -1368,7 +1384,7 @@ if (rc < 0) return; - priv->state = XC2028_SLEEP; + priv->state = XC2028_ACTIVE; } static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg) @@ -1383,8 +1399,16 @@ /* * Copy the config data. + * For the firmware name, keep a local copy of the string, + * in order to avoid troubles during device release. */ + kfree(priv->ctrl.fname); memcpy(&priv->ctrl, p, sizeof(priv->ctrl)); + if (p->fname) { + priv->ctrl.fname = kstrdup(p->fname, GFP_KERNEL); + if (priv->ctrl.fname == NULL) + rc = -ENOMEM; + } /* * If firmware name changed, frees firmware. As free_firmware will @@ -1399,15 +1423,10 @@ if (priv->state == XC2028_NO_FIRMWARE) { if (!firmware_name[0]) - priv->fname = kstrdup(p->fname, GFP_KERNEL); + priv->fname = priv->ctrl.fname; else priv->fname = firmware_name; - if (!priv->fname) { - rc = -ENOMEM; - goto unlock; - } - rc = request_firmware_nowait(THIS_MODULE, 1, priv->fname, priv->i2c_props.adap->dev.parent, @@ -1420,7 +1439,6 @@ } else priv->state = XC2028_WAITING_FIRMWARE; } -unlock: mutex_unlock(&priv->lock); return rc; @@ -1471,7 +1489,6 @@ case 0: /* memory allocation failure */ goto fail; - break; case 1: /* new tuner instance */ priv->ctrl.max_len = 13;