Copyright (C) 2006-2008 Steven Toth <stoth@hauppauge.com> Copyright (C) 2006-2007 Georg Acher Copyright (C) 2007-2008 Darron Broad March 2007 Fixed some bugs. Added diseqc support. Added corrected signal strength support. August 2007 Sync with legacy version. Some clean ups. Copyright (C) 2008 Igor Liplianin September, 9th 2008 Fixed locking on high symbol rates (>30000). Implement MPEG initialization parameter. January, 17th 2009 Fill set_voltage with actually control voltage code. Correct set tone to not affect voltage.
switch (inversion) { case INVERSION_OFF:
state->dnxt.inversion_val = 0x00; break; case INVERSION_ON:
state->dnxt.inversion_val = 0x04; break; case INVERSION_AUTO:
state->dnxt.inversion_val = 0x0C; break; default: return -EINVAL;
}
state->dnxt.inversion = inversion;
return 0;
}
/* * modfec (modulation and FEC) * =========================== * * MOD FEC mask/val standard * ---- -------- ----------- -------- * QPSK FEC_1_2 0x02 0x02+X DVB-S * QPSK FEC_2_3 0x04 0x02+X DVB-S * QPSK FEC_3_4 0x08 0x02+X DVB-S * QPSK FEC_4_5 0x10 0x02+X DVB-S (?) * QPSK FEC_5_6 0x20 0x02+X DVB-S * QPSK FEC_6_7 0x40 0x02+X DVB-S * QPSK FEC_7_8 0x80 0x02+X DVB-S * QPSK FEC_8_9 0x01 0x02+X DVB-S (?) (NOT SUPPORTED?) * QPSK AUTO 0xff 0x02+X DVB-S * * For DVB-S high byte probably represents FEC * and low byte selects the modulator. The high * byte is search range mask. Bit 5 may turn * on DVB-S and remaining bits represent some * kind of calibration (how/what i do not know). * * Eg.(2/3) szap "Zone Horror" * * mask/val = 0x04, 0x20 * status 1f | signal c3c0 | snr a333 | ber 00000098 | unc 0 | FE_HAS_LOCK * * mask/val = 0x04, 0x30 * status 1f | signal c3c0 | snr a333 | ber 00000000 | unc 0 | FE_HAS_LOCK * * After tuning FECSTATUS contains actual FEC * in use numbered 1 through to 8 for 1/2 .. 2/3 etc * * NBC=NOT/NON BACKWARD COMPATIBLE WITH DVB-S (DVB-S2 only) * * NBC-QPSK FEC_1_2 0x00, 0x04 DVB-S2 * NBC-QPSK FEC_3_5 0x00, 0x05 DVB-S2 * NBC-QPSK FEC_2_3 0x00, 0x06 DVB-S2 * NBC-QPSK FEC_3_4 0x00, 0x07 DVB-S2 * NBC-QPSK FEC_4_5 0x00, 0x08 DVB-S2 * NBC-QPSK FEC_5_6 0x00, 0x09 DVB-S2 * NBC-QPSK FEC_8_9 0x00, 0x0a DVB-S2 * NBC-QPSK FEC_9_10 0x00, 0x0b DVB-S2 * * NBC-8PSK FEC_3_5 0x00, 0x0c DVB-S2 * NBC-8PSK FEC_2_3 0x00, 0x0d DVB-S2 * NBC-8PSK FEC_3_4 0x00, 0x0e DVB-S2 * NBC-8PSK FEC_5_6 0x00, 0x0f DVB-S2 * NBC-8PSK FEC_8_9 0x00, 0x10 DVB-S2 * NBC-8PSK FEC_9_10 0x00, 0x11 DVB-S2 * * For DVB-S2 low bytes selects both modulator * and FEC. High byte is meaningless here. To * set pilot, bit 6 (0x40) is set. When inspecting * FECSTATUS bit 7 (0x80) represents the pilot * selection whilst not tuned. When tuned, actual FEC * in use is found in FECSTATUS as per above. Pilot * value is reset.
*/
/* A table of modulation, fec and configuration bytes for the demod. * Not all S2 mmodulation schemes are support and not all rates with * a scheme are support. Especially, no auto detect when in S2 mode.
*/ staticstruct cx24116_modfec { enum fe_delivery_system delivery_system; enum fe_modulation modulation; enum fe_code_rate fec;
u8 mask; /* In DVBS mode this is used to autodetect */
u8 val; /* Passed to the firmware to indicate mode selection */
} CX24116_MODFEC_MODES[] = { /* QPSK. For unknown rates we set hardware to auto detect 0xfe 0x30 */
staticint cx24116_lookup_fecmod(struct cx24116_state *state, enum fe_delivery_system d, enum fe_modulation m, enum fe_code_rate f)
{ int i, ret = -EOPNOTSUPP;
dprintk("%s(0x%02x,0x%02x)\n", __func__, m, f);
for (i = 0; i < ARRAY_SIZE(CX24116_MODFEC_MODES); i++) { if ((d == CX24116_MODFEC_MODES[i].delivery_system) &&
(m == CX24116_MODFEC_MODES[i].modulation) &&
(f == CX24116_MODFEC_MODES[i].fec)) {
ret = i; break;
}
}
return ret;
}
staticint cx24116_set_fec(struct cx24116_state *state, enum fe_delivery_system delsys, enum fe_modulation mod, enum fe_code_rate fec)
{ int ret = 0;
staticint cx24116_firmware_ondemand(struct dvb_frontend *fe)
{ struct cx24116_state *state = fe->demodulator_priv; conststruct firmware *fw; int ret = 0;
dprintk("%s()\n", __func__);
if (cx24116_readreg(state, 0x20) > 0) {
if (state->skip_fw_load) return 0;
/* Load firmware */ /* request the firmware, this will block until loaded */
printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n",
__func__, CX24116_DEFAULT_FIRMWARE);
ret = request_firmware(&fw, CX24116_DEFAULT_FIRMWARE,
state->i2c->dev.parent);
printk(KERN_INFO "%s: Waiting for firmware upload(2)...\n",
__func__); if (ret) {
printk(KERN_ERR "%s: No firmware uploaded (timeout or file not found?)\n",
__func__); return ret;
}
/* Make sure we don't recurse back through here
* during loading */
state->skip_fw_load = 1;
ret = cx24116_load_firmware(fe, fw); if (ret)
printk(KERN_ERR "%s: Writing firmware to device failed\n",
__func__);
/* Ensure firmware is always loaded if required */
state->skip_fw_load = 0;
}
return ret;
}
/* Take a basic firmware command structure, format it * and forward it for processing
*/ staticint cx24116_cmd_execute(struct dvb_frontend *fe, struct cx24116_cmd *cmd)
{ struct cx24116_state *state = fe->demodulator_priv; int i, ret;
dprintk("%s()\n", __func__);
/* Load the firmware if required */
ret = cx24116_firmware_ondemand(fe); if (ret != 0) {
printk(KERN_ERR "%s(): Unable initialise the firmware\n",
__func__); return ret;
}
/* Write the command */ for (i = 0; i < cmd->len ; i++) {
dprintk("%s: 0x%02x == 0x%02x\n", __func__, i, cmd->args[i]);
cx24116_writereg(state, i, cmd->args[i]);
}
/* Start execution and wait for cmd to terminate */
cx24116_writereg(state, CX24116_REG_EXECUTE, 0x01); while (cx24116_readreg(state, CX24116_REG_EXECUTE)) {
msleep(10); if (i++ > 64) { /* Avoid looping forever if the firmware does
not respond */
printk(KERN_WARNING "%s() Firmware not responding\n",
__func__); return -EREMOTEIO;
}
} return 0;
}
/* Split firmware to the max I2C write len and write.
* Writes whole firmware as one write when i2c_wr_max is set to 0. */ if (state->config->i2c_wr_max)
max = state->config->i2c_wr_max; else
max = INT_MAX; /* enough for 32k firmware */
for (remaining = fw->size; remaining > 0; remaining -= max - 1) {
len = remaining; if (len > max - 1)
len = max - 1;
/* The reelbox patches show the value in the registers represents * ESNO, from 0->30db (values 0->300). We provide this value by * default.
*/ staticint cx24116_read_snr_esno(struct dvb_frontend *fe, u16 *snr)
{ struct cx24116_state *state = fe->demodulator_priv;
/* Overwrite the current tuning params, we are about to tune */ staticvoid cx24116_clone_params(struct dvb_frontend *fe)
{ struct cx24116_state *state = fe->demodulator_priv;
state->dcur = state->dnxt;
}
/* Wait for LNB */ staticint cx24116_wait_for_lnb(struct dvb_frontend *fe)
{ struct cx24116_state *state = fe->demodulator_priv; int i;
/* allocate memory for the internal state */
state = kzalloc(sizeof(*state), GFP_KERNEL); if (state == NULL) return NULL;
state->config = config;
state->i2c = i2c;
/* check if the demod is present */
ret = (cx24116_readreg(state, 0xFF) << 8) |
cx24116_readreg(state, 0xFE); if (ret != 0x0501) {
kfree(state);
printk(KERN_INFO "Invalid probe, probably not a CX24116 device\n"); return NULL;
}
/* * Initialise or wake up device * * Power config will reset and load initial firmware if required
*/ staticint cx24116_initfe(struct dvb_frontend *fe)
{ struct cx24116_state *state = fe->demodulator_priv; struct cx24116_cmd cmd; int ret;
dprintk("%s()\n", __func__);
/* Power on */
cx24116_writereg(state, 0xe0, 0);
cx24116_writereg(state, 0xe1, 0);
cx24116_writereg(state, 0xea, 0);
/* Firmware CMD 36: Power config */
cmd.args[0x00] = CMD_TUNERSLEEP;
cmd.args[0x01] = 0;
cmd.len = 0x02;
ret = cx24116_cmd_execute(fe, &cmd); if (ret != 0) return ret;
ret = cx24116_diseqc_init(fe); if (ret != 0) return ret;
/* HVR-4000 needs this */ return cx24116_set_voltage(fe, SEC_VOLTAGE_13);
}
/* * Put device to sleep
*/ staticint cx24116_sleep(struct dvb_frontend *fe)
{ struct cx24116_state *state = fe->demodulator_priv; struct cx24116_cmd cmd; int ret;
dprintk("%s()\n", __func__);
/* Firmware CMD 36: Power config */
cmd.args[0x00] = CMD_TUNERSLEEP;
cmd.args[0x01] = 1;
cmd.len = 0x02;
ret = cx24116_cmd_execute(fe, &cmd); if (ret != 0) return ret;
/* Power off (Shutdown clocks) */
cx24116_writereg(state, 0xea, 0xff);
cx24116_writereg(state, 0xe1, 1);
cx24116_writereg(state, 0xe0, 1);
return 0;
}
/* dvb-core told us to tune, the tv property cache will be complete, * it's safe for is to pull values and use them for tuning purposes.
*/ staticint cx24116_set_frontend(struct dvb_frontend *fe)
{ struct cx24116_state *state = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct cx24116_cmd cmd; enum fe_status tunerstat; int i, status, ret, retune = 1;
dprintk("%s()\n", __func__);
switch (c->delivery_system) { case SYS_DVBS:
dprintk("%s: DVB-S delivery system selected\n", __func__);
/* Only QPSK is supported for DVB-S */ if (c->modulation != QPSK) {
dprintk("%s: unsupported modulation selected (%d)\n",
__func__, c->modulation); return -EOPNOTSUPP;
}
/* Pilot doesn't exist in DVB-S, turn bit off */
state->dnxt.pilot_val = CX24116_PILOT_OFF;
ret = cx24116_set_inversion(state, c->inversion); if (ret != 0) return ret;
/* FEC_NONE/AUTO for DVB-S2 is not supported and detected here */
ret = cx24116_set_fec(state, c->delivery_system, c->modulation, c->fec_inner); if (ret != 0) return ret;
ret = cx24116_set_symbolrate(state, c->symbol_rate); if (ret != 0) return ret;
/* discard the 'current' tuning parameters and prepare to tune */
cx24116_clone_params(fe);
/* We need to support pilot and non-pilot tuning in the * driver automatically. This is a workaround for because * the demod does not support autodetect.
*/ do { /* Reset status register */
status = cx24116_readreg(state, CX24116_REG_SSTATUS)
& CX24116_SIGNAL_MASK;
cx24116_writereg(state, CX24116_REG_SSTATUS, status);
/* Tune */
ret = cx24116_cmd_execute(fe, &cmd); if (ret != 0) break;
/* * Wait for up to 500 ms before retrying * * If we are able to tune then generally it occurs within 100ms. * If it takes longer, try a different toneburst setting.
*/ for (i = 0; i < 50 ; i++) {
cx24116_read_status(fe, &tunerstat);
status = tunerstat & (FE_HAS_SIGNAL | FE_HAS_SYNC); if (status == (FE_HAS_SIGNAL | FE_HAS_SYNC)) {
dprintk("%s: Tuned\n", __func__); goto tuned;
}
msleep(10);
}
dprintk("%s: Not tuned\n", __func__);
/* Toggle pilot bit when in auto-pilot */ if (state->dcur.pilot == PILOT_AUTO)
cmd.args[0x07] ^= CX24116_PILOT_ON;
} while (--retune);
staticint cx24116_tune(struct dvb_frontend *fe, bool re_tune, unsignedint mode_flags, unsignedint *delay, enum fe_status *status)
{ /* * It is safe to discard "params" here, as the DVB core will sync * fe->dtv_property_cache with fepriv->parameters_in, where the * DVBv3 params are stored. The only practical usage for it indicate * that re-tuning is needed, e. g. (fepriv->state & FESTATE_RETUNE) is * true.
*/
*delay = HZ / 5; if (re_tune) { int ret = cx24116_set_frontend(fe); if (ret) return ret;
} return cx24116_read_status(fe, status);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.