--- zzzz-none-000/linux-3.10.107/drivers/media/usb/dvb-usb-v2/lmedm04.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/media/usb/dvb-usb-v2/lmedm04.c 2021-02-04 17:41:59.000000000 +0000 @@ -125,14 +125,13 @@ #define TUNER_RS2000 0x4 struct lme2510_state { + unsigned long int_urb_due; + enum fe_status lock_status; u8 id; u8 tuner_config; - u8 signal_lock; u8 signal_level; u8 signal_sn; u8 time_key; - u8 last_key; - u8 key_timeout; u8 i2c_talk_onoff; u8 i2c_gate; u8 i2c_tuner_gate_w; @@ -144,7 +143,13 @@ void *buffer; struct urb *lme_urb; void *usb_buffer; - int (*fe_set_voltage)(struct dvb_frontend *, fe_sec_voltage_t); + /* Frontend original calls */ + int (*fe_read_status)(struct dvb_frontend *, enum fe_status *); + int (*fe_read_signal_strength)(struct dvb_frontend *, u16 *); + int (*fe_read_snr)(struct dvb_frontend *, u16 *); + int (*fe_read_ber)(struct dvb_frontend *, u32 *); + int (*fe_read_ucblocks)(struct dvb_frontend *, u32 *); + int (*fe_set_voltage)(struct dvb_frontend *, enum fe_sec_voltage); u8 dvb_usb_lme2510_firmware; }; @@ -252,6 +257,62 @@ return ret; } +/* Convert range from 0x00-0xff to 0x0000-0xffff */ +#define reg_to_16bits(x) ((x) | ((x) << 8)) + +static void lme2510_update_stats(struct dvb_usb_adapter *adap) +{ + struct lme2510_state *st = adap_to_priv(adap); + struct dvb_frontend *fe = adap->fe[0]; + struct dtv_frontend_properties *c; + u32 s_tmp = 0, c_tmp = 0; + + if (!fe) + return; + + c = &fe->dtv_property_cache; + + c->block_count.len = 1; + c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->block_error.len = 1; + c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_count.len = 1; + c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_error.len = 1; + c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + + if (st->i2c_talk_onoff) { + c->strength.len = 1; + c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->cnr.len = 1; + c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + return; + } + + switch (st->tuner_config) { + case TUNER_LG: + s_tmp = reg_to_16bits(0xff - st->signal_level); + c_tmp = reg_to_16bits(0xff - st->signal_sn); + break; + case TUNER_S7395: + case TUNER_S0194: + s_tmp = 0xffff - (((st->signal_level * 2) << 8) * 5 / 4); + c_tmp = reg_to_16bits((0xff - st->signal_sn - 0xa1) * 3); + break; + case TUNER_RS2000: + s_tmp = reg_to_16bits(st->signal_level); + c_tmp = reg_to_16bits(st->signal_sn); + } + + c->strength.len = 1; + c->strength.stat[0].scale = FE_SCALE_RELATIVE; + c->strength.stat[0].uvalue = (u64)s_tmp; + + c->cnr.len = 1; + c->cnr.stat[0].scale = FE_SCALE_RELATIVE; + c->cnr.stat[0].uvalue = (u64)c_tmp; +} + static void lme2510_int_response(struct urb *lme_urb) { struct dvb_usb_adapter *adap = lme_urb->context; @@ -259,6 +320,7 @@ static u8 *ibuf, *rbuf; int i = 0, offset; u32 key; + u8 signal_lock = 0; switch (lme_urb->status) { case 0: @@ -286,22 +348,21 @@ switch (ibuf[0]) { case 0xaa: debug_data_snipet(1, "INT Remote data snipet", ibuf); - if ((ibuf[4] + ibuf[5]) == 0xff) { - key = ibuf[5]; - key += (ibuf[3] > 0) - ? (ibuf[3] ^ 0xff) << 8 : 0; - key += (ibuf[2] ^ 0xff) << 16; - deb_info(1, "INT Key =%08x", key); - if (adap_to_d(adap)->rc_dev != NULL) - rc_keydown(adap_to_d(adap)->rc_dev, - key, 0); - } + if (!adap_to_d(adap)->rc_dev) + break; + + key = RC_SCANCODE_NEC32(ibuf[2] << 24 | + ibuf[3] << 16 | + ibuf[4] << 8 | + ibuf[5]); + + deb_info(1, "INT Key = 0x%08x", key); + rc_keydown(adap_to_d(adap)->rc_dev, RC_TYPE_NEC, key, 0); break; case 0xbb: switch (st->tuner_config) { case TUNER_LG: - if (ibuf[2] > 0) - st->signal_lock = ibuf[2]; + signal_lock = ibuf[2] & BIT(5); st->signal_level = ibuf[4]; st->signal_sn = ibuf[3]; st->time_key = ibuf[7]; @@ -310,29 +371,31 @@ case TUNER_S0194: /* Tweak for earlier firmware*/ if (ibuf[1] == 0x03) { - if (ibuf[2] > 1) - st->signal_lock = ibuf[2]; + signal_lock = ibuf[2] & BIT(4); st->signal_level = ibuf[3]; st->signal_sn = ibuf[4]; } else { st->signal_level = ibuf[4]; st->signal_sn = ibuf[5]; - st->signal_lock = - (st->signal_lock & 0xf7) + - ((ibuf[2] & 0x01) << 0x03); } break; case TUNER_RS2000: - if (ibuf[1] == 0x3 && ibuf[6] == 0xff) - st->signal_lock = 0xff; - else - st->signal_lock = 0x00; + signal_lock = ibuf[2] & 0xee; st->signal_level = ibuf[5]; st->signal_sn = ibuf[4]; st->time_key = ibuf[7]; default: break; } + + /* Interrupt will also throw just BIT 0 as lock */ + signal_lock |= ibuf[2] & BIT(0); + + if (!signal_lock) + st->lock_status &= ~FE_HAS_LOCK; + + lme2510_update_stats(adap); + debug_data_snipet(5, "INT Remote data snipet in", ibuf); break; case 0xcc: @@ -343,7 +406,13 @@ break; } } + usb_submit_urb(lme_urb, GFP_ATOMIC); + + /* Interrupt urb is due every 48 msecs while streaming the buffer + * stores up to 4 periods if missed. Allow 200 msec for next interrupt. + */ + st->int_urb_due = jiffies + msecs_to_jiffies(200); } static int lme2510_int_read(struct dvb_usb_adapter *adap) @@ -453,171 +522,13 @@ static int lme2510_msg(struct dvb_usb_device *d, u8 *wbuf, int wlen, u8 *rbuf, int rlen) { - int ret = 0; struct lme2510_state *st = d->priv; - if (st->i2c_talk_onoff == 1) { - - ret = lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); - - switch (st->tuner_config) { - case TUNER_LG: - if (wbuf[2] == 0x1c) { - if (wbuf[3] == 0x0e) { - st->signal_lock = rbuf[1]; - if ((st->stream_on & 1) && - (st->signal_lock & 0x10)) { - lme2510_stream_restart(d); - st->i2c_talk_onoff = 0; - } - msleep(80); - } - } - break; - case TUNER_S7395: - if (wbuf[2] == 0xd0) { - if (wbuf[3] == 0x24) { - st->signal_lock = rbuf[1]; - if ((st->stream_on & 1) && - (st->signal_lock & 0x8)) { - lme2510_stream_restart(d); - st->i2c_talk_onoff = 0; - } - } - } - break; - case TUNER_S0194: - if (wbuf[2] == 0xd0) { - if (wbuf[3] == 0x1b) { - st->signal_lock = rbuf[1]; - if ((st->stream_on & 1) && - (st->signal_lock & 0x8)) { - lme2510_stream_restart(d); - st->i2c_talk_onoff = 0; - } - } - } - break; - case TUNER_RS2000: - default: - break; - } - } else { - /* TODO rewrite this section */ - switch (st->tuner_config) { - case TUNER_LG: - switch (wbuf[3]) { - case 0x0e: - rbuf[0] = 0x55; - rbuf[1] = st->signal_lock; - break; - case 0x43: - rbuf[0] = 0x55; - rbuf[1] = st->signal_level; - break; - case 0x1c: - rbuf[0] = 0x55; - rbuf[1] = st->signal_sn; - break; - case 0x15: - case 0x16: - case 0x17: - case 0x18: - rbuf[0] = 0x55; - rbuf[1] = 0x00; - break; - default: - lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); - st->i2c_talk_onoff = 1; - break; - } - break; - case TUNER_S7395: - switch (wbuf[3]) { - case 0x10: - rbuf[0] = 0x55; - rbuf[1] = (st->signal_level & 0x80) - ? 0 : (st->signal_level * 2); - break; - case 0x2d: - rbuf[0] = 0x55; - rbuf[1] = st->signal_sn; - break; - case 0x24: - rbuf[0] = 0x55; - rbuf[1] = st->signal_lock; - break; - case 0x2e: - case 0x26: - case 0x27: - rbuf[0] = 0x55; - rbuf[1] = 0x00; - break; - default: - lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); - st->i2c_talk_onoff = 1; - break; - } - break; - case TUNER_S0194: - switch (wbuf[3]) { - case 0x18: - rbuf[0] = 0x55; - rbuf[1] = (st->signal_level & 0x80) - ? 0 : (st->signal_level * 2); - break; - case 0x24: - rbuf[0] = 0x55; - rbuf[1] = st->signal_sn; - break; - case 0x1b: - rbuf[0] = 0x55; - rbuf[1] = st->signal_lock; - break; - case 0x19: - case 0x25: - case 0x1e: - case 0x1d: - rbuf[0] = 0x55; - rbuf[1] = 0x00; - break; - default: - lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); - st->i2c_talk_onoff = 1; - break; - } - break; - case TUNER_RS2000: - switch (wbuf[3]) { - case 0x8c: - rbuf[0] = 0x55; - rbuf[1] = 0xff; - if (st->last_key == st->time_key) { - st->key_timeout++; - if (st->key_timeout > 5) - rbuf[1] = 0; - } else - st->key_timeout = 0; - st->last_key = st->time_key; - break; - default: - lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); - st->i2c_talk_onoff = 1; - break; - } - default: - break; - } - - deb_info(4, "I2C From Interrupt Message out(%02x) in(%02x)", - wbuf[3], rbuf[1]); - - } + st->i2c_talk_onoff = 1; - return ret; + return lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); } - static int lme2510_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) { @@ -822,20 +733,22 @@ case 0x1122: switch (st->dvb_usb_lme2510_firmware) { default: - st->dvb_usb_lme2510_firmware = TUNER_S0194; case TUNER_S0194: fw_lme = fw_s0194; ret = request_firmware(&fw, fw_lme, &udev->dev); if (ret == 0) { + st->dvb_usb_lme2510_firmware = TUNER_S0194; cold = 0; break; } - st->dvb_usb_lme2510_firmware = TUNER_LG; + /* fall through */ case TUNER_LG: fw_lme = fw_lg; ret = request_firmware(&fw, fw_lme, &udev->dev); - if (ret == 0) + if (ret == 0) { + st->dvb_usb_lme2510_firmware = TUNER_LG; break; + } st->dvb_usb_lme2510_firmware = TUNER_DEFAULT; break; } @@ -843,26 +756,30 @@ case 0x1120: switch (st->dvb_usb_lme2510_firmware) { default: - st->dvb_usb_lme2510_firmware = TUNER_S7395; case TUNER_S7395: fw_lme = fw_c_s7395; ret = request_firmware(&fw, fw_lme, &udev->dev); if (ret == 0) { + st->dvb_usb_lme2510_firmware = TUNER_S7395; cold = 0; break; } - st->dvb_usb_lme2510_firmware = TUNER_LG; + /* fall through */ case TUNER_LG: fw_lme = fw_c_lg; ret = request_firmware(&fw, fw_lme, &udev->dev); - if (ret == 0) + if (ret == 0) { + st->dvb_usb_lme2510_firmware = TUNER_LG; break; - st->dvb_usb_lme2510_firmware = TUNER_S0194; + } + /* fall through */ case TUNER_S0194: fw_lme = fw_c_s0194; ret = request_firmware(&fw, fw_lme, &udev->dev); - if (ret == 0) + if (ret == 0) { + st->dvb_usb_lme2510_firmware = TUNER_S0194; break; + } st->dvb_usb_lme2510_firmware = TUNER_DEFAULT; cold = 0; break; @@ -934,35 +851,18 @@ .set_symbol_rate = sharp_z0194a_set_symbol_rate, }; -static int dm04_rs2000_set_ts_param(struct dvb_frontend *fe, - int caller) -{ - struct dvb_usb_adapter *adap = fe_to_adap(fe); - struct dvb_usb_device *d = adap_to_d(adap); - struct lme2510_state *st = d->priv; - - mutex_lock(&d->i2c_mutex); - if ((st->i2c_talk_onoff == 1) && (st->stream_on & 1)) { - st->i2c_talk_onoff = 0; - lme2510_stream_restart(d); - } - mutex_unlock(&d->i2c_mutex); - - return 0; -} - static struct m88rs2000_config m88rs2000_config = { - .demod_addr = 0x68, - .set_ts_params = dm04_rs2000_set_ts_param, + .demod_addr = 0x68 }; static struct ts2020_config ts2020_config = { .tuner_address = 0x60, .clk_out_div = 7, + .dont_poll = true }; static int dm04_lme2510_set_voltage(struct dvb_frontend *fe, - fe_sec_voltage_t voltage) + enum fe_sec_voltage voltage) { struct dvb_usb_device *d = fe_to_d(fe); struct lme2510_state *st = fe_to_priv(fe); @@ -997,27 +897,90 @@ return (ret < 0) ? -ENODEV : 0; } -static int dm04_rs2000_read_signal_strength(struct dvb_frontend *fe, - u16 *strength) +static int dm04_read_status(struct dvb_frontend *fe, enum fe_status *status) { + struct dvb_usb_device *d = fe_to_d(fe); + struct lme2510_state *st = d->priv; + int ret = 0; + + if (st->i2c_talk_onoff) { + if (st->fe_read_status) { + ret = st->fe_read_status(fe, status); + if (ret < 0) + return ret; + } + + st->lock_status = *status; + + if (*status & FE_HAS_LOCK && st->stream_on) { + mutex_lock(&d->i2c_mutex); + + st->i2c_talk_onoff = 0; + ret = lme2510_stream_restart(d); + + mutex_unlock(&d->i2c_mutex); + } + + return ret; + } + + /* Timeout of interrupt reached on RS2000 */ + if (st->tuner_config == TUNER_RS2000 && + time_after(jiffies, st->int_urb_due)) + st->lock_status &= ~FE_HAS_LOCK; + + *status = st->lock_status; + + if (!(*status & FE_HAS_LOCK)) { + struct dvb_usb_adapter *adap = fe_to_adap(fe); + + st->i2c_talk_onoff = 1; + + lme2510_update_stats(adap); + } + + return ret; +} + +static int dm04_read_signal_strength(struct dvb_frontend *fe, u16 *strength) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct lme2510_state *st = fe_to_priv(fe); - *strength = (u16)((u32)st->signal_level * 0xffff / 0xff); + if (st->fe_read_signal_strength && !st->stream_on) + return st->fe_read_signal_strength(fe, strength); + + if (c->strength.stat[0].scale == FE_SCALE_RELATIVE) + *strength = (u16)c->strength.stat[0].uvalue; + else + *strength = 0; return 0; } -static int dm04_rs2000_read_snr(struct dvb_frontend *fe, u16 *snr) +static int dm04_read_snr(struct dvb_frontend *fe, u16 *snr) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct lme2510_state *st = fe_to_priv(fe); - *snr = (u16)((u32)st->signal_sn * 0xffff / 0x7f); + if (st->fe_read_snr && !st->stream_on) + return st->fe_read_snr(fe, snr); + + if (c->cnr.stat[0].scale == FE_SCALE_RELATIVE) + *snr = (u16)c->cnr.stat[0].uvalue; + else + *snr = 0; return 0; } static int dm04_read_ber(struct dvb_frontend *fe, u32 *ber) { + struct lme2510_state *st = fe_to_priv(fe); + + if (st->fe_read_ber && !st->stream_on) + return st->fe_read_ber(fe, ber); + *ber = 0; return 0; @@ -1025,6 +988,11 @@ static int dm04_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) { + struct lme2510_state *st = fe_to_priv(fe); + + if (st->fe_read_ucblocks && !st->stream_on) + return st->fe_read_ucblocks(fe, ucblocks); + *ucblocks = 0; return 0; @@ -1118,15 +1086,6 @@ st->tuner_config = TUNER_RS2000; st->fe_set_voltage = adap->fe[0]->ops.set_voltage; - - adap->fe[0]->ops.read_signal_strength = - dm04_rs2000_read_signal_strength; - adap->fe[0]->ops.read_snr = - dm04_rs2000_read_snr; - adap->fe[0]->ops.read_ber = - dm04_read_ber; - adap->fe[0]->ops.read_ucblocks = - dm04_read_ucblocks; } break; } @@ -1145,7 +1104,19 @@ return -ENODEV; } + st->fe_read_status = adap->fe[0]->ops.read_status; + st->fe_read_signal_strength = adap->fe[0]->ops.read_signal_strength; + st->fe_read_snr = adap->fe[0]->ops.read_snr; + st->fe_read_ber = adap->fe[0]->ops.read_ber; + st->fe_read_ucblocks = adap->fe[0]->ops.read_ucblocks; + + adap->fe[0]->ops.read_status = dm04_read_status; + adap->fe[0]->ops.read_signal_strength = dm04_read_signal_strength; + adap->fe[0]->ops.read_snr = dm04_read_snr; + adap->fe[0]->ops.read_ber = dm04_read_ber; + adap->fe[0]->ops.read_ucblocks = dm04_read_ucblocks; adap->fe[0]->ops.set_voltage = dm04_lme2510_set_voltage; + ret = lme_name(adap); return ret; } @@ -1232,7 +1203,7 @@ usb_reset_configuration(d->udev); usb_set_interface(d->udev, - d->intf->cur_altsetting->desc.bInterfaceNumber, 1); + d->props->bInterfaceNumber, 1); st->dvb_usb_lme2510_firmware = dvb_usb_lme2510_firmware; @@ -1257,7 +1228,7 @@ /* Turn PID filter on the fly by module option */ if (pid_filter == 2) { - adap->pid_filtering = 1; + adap->pid_filtering = true; adap->max_feed_count = 15; } @@ -1287,7 +1258,6 @@ if (st->usb_buffer != NULL) { st->i2c_talk_onoff = 1; - st->signal_lock = 0; st->signal_level = 0; st->signal_sn = 0; buffer = st->usb_buffer; @@ -1375,7 +1345,7 @@ MODULE_AUTHOR("Malcolm Priestley "); MODULE_DESCRIPTION("LME2510(C) DVB-S USB2.0"); -MODULE_VERSION("2.06"); +MODULE_VERSION("2.07"); MODULE_LICENSE("GPL"); MODULE_FIRMWARE(LME2510_C_S7395); MODULE_FIRMWARE(LME2510_C_LG);