📄 dib3000mc.c~
字号:
/* * Driver for DiBcom DiB3000MC/P-demodulator. * * Copyright (C) 2004-6 DiBcom (http://www.dibcom.fr/) * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) * * This code is partially based on the previous dib3000mc.c . * * 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, version 2. */#include <linux/kernel.h>#include <linux/i2c.h>//#include <linux/init.h>//#include <linux/delay.h>//#include <linux/string.h>//#include <linux/slab.h>#include "dvb_frontend.h"#include "dib3000mc.h"static int debug;module_param(debug, int, 0644);MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB3000MC/P:"); printk(args); } } while (0)struct dib3000mc_state { struct dvb_frontend demod; struct dib3000mc_config *cfg; u8 i2c_addr; struct i2c_adapter *i2c_adap; struct dibx000_i2c_master i2c_master; u32 timf; fe_bandwidth_t current_bandwidth; u16 dev_id;};unsigned int lg8934lock;void ComputeSectionAddress(unsigned char reg, unsigned char *result_reg) { unsigned int tmp; if(reg < 0xc0) tmp = 0xffffffff; else tmp = 0; *result_reg = (tmp & 0xfc) + 0x36;}EXPORT_SYMBOL(ComputeSectionAddress);static int dib3000mc_init(struct dvb_frontend *demod){ return 0;}static int dib3000mc_sleep(struct dvb_frontend *demod){ return 0;}static int dib3000mc_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep){ return 0;}static int dib3000mc_read_ber(struct dvb_frontend *fe, u32 *ber){ return 0;}static int dib3000mc_read_unc_blocks(struct dvb_frontend *fe, u32 *unc){ return 0;}static int dib3000mc_read_signal_strength(struct dvb_frontend *fe, u16 *strength){ 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;}int dib3000mc_pid_control(struct dvb_frontend *fe, int index, int pid,int onoff){ return 0;}EXPORT_SYMBOL(dib3000mc_pid_control);int dib3000mc_pid_parse(struct dvb_frontend *fe, int onoff){ return 0;}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[]){ return 0;}EXPORT_SYMBOL(dib3000mc_i2c_enumeration);static int dib3000mc_read_status(struct dvb_frontend *fe, fe_status_t *stat){ unsigned int lock; lock = lg8934lock; dprintk("lock status %d\n", lock); if(lg8934lock < 1) lock = 0xffffffff; else lock = 0; lock = ~lock; lock = lock & 0x1f; *stat = lock; return 0;}static int dib3000mc_write_byte(struct dib3000mc_state *state, unsigned char reg, unsigned char val){ struct i2c_msg msg; unsigned char wb[2]; unsigned char seg_reg; wb[0] = reg; wb[1] = val; ComputeSectionAddress(reg, &seg_reg); msg.addr = state->i2c_addr = (seg_reg>>1); msg.flags = 0; msg.len = 2; msg.buf = wb; return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;}int lgs8934_SetManualParameters(struct dib3000mc_state *state, unsigned char val) { int result; result = dib3000mc_write_byte(state, 0x7d, val|0x40); if(result != 0) return 1; result = dib3000mc_write_byte(state, 0xc0, val|0x40); if(result != 0) return 1; return 0;}EXPORT_SYMBOL(lgs8934_SetManualParameters);static int dib3000mc_read_byte(struct dib3000mc_state *state, u8 reg, unsigned char *i2c_read_result){ struct i2c_msg msg[2]; unsigned char wb[2]; unsigned char rb[2]; unsigned char seg_reg; wb[0] = reg; wb[1] = reg; ComputeSectionAddress(reg, &seg_reg); msg[0].addr = msg[1].addr = state->i2c_addr = (seg_reg >> 1); msg[0].buf = wb; msg[0].flags = 0; msg[0].len = 2; msg[1].flags = I2C_M_RD; msg[1].len = 2; msg[1].buf = rb; if (i2c_transfer(state->i2c_adap, msg, 2) !=2) { printk("i2c read error on %d\n",reg); return 1; } *i2c_read_result = rb[0]; return 0;}void IsLgs8934Lock(struct dib3000mc_state *state, unsigned char *result) { unsigned char i2c_read_result; i2c_read_result = 0; dib3000mc_read_byte(state, 0x4b, &i2c_read_result); i2c_read_result &= 0xc0; printk("LGS8934 Lock (%d)!!", (*result = (i2c_read_result == 0xc0 ? 1 : 0)));}EXPORT_SYMBOL(IsLgs8934Lock);void lgs8934_SetManualMode(struct dib3000mc_state *state) { unsigned char i2c_read_result; if(dib3000mc_read_byte(state, 0x7e, &i2c_read_result) != 0) { printk("SetMaualMode Failed\n"); return; } i2c_read_result &= 0xfe; if(dib3000mc_write_byte(state, 0x7e, i2c_read_result) != 0) { printk("SetMaualMode Failed\n"); return; } if(dib3000mc_read_byte(state, 0x7e, &i2c_read_result) != 0) { printk("SetMaualMode Failed\n"); return; } if(dib3000mc_read_byte(state, 0xc1, &i2c_read_result) != 0) { printk("SetMaualMode Failed\n"); return; } i2c_read_result &= 0xfe; if(dib3000mc_write_byte(state, 0xc1, i2c_read_result) != 0) { printk("SetMaualMode Failed\n"); }}EXPORT_SYMBOL(lgs8934_SetManualMode);void DumpConfigedReg(struct dib3000mc_state *state) { unsigned char i2c_read_result; if(dib3000mc_read_byte(state, 0x04, &i2c_read_result) != 0) { printk("DumpConfigedReg Failed\n"); return; } if(dib3000mc_read_byte(state, 0x7d, &i2c_read_result) != 0) { printk("DumpConfigedReg Failed\n"); return; } if(dib3000mc_read_byte(state, 0xc8, &i2c_read_result) != 0) { printk("DumpConfigedReg Failed\n"); return; } if(dib3000mc_read_byte(state, 0x37, &i2c_read_result) != 0) { printk("DumpConfigedReg Failed\n"); return; } if(dib3000mc_read_byte(state, 0xc2, &i2c_read_result) != 0) { printk("DumpConfigedReg Failed\n"); return; } if(dib3000mc_read_byte(state, 0x7c, &i2c_read_result) != 0) { printk("DumpConfigedReg Failed\n"); return; }}EXPORT_SYMBOL(DumpConfigedReg);void lgs8934_SetAutoMode(struct dib3000mc_state *state) { unsigned char i2c_read_result; printk("lgs8934_SetAutoMode! \n"); if(dib3000mc_read_byte(state, 0x4b, &i2c_read_result)) goto FAILED; if(dib3000mc_read_byte(state, 0xc2, &i2c_read_result)) goto FAILED; if(dib3000mc_write_byte(state, 0xc2, 0x0a)) goto FAILED; if(dib3000mc_write_byte(state, 0x7c, 0x07)) goto FAILED; if(dib3000mc_write_byte(state, 0x07, 0x9f)) goto FAILED; if(dib3000mc_write_byte(state, 0x09, 0x00)) goto FAILED; if(dib3000mc_write_byte(state, 0x0a, 0x00)) goto FAILED; if(dib3000mc_write_byte(state, 0x0b, 0x00)) goto FAILED; if(dib3000mc_write_byte(state, 0x0c, 0x00)) goto FAILED; if(dib3000mc_write_byte(state, 0xc5, 0x00)) goto FAILED; if(dib3000mc_write_byte(state, 0x03, 0x00)) goto FAILED; if(dib3000mc_write_byte(state, 0x7e, 0x01)) goto FAILED; if(dib3000mc_write_byte(state, 0xc1, 0x01)) goto FAILED; if(dib3000mc_write_byte(state, 0x2d, 0x00)) goto FAILED; dib3000mc_write_byte(state, 0x2e, 0x62);FAILED: printk("lgs8934_SetAutoMode Failed");}EXPORT_SYMBOL(lgs8934_SetAutoMode);int lgs8934_WaitForLock(struct dib3000mc_state *state, unsigned char reg, unsigned char mask, unsigned char target, int sleep_amount, unsigned char *error_code, int retries){ int tries; unsigned char i2c_read_result; if(retries <= 0) goto FAILED; /* please forgive me to write goto statements, or else the code won't look alike (though it's equivalent) */ tries = 0; do{ msleep(sleep_amount); if(dib3000mc_read_byte(state, reg, &i2c_read_result)) *error_code = i2c_read_result; if((i2c_read_result & mask) == target) { lg8934lock = 1; printk("LGS8934 Locked!!"); return 1; } tries++; } while(tries != retries);FAILED: return 0;}EXPORT_SYMBOL(lgs8934_WaitForLock);static int lgs8934_softreset(struct dib3000mc_state *state) { unsigned char i2c_read_result; if(dib3000mc_read_byte(state, 0x02, &i2c_read_result)) goto FAILED; i2c_read_result &= 0xfe; if(dib3000mc_write_byte(state, 0x02, i2c_read_result)) goto FAILED; msleep(100); i2c_read_result |= 0x01; if(dib3000mc_write_byte(state, 0x02, i2c_read_result)) goto FAILED; msleep(500); return 0;FAILED: return 1;}void CloseEcho(struct dib3000mc_state *state){ unsigned char i2c_read_result; if(dib3000mc_read_byte(state, 0x01, &i2c_read_result)) goto FAILED; if(dib3000mc_write_byte(state, 0x01, i2c_read_result & 0x7f)) goto FAILED; lgs8934_softreset(state);FAILED: printk("\t CloseEcho is failed!");}EXPORT_SYMBOL(CloseEcho);void OpenEcho(struct dib3000mc_state *state, unsigned char val) { val = (val >> 1) | 0x80; if(dib3000mc_write_byte(state, 0x01, val)) goto FAILED; lgs8934_softreset(state);FAILED: printk("\t OpenEcho is failed!");}EXPORT_SYMBOL(OpenEcho);void lgs8934_auto_detect(struct dib3000mc_state *state, unsigned int *unused) { unsigned char i2c_write_data; int tries; tries = 0; printk("lgs8934_auto_detect! \n"); do {/* if((tries & 1) == 0) i2c_write_data = 0; else if(((tries & 1)-1) == 0) i2c_write_data = 2; else i2c_write_data = 0;*//* oh well, no matter how i'm rewriting this, it's just not the same... seems my code is more optimized? */ if(!(tries & 1)) i2c_write_data = 0; else i2c_write_data = 2; if(dib3000mc_write_byte(state, 0x04, i2c_write_data)) goto RETRY; lgs8934_softreset(state); msleep(200); if(lgs8934_WaitForLock(state, 0x4b, 0xc0, 0xc0, 500, &i2c_write_data, 2) == 0) goto RETRY; if(dib3000mc_read_byte(state, 0xa2, &i2c_write_data)) goto RETRY; if(lgs8934_SetManualParameters(state, i2c_write_data)) goto RETRY; break;RETRY: tries++; } while (tries != 2);}EXPORT_SYMBOL(lgs8934_auto_detect);static int dib3000mc_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep){ struct dib3000mc_state *state; fe->ops.tuner_ops.set_params(fe, fep); state = fe->demodulator_priv; lg8934lock = 0; lgs8934_SetAutoMode(state); lgs8934_auto_detect(state, &lg8934lock); lgs8934_SetManualMode(state); lgs8934_softreset(state); DumpConfigedReg(state); printk("lgs8934_auto_detect, lock %d\n", lg8934lock); 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);}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; unsigned char i2c_read_data; 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)); i2c_read_data = 0xff; dib3000mc_read_byte(st, 0, &i2c_read_data); if(i2c_read_data == 0x0c) { printk("Found LGS8934 version=%x\n", 0x0c); } else { printk("Cannot find LGS8934\n"); } st->dev_id = dibx000_init_i2c_master(&st->i2c_master, DIB3000MC, st->i2c_adap, st->i2c_addr); return demod;}EXPORT_SYMBOL(dib3000mc_attach);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 struct dvb_frontend_ops dib3000mc_ops = { .info = { .name = "Legend Slilicon 8934", .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("JHA <jha.hsiao@gmail.com>");MODULE_DESCRIPTION("Driver for the Legend 8934 demodulator");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -