📄 tda1004x.c
字号:
*fe_status = 0; if (status & 4) *fe_status |= FE_HAS_SIGNAL; if (status & 2) *fe_status |= FE_HAS_CARRIER; if (status & 8) *fe_status |= FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; // if we don't already have VITERBI (i.e. not LOCKED), see if the viterbi // is getting anything valid if (!(*fe_status & FE_HAS_VITERBI)) { // read the CBER cber = tda1004x_read_byte(i2c, tda_state, TDA1004X_CBER_LSB); if (cber == -1) return -EIO; status = tda1004x_read_byte(i2c, tda_state, TDA1004X_CBER_MSB); if (status == -1) return -EIO; cber |= (status << 8); tda1004x_read_byte(i2c, tda_state, TDA1004X_CBER_RESET); if (cber != 65535) { *fe_status |= FE_HAS_VITERBI; } } // if we DO have some valid VITERBI output, but don't already have SYNC // bytes (i.e. not LOCKED), see if the RS decoder is getting anything valid. if ((*fe_status & FE_HAS_VITERBI) && (!(*fe_status & FE_HAS_SYNC))) { // read the VBER vber = tda1004x_read_byte(i2c, tda_state, TDA1004X_VBER_LSB); if (vber == -1) return -EIO; status = tda1004x_read_byte(i2c, tda_state, TDA1004X_VBER_MID); if (status == -1) return -EIO; vber |= (status << 8); status = tda1004x_read_byte(i2c, tda_state, TDA1004X_VBER_MSB); if (status == -1) return -EIO; vber |= ((status << 16) & 0x0f); tda1004x_read_byte(i2c, tda_state, TDA1004X_CVBER_LUT); // if RS has passed some valid TS packets, then we must be // getting some SYNC bytes if (vber < 16632) { *fe_status |= FE_HAS_SYNC; } } // success dprintk("%s: fe_status=0x%x\n", __FUNCTION__, *fe_status); return 0;}static int tda1004x_read_signal_strength(struct dvb_i2c_bus *i2c, struct tda1004x_state* tda_state, u16 * signal){ int tmp; int reg = 0; dprintk("%s\n", __FUNCTION__); // determine the register to use switch(tda_state->fe_type) { case FE_TYPE_TDA10045H: reg = TDA10045H_S_AGC; break; case FE_TYPE_TDA10046H: reg = TDA10046H_AGC_IF_LEVEL; break; } // read it tmp = tda1004x_read_byte(i2c, tda_state, reg); if (tmp < 0) return -EIO; // done *signal = (tmp << 8) | tmp; dprintk("%s: signal=0x%x\n", __FUNCTION__, *signal); return 0;}static int tda1004x_read_snr(struct dvb_i2c_bus *i2c, struct tda1004x_state* tda_state, u16 * snr){ int tmp; dprintk("%s\n", __FUNCTION__); // read it tmp = tda1004x_read_byte(i2c, tda_state, TDA1004X_SNR); if (tmp < 0) return -EIO; if (tmp) { tmp = 255 - tmp; } // done *snr = ((tmp << 8) | tmp); dprintk("%s: snr=0x%x\n", __FUNCTION__, *snr); return 0;}static int tda1004x_read_ucblocks(struct dvb_i2c_bus *i2c, struct tda1004x_state* tda_state, u32* ucblocks){ int tmp; int tmp2; int counter; dprintk("%s\n", __FUNCTION__); // read the UCBLOCKS and reset counter = 0; tmp = tda1004x_read_byte(i2c, tda_state, TDA1004X_UNCOR); if (tmp < 0) return -EIO; tmp &= 0x7f; while (counter++ < 5) { tda1004x_write_mask(i2c, tda_state, TDA1004X_UNCOR, 0x80, 0); tda1004x_write_mask(i2c, tda_state, TDA1004X_UNCOR, 0x80, 0); tda1004x_write_mask(i2c, tda_state, TDA1004X_UNCOR, 0x80, 0); tmp2 = tda1004x_read_byte(i2c, tda_state, TDA1004X_UNCOR); if (tmp2 < 0) return -EIO; tmp2 &= 0x7f; if ((tmp2 < tmp) || (tmp2 == 0)) break; } // done if (tmp != 0x7f) { *ucblocks = tmp; } else { *ucblocks = 0xffffffff; } dprintk("%s: ucblocks=0x%x\n", __FUNCTION__, *ucblocks); return 0;}static int tda1004x_read_ber(struct dvb_i2c_bus *i2c, struct tda1004x_state* tda_state, u32* ber){ int tmp; dprintk("%s\n", __FUNCTION__); // read it in tmp = tda1004x_read_byte(i2c, tda_state, TDA1004X_CBER_LSB); if (tmp < 0) return -EIO; *ber = tmp << 1; tmp = tda1004x_read_byte(i2c, tda_state, TDA1004X_CBER_MSB); if (tmp < 0) return -EIO; *ber |= (tmp << 9); tda1004x_read_byte(i2c, tda_state, TDA1004X_CBER_RESET); // done dprintk("%s: ber=0x%x\n", __FUNCTION__, *ber); return 0;}static int tda1004x_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg){ int status = 0; struct dvb_i2c_bus *i2c = fe->i2c; struct tda1004x_state *tda_state = (struct tda1004x_state *) &(fe->data); dprintk("%s: cmd=0x%x\n", __FUNCTION__, cmd); switch (cmd) { case FE_GET_INFO: switch(tda_state->fe_type) { case FE_TYPE_TDA10045H: memcpy(arg, &tda10045h_info, sizeof(struct dvb_frontend_info)); break; case FE_TYPE_TDA10046H: memcpy(arg, &tda10046h_info, sizeof(struct dvb_frontend_info)); break; } break; case FE_READ_STATUS: return tda1004x_read_status(i2c, tda_state, (fe_status_t *) arg); case FE_READ_BER: return tda1004x_read_ber(i2c, tda_state, (u32 *) arg); case FE_READ_SIGNAL_STRENGTH: return tda1004x_read_signal_strength(i2c, tda_state, (u16 *) arg); case FE_READ_SNR: return tda1004x_read_snr(i2c, tda_state, (u16 *) arg); case FE_READ_UNCORRECTED_BLOCKS: return tda1004x_read_ucblocks(i2c, tda_state, (u32 *) arg); case FE_SET_FRONTEND: return tda1004x_set_fe(i2c, tda_state, (struct dvb_frontend_parameters*) arg); case FE_GET_FRONTEND: return tda1004x_get_fe(i2c, tda_state, (struct dvb_frontend_parameters*) arg); case FE_INIT: // don't bother reinitialising if (tda_state->initialised) return 0; // OK, perform initialisation switch(tda_state->fe_type) { case FE_TYPE_TDA10045H: status = tda10045h_init(i2c, tda_state); break; case FE_TYPE_TDA10046H: status = tda10046h_init(i2c, tda_state); break; } if (status == 0) tda_state->initialised = 1; return status; default: return -EOPNOTSUPP; } return 0;}static int tda1004x_attach(struct dvb_i2c_bus *i2c, void **data){ int tda1004x_address = -1; int tuner_address = -1; int fe_type = -1; int tuner_type = -1; struct tda1004x_state tda_state; struct i2c_msg tuner_msg = {.addr=0, .flags=0, .buf=0, .len=0 }; static u8 td1344_init[] = { 0x0b, 0xf5, 0x88, 0xab }; static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab }; static u8 td1316_init_tda10046h[] = { 0x0b, 0xf5, 0x80, 0xab }; int status; dprintk("%s\n", __FUNCTION__); // probe for tda10045h if (tda1004x_address == -1) { tda_state.tda1004x_address = 0x08; if (tda1004x_read_byte(i2c, &tda_state, TDA1004X_CHIPID) == 0x25) { tda1004x_address = 0x08; fe_type = FE_TYPE_TDA10045H; printk("tda1004x: Detected Philips TDA10045H.\n"); } } // probe for tda10046h if (tda1004x_address == -1) { tda_state.tda1004x_address = 0x08; if (tda1004x_read_byte(i2c, &tda_state, TDA1004X_CHIPID) == 0x46) { tda1004x_address = 0x08; fe_type = FE_TYPE_TDA10046H; printk("tda1004x: Detected Philips TDA10046H.\n"); } } // did we find a frontend? if (tda1004x_address == -1) { return -ENODEV; } // enable access to the tuner tda1004x_enable_tuner_i2c(i2c, &tda_state); // check for a TD1344 first if (tuner_address == -1) { tuner_msg.addr = 0x61; tuner_msg.buf = td1344_init; tuner_msg.len = sizeof(td1344_init); if (i2c->xfer(i2c, &tuner_msg, 1) == 1) { dvb_delay(1); tuner_address = 0x61; tuner_type = TUNER_TYPE_TD1344; printk("tda1004x: Detected Philips TD1344 tuner.\n"); } } // OK, try a TD1316 on address 0x63 if (tuner_address == -1) { tuner_msg.addr = 0x63; tuner_msg.buf = td1316_init; tuner_msg.len = sizeof(td1316_init); if (i2c->xfer(i2c, &tuner_msg, 1) == 1) { dvb_delay(1); tuner_address = 0x63; tuner_type = TUNER_TYPE_TD1316; printk("tda1004x: Detected Philips TD1316 tuner.\n"); } } // OK, TD1316 again, on address 0x60 (TDA10046H) if (tuner_address == -1) { tuner_msg.addr = 0x60; tuner_msg.buf = td1316_init_tda10046h; tuner_msg.len = sizeof(td1316_init_tda10046h); if (i2c->xfer(i2c, &tuner_msg, 1) == 1) { dvb_delay(1); tuner_address = 0x60; tuner_type = TUNER_TYPE_TD1316; printk("tda1004x: Detected Philips TD1316 tuner.\n"); } } tda1004x_disable_tuner_i2c(i2c, &tda_state); // did we find a tuner? if (tuner_address == -1) { printk("tda1004x: Detected, but with unknown tuner.\n"); return -ENODEV; } // create state tda_state.tda1004x_address = tda1004x_address; tda_state.fe_type = fe_type; tda_state.tuner_address = tuner_address; tda_state.tuner_type = tuner_type; tda_state.initialised = 0; // upload firmware if ((status = tda1004x_fwupload(i2c, &tda_state)) != 0) return status; // register switch(tda_state.fe_type) { case FE_TYPE_TDA10045H: return dvb_register_frontend(tda1004x_ioctl, i2c, (void *)(*((u32*) &tda_state)), &tda10045h_info); case FE_TYPE_TDA10046H: return dvb_register_frontend(tda1004x_ioctl, i2c, (void *)(*((u32*) &tda_state)), &tda10046h_info); } // should not get here return -EINVAL;}staticvoid tda1004x_detach(struct dvb_i2c_bus *i2c, void *data){ dprintk("%s\n", __FUNCTION__); dvb_unregister_frontend(tda1004x_ioctl, i2c);}staticint __init init_tda1004x(void){ return dvb_register_i2c_device(THIS_MODULE, tda1004x_attach, tda1004x_detach);}staticvoid __exit exit_tda1004x(void){ dvb_unregister_i2c_device(tda1004x_attach);}module_init(init_tda1004x);module_exit(exit_tda1004x);MODULE_DESCRIPTION("Philips TDA10045H & TDA10046H DVB-T Frontend");MODULE_AUTHOR("Andrew de Quincey & Robert Schlabbach");MODULE_LICENSE("GPL");MODULE_PARM(tda1004x_debug, "i");MODULE_PARM_DESC(tda1004x_debug, "enable verbose debug messages");MODULE_PARM(tda1004x_firmware, "s");MODULE_PARM_DESC(tda1004x_firmware, "Where to find the firmware file");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -