dib3000mc.c
来自「trident tm5600的linux驱动」· C语言 代码 · 共 935 行 · 第 1/2 页
C
935 行
dib3000mc_write_word(state, 95,0); dib3000mc_write_word(state, 96,0); dib3000mc_write_word(state, 97,0); dib3000mc_write_word(state, 98,0); dib3000mc_set_impulse_noise(state, 0, ch->u.ofdm.transmission_mode); value = 0; switch (ch->u.ofdm.transmission_mode) { case TRANSMISSION_MODE_2K: value |= (0 << 7); break; default: case TRANSMISSION_MODE_8K: value |= (1 << 7); break; } switch (ch->u.ofdm.guard_interval) { case GUARD_INTERVAL_1_32: value |= (0 << 5); break; case GUARD_INTERVAL_1_16: value |= (1 << 5); break; case GUARD_INTERVAL_1_4: value |= (3 << 5); break; default: case GUARD_INTERVAL_1_8: value |= (2 << 5); break; } switch (ch->u.ofdm.constellation) { case QPSK: value |= (0 << 3); break; case QAM_16: value |= (1 << 3); break; default: case QAM_64: value |= (2 << 3); break; } switch (HIERARCHY_1) { case HIERARCHY_2: value |= 2; break; case HIERARCHY_4: value |= 4; break; default: case HIERARCHY_1: value |= 1; break; } dib3000mc_write_word(state, 0, value); dib3000mc_write_word(state, 5, (1 << 8) | ((seq & 0xf) << 4)); value = 0; if (ch->u.ofdm.hierarchy_information == 1) value |= (1 << 4); if (1 == 1) value |= 1; switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) { case FEC_2_3: value |= (2 << 1); break; case FEC_3_4: value |= (3 << 1); break; case FEC_5_6: value |= (5 << 1); break; case FEC_7_8: value |= (7 << 1); break; default: case FEC_1_2: value |= (1 << 1); break; } dib3000mc_write_word(state, 181, value); // diversity synchro delay add 50% SFN margin switch (ch->u.ofdm.transmission_mode) { case TRANSMISSION_MODE_8K: value = 256; break; case TRANSMISSION_MODE_2K: default: value = 64; break; } switch (ch->u.ofdm.guard_interval) { case GUARD_INTERVAL_1_16: value *= 2; break; case GUARD_INTERVAL_1_8: value *= 4; break; case GUARD_INTERVAL_1_4: value *= 8; break; default: case GUARD_INTERVAL_1_32: value *= 1; break; } value <<= 4; value |= dib3000mc_read_word(state, 180) & 0x000f; dib3000mc_write_word(state, 180, value); // restart demod value = dib3000mc_read_word(state, 0); dib3000mc_write_word(state, 0, value | (1 << 9)); dib3000mc_write_word(state, 0, value); msleep(30); dib3000mc_set_impulse_noise(state, state->cfg->impulse_noise_mode, ch->u.ofdm.transmission_mode);}static int dib3000mc_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *chan){ struct dib3000mc_state *state = demod->demodulator_priv; u16 reg;// u32 val; struct dvb_frontend_parameters schan; schan = *chan; /* TODO what is that ? */#if 0 if (boost) { val = (dib3000mc_read_word(state, 6) << 16) | dib3000mc_read_word(state, 7); val *= 85; val >>= 7; dib3000mc_write_word(state, 6, (val >> 16) & 0xffff); dib3000mc_write_word(state, 7, (val ) & 0xffff); }#endif /* a channel for autosearch */ schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32; schan.u.ofdm.constellation = QAM_64; schan.u.ofdm.code_rate_HP = FEC_2_3; schan.u.ofdm.code_rate_LP = FEC_2_3; schan.u.ofdm.hierarchy_information = 0; dib3000mc_set_channel_cfg(state, &schan, 11); reg = dib3000mc_read_word(state, 0); dib3000mc_write_word(state, 0, reg | (1 << 8)); dib3000mc_read_word(state, 511); dib3000mc_write_word(state, 0, reg); return 0;}static int dib3000mc_autosearch_is_irq(struct dvb_frontend *demod){ struct dib3000mc_state *state = demod->demodulator_priv; u16 irq_pending = dib3000mc_read_word(state, 511); if (irq_pending & 0x1) // failed return 1; if (irq_pending & 0x2) // succeeded return 2; return 0; // still pending}static int dib3000mc_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch){ struct dib3000mc_state *state = demod->demodulator_priv; // ** configure demod ** dib3000mc_set_channel_cfg(state, ch, 0); // activates isi if (state->sfn_workaround_active) { dprintk("SFN workaround is active\n"); dib3000mc_write_word(state, 29, 0x1273); dib3000mc_write_word(state, 108, 0x4000); // P_pha3_force_pha_shift } else { dib3000mc_write_word(state, 29, 0x1073); dib3000mc_write_word(state, 108, 0x0000); // P_pha3_force_pha_shift } dib3000mc_set_adp_cfg(state, (u8)ch->u.ofdm.constellation); if (ch->u.ofdm.transmission_mode == TRANSMISSION_MODE_8K) { dib3000mc_write_word(state, 26, 38528); dib3000mc_write_word(state, 33, 8); } else { dib3000mc_write_word(state, 26, 30336); dib3000mc_write_word(state, 33, 6); } if (dib3000mc_read_word(state, 509) & 0x80) dib3000mc_set_timing(state, ch->u.ofdm.transmission_mode, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth), 1); return 0;}struct i2c_adapter * dib3000mc_get_tuner_i2c_master(struct dvb_frontend *demod, int gating){ struct dib3000mc_state *st = demod->demodulator_priv; return dibx000_get_i2c_adapter(&st->i2c_master, DIBX000_I2C_INTERFACE_TUNER, gating);}EXPORT_SYMBOL(dib3000mc_get_tuner_i2c_master);static int dib3000mc_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep){ struct dib3000mc_state *state = fe->demodulator_priv; u16 tps = dib3000mc_read_word(state,458); fep->inversion = INVERSION_AUTO; fep->u.ofdm.bandwidth = state->current_bandwidth; switch ((tps >> 8) & 0x1) { case 0: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; break; case 1: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; break; } switch (tps & 0x3) { case 0: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; break; case 1: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; break; case 2: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; break; case 3: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; break; } switch ((tps >> 13) & 0x3) { case 0: fep->u.ofdm.constellation = QPSK; break; case 1: fep->u.ofdm.constellation = QAM_16; break; case 2: default: fep->u.ofdm.constellation = QAM_64; break; } /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */ /* (tps >> 12) & 0x1 == hrch is used, (tps >> 9) & 0x7 == alpha */ fep->u.ofdm.hierarchy_information = HIERARCHY_NONE; switch ((tps >> 5) & 0x7) { case 1: fep->u.ofdm.code_rate_HP = FEC_1_2; break; case 2: fep->u.ofdm.code_rate_HP = FEC_2_3; break; case 3: fep->u.ofdm.code_rate_HP = FEC_3_4; break; case 5: fep->u.ofdm.code_rate_HP = FEC_5_6; break; case 7: default: fep->u.ofdm.code_rate_HP = FEC_7_8; break; } switch ((tps >> 2) & 0x7) { case 1: fep->u.ofdm.code_rate_LP = FEC_1_2; break; case 2: fep->u.ofdm.code_rate_LP = FEC_2_3; break; case 3: fep->u.ofdm.code_rate_LP = FEC_3_4; break; case 5: fep->u.ofdm.code_rate_LP = FEC_5_6; break; case 7: default: fep->u.ofdm.code_rate_LP = FEC_7_8; break; } return 0;}static int dib3000mc_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep){ struct dib3000mc_state *state = fe->demodulator_priv; int ret; dib3000mc_set_output_mode(state, OUTMODE_HIGH_Z); state->current_bandwidth = fep->u.ofdm.bandwidth; dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth)); /* maybe the parameter has been changed */ state->sfn_workaround_active = buggy_sfn_workaround; if (fe->ops.tuner_ops.set_params) { fe->ops.tuner_ops.set_params(fe, fep); msleep(100); } if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO || fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO || fep->u.ofdm.constellation == QAM_AUTO || fep->u.ofdm.code_rate_HP == FEC_AUTO) { int i = 1000, found; dib3000mc_autosearch_start(fe, fep); do { msleep(1); found = dib3000mc_autosearch_is_irq(fe); } while (found == 0 && i--); dprintk("autosearch returns: %d\n",found); if (found == 0 || found == 1) return 0; // no channel found dib3000mc_get_frontend(fe, fep); } ret = dib3000mc_tune(fe, fep); /* make this a config parameter */ dib3000mc_set_output_mode(state, OUTMODE_MPEG2_FIFO); return ret;}static int dib3000mc_read_status(struct dvb_frontend *fe, fe_status_t *stat){ struct dib3000mc_state *state = fe->demodulator_priv; u16 lock = dib3000mc_read_word(state, 509); *stat = 0; if (lock & 0x8000) *stat |= FE_HAS_SIGNAL; if (lock & 0x3000) *stat |= FE_HAS_CARRIER; if (lock & 0x0100) *stat |= FE_HAS_VITERBI; if (lock & 0x0010) *stat |= FE_HAS_SYNC; if (lock & 0x0008) *stat |= FE_HAS_LOCK; return 0;}static int dib3000mc_read_ber(struct dvb_frontend *fe, u32 *ber){ struct dib3000mc_state *state = fe->demodulator_priv; *ber = (dib3000mc_read_word(state, 500) << 16) | dib3000mc_read_word(state, 501); return 0;}static int dib3000mc_read_unc_blocks(struct dvb_frontend *fe, u32 *unc){ struct dib3000mc_state *state = fe->demodulator_priv; *unc = dib3000mc_read_word(state, 508); return 0;}static int dib3000mc_read_signal_strength(struct dvb_frontend *fe, u16 *strength){ struct dib3000mc_state *state = fe->demodulator_priv; u16 val = dib3000mc_read_word(state, 392); *strength = 65535 - val; return 0;}static int dib3000mc_read_snr(struct dvb_frontend* fe, u16 *snr){ *snr = 0x0000; return 0;}static int dib3000mc_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune){ tune->min_delay_ms = 1000; return 0;}static void dib3000mc_release(struct dvb_frontend *fe){ struct dib3000mc_state *state = fe->demodulator_priv; dibx000_exit_i2c_master(&state->i2c_master); kfree(state);}int dib3000mc_pid_control(struct dvb_frontend *fe, int index, int pid,int onoff){ struct dib3000mc_state *state = fe->demodulator_priv; dib3000mc_write_word(state, 212 + index, onoff ? (1 << 13) | pid : 0); return 0;}EXPORT_SYMBOL(dib3000mc_pid_control);int dib3000mc_pid_parse(struct dvb_frontend *fe, int onoff){ struct dib3000mc_state *state = fe->demodulator_priv; u16 tmp = dib3000mc_read_word(state, 206) & ~(1 << 4); tmp |= (onoff << 4); return dib3000mc_write_word(state, 206, tmp);}EXPORT_SYMBOL(dib3000mc_pid_parse);void dib3000mc_set_config(struct dvb_frontend *fe, struct dib3000mc_config *cfg){ struct dib3000mc_state *state = fe->demodulator_priv; state->cfg = cfg;}EXPORT_SYMBOL(dib3000mc_set_config);int dib3000mc_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib3000mc_config cfg[]){ struct dib3000mc_state st = { .i2c_adap = i2c }; int k; u8 new_addr; static u8 DIB3000MC_I2C_ADDRESS[] = {20,22,24,26}; for (k = no_of_demods-1; k >= 0; k--) { st.cfg = &cfg[k]; /* designated i2c address */ new_addr = DIB3000MC_I2C_ADDRESS[k]; st.i2c_addr = new_addr; if (dib3000mc_identify(&st) != 0) { st.i2c_addr = default_addr; if (dib3000mc_identify(&st) != 0) { dprintk("-E- DiB3000P/MC #%d: not identified\n", k); return -ENODEV; } } dib3000mc_set_output_mode(&st, OUTMODE_MPEG2_PAR_CONT_CLK); // set new i2c address and force divstr (Bit 1) to value 0 (Bit 0) dib3000mc_write_word(&st, 1024, (new_addr << 3) | 0x1); st.i2c_addr = new_addr; } for (k = 0; k < no_of_demods; k++) { st.cfg = &cfg[k]; st.i2c_addr = DIB3000MC_I2C_ADDRESS[k]; dib3000mc_write_word(&st, 1024, st.i2c_addr << 3); /* turn off data output */ dib3000mc_set_output_mode(&st, OUTMODE_HIGH_Z); } return 0;}EXPORT_SYMBOL(dib3000mc_i2c_enumeration);static struct dvb_frontend_ops dib3000mc_ops;struct dvb_frontend * dib3000mc_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib3000mc_config *cfg){ struct dvb_frontend *demod; struct dib3000mc_state *st; st = kzalloc(sizeof(struct dib3000mc_state), GFP_KERNEL); if (st == NULL) return NULL; st->cfg = cfg; st->i2c_adap = i2c_adap; st->i2c_addr = i2c_addr; demod = &st->demod; demod->demodulator_priv = st; memcpy(&st->demod.ops, &dib3000mc_ops, sizeof(struct dvb_frontend_ops)); if (dib3000mc_identify(st) != 0) goto error; dibx000_init_i2c_master(&st->i2c_master, DIB3000MC, st->i2c_adap, st->i2c_addr); dib3000mc_write_word(st, 1037, 0x3130); return demod;error: kfree(st); return NULL;}EXPORT_SYMBOL(dib3000mc_attach);static struct dvb_frontend_ops dib3000mc_ops = { .info = { .name = "DiBcom 3000MC/P", .type = FE_OFDM, .frequency_min = 44250000, .frequency_max = 867250000, .frequency_stepsize = 62500, .caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO, }, .release = dib3000mc_release, .init = dib3000mc_init, .sleep = dib3000mc_sleep, .set_frontend = dib3000mc_set_frontend, .get_tune_settings = dib3000mc_fe_get_tune_settings, .get_frontend = dib3000mc_get_frontend, .read_status = dib3000mc_read_status, .read_ber = dib3000mc_read_ber, .read_signal_strength = dib3000mc_read_signal_strength, .read_snr = dib3000mc_read_snr, .read_ucblocks = dib3000mc_read_unc_blocks,};MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");MODULE_DESCRIPTION("Driver for the DiBcom 3000MC/P COFDM demodulator");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?