📄 af9005-fe.c
字号:
/* Frontend part of the Linux driver for the Afatech 9005 * USB1.1 DVB-T receiver. * * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org) * * Thanks to Afatech who kindly provided information. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * see Documentation/dvb/README.dvb-usb for more information */#include "af9005.h"#include "af9005-script.h"#include "mt2060.h"#include "qt1010.h"#include <asm/div64.h>struct af9005_fe_state { struct dvb_usb_device *d; fe_status_t stat; /* retraining parameters */ u32 original_fcw; u16 original_rf_top; u16 original_if_top; u16 original_if_min; u16 original_aci0_if_top; u16 original_aci1_if_top; u16 original_aci0_if_min; u8 original_if_unplug_th; u8 original_rf_unplug_th; u8 original_dtop_if_unplug_th; u8 original_dtop_rf_unplug_th; /* statistics */ u32 pre_vit_error_count; u32 pre_vit_bit_count; u32 ber; u32 post_vit_error_count; u32 post_vit_bit_count; u32 unc; u16 abort_count; int opened; int strong; unsigned long next_status_check; struct dvb_frontend frontend;};static int af9005_write_word_agc(struct dvb_usb_device *d, u16 reghi, u16 reglo, u8 pos, u8 len, u16 value){ int ret; u8 temp; if ((ret = af9005_write_ofdm_register(d, reglo, (u8) (value & 0xff)))) return ret; temp = (u8) ((value & 0x0300) >> 8); return af9005_write_register_bits(d, reghi, pos, len, (u8) ((value & 0x300) >> 8));}static int af9005_read_word_agc(struct dvb_usb_device *d, u16 reghi, u16 reglo, u8 pos, u8 len, u16 * value){ int ret; u8 temp0, temp1; if ((ret = af9005_read_ofdm_register(d, reglo, &temp0))) return ret; if ((ret = af9005_read_ofdm_register(d, reghi, &temp1))) return ret; switch (pos) { case 0: *value = ((u16) (temp1 & 0x03) << 8) + (u16) temp0; break; case 2: *value = ((u16) (temp1 & 0x0C) << 6) + (u16) temp0; break; case 4: *value = ((u16) (temp1 & 0x30) << 4) + (u16) temp0; break; case 6: *value = ((u16) (temp1 & 0xC0) << 2) + (u16) temp0; break; default: err("invalid pos in read word agc"); return -EINVAL; } return 0;}static int af9005_is_fecmon_available(struct dvb_frontend *fe, int *available){ struct af9005_fe_state *state = fe->demodulator_priv; int ret; u8 temp; *available = false; ret = af9005_read_register_bits(state->d, xd_p_fec_vtb_rsd_mon_en, fec_vtb_rsd_mon_en_pos, fec_vtb_rsd_mon_en_len, &temp); if (ret) return ret; if (temp & 1) { ret = af9005_read_register_bits(state->d, xd_p_reg_ofsm_read_rbc_en, reg_ofsm_read_rbc_en_pos, reg_ofsm_read_rbc_en_len, &temp); if (ret) return ret; if ((temp & 1) == 0) *available = true; } return 0;}static int af9005_get_post_vit_err_cw_count(struct dvb_frontend *fe, u32 * post_err_count, u32 * post_cw_count, u16 * abort_count){ struct af9005_fe_state *state = fe->demodulator_priv; int ret; u32 err_count; u32 cw_count; u8 temp, temp0, temp1, temp2; u16 loc_abort_count; *post_err_count = 0; *post_cw_count = 0; /* check if error bit count is ready */ ret = af9005_read_register_bits(state->d, xd_r_fec_rsd_ber_rdy, fec_rsd_ber_rdy_pos, fec_rsd_ber_rdy_len, &temp); if (ret) return ret; if (!temp) { deb_info("rsd counter not ready\n"); return 100; } /* get abort count */ ret = af9005_read_ofdm_register(state->d, xd_r_fec_rsd_abort_packet_cnt_7_0, &temp0); if (ret) return ret; ret = af9005_read_ofdm_register(state->d, xd_r_fec_rsd_abort_packet_cnt_15_8, &temp1); if (ret) return ret; loc_abort_count = ((u16) temp1 << 8) + temp0; /* get error count */ ret = af9005_read_ofdm_register(state->d, xd_r_fec_rsd_bit_err_cnt_7_0, &temp0); if (ret) return ret; ret = af9005_read_ofdm_register(state->d, xd_r_fec_rsd_bit_err_cnt_15_8, &temp1); if (ret) return ret; ret = af9005_read_ofdm_register(state->d, xd_r_fec_rsd_bit_err_cnt_23_16, &temp2); if (ret) return ret; err_count = ((u32) temp2 << 16) + ((u32) temp1 << 8) + temp0; *post_err_count = err_count - (u32) loc_abort_count *8 * 8; /* get RSD packet number */ ret = af9005_read_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_7_0, &temp0); if (ret) return ret; ret = af9005_read_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_15_8, &temp1); if (ret) return ret; cw_count = ((u32) temp1 << 8) + temp0; if (cw_count == 0) { err("wrong RSD packet count"); return -EIO; } deb_info("POST abort count %d err count %d rsd packets %d\n", loc_abort_count, err_count, cw_count); *post_cw_count = cw_count - (u32) loc_abort_count; *abort_count = loc_abort_count; return 0;}static int af9005_get_post_vit_ber(struct dvb_frontend *fe, u32 * post_err_count, u32 * post_cw_count, u16 * abort_count){ u32 loc_cw_count = 0, loc_err_count; u16 loc_abort_count; int ret; ret = af9005_get_post_vit_err_cw_count(fe, &loc_err_count, &loc_cw_count, &loc_abort_count); if (ret) return ret; *post_err_count = loc_err_count; *post_cw_count = loc_cw_count * 204 * 8; *abort_count = loc_abort_count; return 0;}static int af9005_get_pre_vit_err_bit_count(struct dvb_frontend *fe, u32 * pre_err_count, u32 * pre_bit_count){ struct af9005_fe_state *state = fe->demodulator_priv; u8 temp, temp0, temp1, temp2; u32 super_frame_count, x, bits; int ret; ret = af9005_read_register_bits(state->d, xd_r_fec_vtb_ber_rdy, fec_vtb_ber_rdy_pos, fec_vtb_ber_rdy_len, &temp); if (ret) return ret; if (!temp) { deb_info("viterbi counter not ready\n"); return 101; /* ERR_APO_VTB_COUNTER_NOT_READY; */ } ret = af9005_read_ofdm_register(state->d, xd_r_fec_vtb_err_bit_cnt_7_0, &temp0); if (ret) return ret; ret = af9005_read_ofdm_register(state->d, xd_r_fec_vtb_err_bit_cnt_15_8, &temp1); if (ret) return ret; ret = af9005_read_ofdm_register(state->d, xd_r_fec_vtb_err_bit_cnt_23_16, &temp2); if (ret) return ret; *pre_err_count = ((u32) temp2 << 16) + ((u32) temp1 << 8) + temp0; ret = af9005_read_ofdm_register(state->d, xd_p_fec_super_frm_unit_7_0, &temp0); if (ret) return ret; ret = af9005_read_ofdm_register(state->d, xd_p_fec_super_frm_unit_15_8, &temp1); if (ret) return ret; super_frame_count = ((u32) temp1 << 8) + temp0; if (super_frame_count == 0) { deb_info("super frame count 0\n"); return 102; } /* read fft mode */ ret = af9005_read_register_bits(state->d, xd_g_reg_tpsd_txmod, reg_tpsd_txmod_pos, reg_tpsd_txmod_len, &temp); if (ret) return ret; if (temp == 0) { /* 2K */ x = 1512; } else if (temp == 1) { /* 8k */ x = 6048; } else { err("Invalid fft mode"); return -EINVAL; } /* read constellation mode */ ret = af9005_read_register_bits(state->d, xd_g_reg_tpsd_const, reg_tpsd_const_pos, reg_tpsd_const_len, &temp); if (ret) return ret; switch (temp) { case 0: /* QPSK */ bits = 2; break; case 1: /* QAM_16 */ bits = 4; break; case 2: /* QAM_64 */ bits = 6; break; default: err("invalid constellation mode"); return -EINVAL; } *pre_bit_count = super_frame_count * 68 * 4 * x * bits; deb_info("PRE err count %d frame count %d bit count %d\n", *pre_err_count, super_frame_count, *pre_bit_count); return 0;}static int af9005_reset_pre_viterbi(struct dvb_frontend *fe){ struct af9005_fe_state *state = fe->demodulator_priv; int ret; /* set super frame count to 1 */ ret = af9005_write_ofdm_register(state->d, xd_p_fec_super_frm_unit_7_0, 1 & 0xff); if (ret) return ret; ret = af9005_write_ofdm_register(state->d, xd_p_fec_super_frm_unit_15_8, 1 >> 8); if (ret) return ret; /* reset pre viterbi error count */ ret = af9005_write_register_bits(state->d, xd_p_fec_vtb_ber_rst, fec_vtb_ber_rst_pos, fec_vtb_ber_rst_len, 1); return ret;}static int af9005_reset_post_viterbi(struct dvb_frontend *fe){ struct af9005_fe_state *state = fe->demodulator_priv; int ret; /* set packet unit */ ret = af9005_write_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_7_0, 10000 & 0xff); if (ret) return ret; ret = af9005_write_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_15_8, 10000 >> 8); if (ret) return ret; /* reset post viterbi error count */ ret = af9005_write_register_bits(state->d, xd_p_fec_rsd_ber_rst, fec_rsd_ber_rst_pos, fec_rsd_ber_rst_len, 1); return ret;}static int af9005_get_statistic(struct dvb_frontend *fe){ struct af9005_fe_state *state = fe->demodulator_priv; int ret, fecavailable; u64 numerator, denominator; deb_info("GET STATISTIC\n"); ret = af9005_is_fecmon_available(fe, &fecavailable); if (ret) return ret; if (!fecavailable) { deb_info("fecmon not available\n"); return 0; } ret = af9005_get_pre_vit_err_bit_count(fe, &state->pre_vit_error_count, &state->pre_vit_bit_count); if (ret == 0) { af9005_reset_pre_viterbi(fe); if (state->pre_vit_bit_count > 0) { /* according to v 0.0.4 of the dvb api ber should be a multiple of 10E-9 so we have to multiply the error count by 10E9=1000000000 */ numerator = (u64) state->pre_vit_error_count * (u64) 1000000000; denominator = (u64) state->pre_vit_bit_count; state->ber = do_div(numerator, denominator); } else { state->ber = 0xffffffff; } } ret = af9005_get_post_vit_ber(fe, &state->post_vit_error_count, &state->post_vit_bit_count, &state->abort_count); if (ret == 0) { ret = af9005_reset_post_viterbi(fe); state->unc += state->abort_count; if (ret) return ret; } return 0;}static int af9005_fe_refresh_state(struct dvb_frontend *fe){ struct af9005_fe_state *state = fe->demodulator_priv; if (time_after(jiffies, state->next_status_check)) { deb_info("REFRESH STATE\n"); /* statistics */ if (af9005_get_statistic(fe)) err("get_statistic_failed"); state->next_status_check = jiffies + 250 * HZ / 1000; } return 0;}static int af9005_fe_read_status(struct dvb_frontend *fe, fe_status_t * stat){ struct af9005_fe_state *state = fe->demodulator_priv; u8 temp;#if 0 /* adjust mt2060 for strong signal (test) */ u8 buf[2]; struct i2c_msg msg = { .addr = 0xc0,.flags = 0,.buf = buf,.len = 2 };#endif int ret; if (fe->ops.tuner_ops.release == NULL) return -ENODEV; *stat = 0; ret = af9005_read_register_bits(state->d, xd_p_agc_lock, agc_lock_pos, agc_lock_len, &temp); if (ret) return ret; if (temp) *stat |= FE_HAS_SIGNAL; ret = af9005_read_register_bits(state->d, xd_p_fd_tpsd_lock, fd_tpsd_lock_pos, fd_tpsd_lock_len, &temp); if (ret) return ret; if (temp) *stat |= FE_HAS_CARRIER; ret = af9005_read_register_bits(state->d, xd_r_mp2if_sync_byte_locked, mp2if_sync_byte_locked_pos, mp2if_sync_byte_locked_pos, &temp); if (ret) return ret; if (temp) *stat |= FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_LOCK; if (state->opened) af9005_led_control(state->d, *stat & FE_HAS_LOCK); ret = af9005_read_register_bits(state->d, xd_p_reg_strong_sginal_detected, reg_strong_sginal_detected_pos, reg_strong_sginal_detected_len, &temp); if (ret) return ret; if (temp != state->strong) { deb_info("adjust for strong signal %d\n", temp);#if 0 /* adjust mt2060 for strong signal (test) */ buf[0] = 0x0b; if (temp) { buf[1] = 0x30; } else { buf[1] = 0x33; } if (i2c_transfer(&state->d->i2c_adap, &msg, 1) != 1) { err("aiaiaia"); } else#endif state->strong = temp; } return 0;}static int af9005_fe_read_ber(struct dvb_frontend *fe, u32 * ber){ struct af9005_fe_state *state = fe->demodulator_priv; if (fe->ops.tuner_ops.release == NULL) return -ENODEV; af9005_fe_refresh_state(fe); *ber = state->ber; return 0;}static int af9005_fe_read_unc_blocks(struct dvb_frontend *fe, u32 * unc){ struct af9005_fe_state *state = fe->demodulator_priv; if (fe->ops.tuner_ops.release == NULL) return -ENODEV; af9005_fe_refresh_state(fe); *unc = state->unc; return 0;}static int af9005_fe_read_signal_strength(struct dvb_frontend *fe, u16 * strength){ struct af9005_fe_state *state = fe->demodulator_priv; int ret; u8 if_gain, rf_gain; if (fe->ops.tuner_ops.release == NULL) return -ENODEV; ret = af9005_read_ofdm_register(state->d, xd_r_reg_aagc_rf_gain, &rf_gain); if (ret) return ret; ret =
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -