dvb_frontend.c
来自「trident tm5600的linux驱动」· C语言 代码 · 共 2,092 行 · 第 1/4 页
C
2,092 行
fe_status_t s; enum dvbfe_algo algo; struct dvb_frontend_parameters *params; dprintk("%s\n", __func__); fepriv->check_wrapped = 0; fepriv->quality = 0; fepriv->delay = 3*HZ; fepriv->status = 0; fepriv->wakeup = 0; fepriv->reinitialise = 0; dvb_frontend_init(fe); set_freezable(); while (1) { up(&fepriv->sem); /* is locked when we enter the thread... */restart:#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) timeout = wait_event_interruptible_timeout(fepriv->wait_queue, dvb_frontend_should_wakeup(fe) || kthread_should_stop(), fepriv->delay);#else timeout = wait_event_interruptible_timeout(fepriv->wait_queue, dvb_frontend_should_wakeup(fe) || kthread_should_stop() || freezing(current), fepriv->delay);#endif if (kthread_should_stop() || dvb_frontend_is_exiting(fe)) { /* got signal or quitting */ break; } if (try_to_freeze()) goto restart; if (down_interruptible(&fepriv->sem)) break; if (fepriv->reinitialise) { dvb_frontend_init(fe); if (fepriv->tone != -1) { fe->ops.set_tone(fe, fepriv->tone); } if (fepriv->voltage != -1) { fe->ops.set_voltage(fe, fepriv->voltage); } fepriv->reinitialise = 0; } /* do an iteration of the tuning loop */ if (fe->ops.get_frontend_algo) { algo = fe->ops.get_frontend_algo(fe); switch (algo) { case DVBFE_ALGO_HW: dprintk("%s: Frontend ALGO = DVBFE_ALGO_HW\n", __func__); params = NULL; /* have we been asked to RETUNE ? */ if (fepriv->state & FESTATE_RETUNE) { dprintk("%s: Retune requested, FESTATE_RETUNE\n", __func__); fepriv->state = FESTATE_TUNED; } if (fe->ops.tune) fe->ops.tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s); if (s != fepriv->status) { dprintk("%s: state changed, adding current state\n", __func__); dvb_frontend_add_event(fe, s); fepriv->status = s; } break; case DVBFE_ALGO_SW: dprintk("%s: Frontend ALGO = DVBFE_ALGO_SW\n", __func__); dvb_frontend_swzigzag(fe); break; case DVBFE_ALGO_CUSTOM: params = NULL; /* have we been asked to RETUNE ? */ dprintk("%s: Frontend ALGO = DVBFE_ALGO_CUSTOM, state=%d\n", __func__, fepriv->state); if (fepriv->state & FESTATE_RETUNE) { dprintk("%s: Retune requested, FESTAT_RETUNE\n", __func__); fepriv->state = FESTATE_TUNED; } /* Case where we are going to search for a carrier * User asked us to retune again for some reason, possibly * requesting a search with a new set of parameters */ if (fepriv->algo_status & DVBFE_ALGO_SEARCH_AGAIN) { if (fe->ops.search) { fepriv->algo_status = fe->ops.search(fe, &fepriv->parameters); /* We did do a search as was requested, the flags are * now unset as well and has the flags wrt to search. */ } else { fepriv->algo_status &= ~DVBFE_ALGO_SEARCH_AGAIN; } } /* Track the carrier if the search was successful */ if (fepriv->algo_status == DVBFE_ALGO_SEARCH_SUCCESS) { if (fe->ops.track) fe->ops.track(fe, &fepriv->parameters); } else { fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN; fepriv->delay = HZ / 2; } fe->ops.read_status(fe, &s); if (s != fepriv->status) { dvb_frontend_add_event(fe, s); /* update event list */ fepriv->status = s; if (!(s & FE_HAS_LOCK)) { fepriv->delay = HZ / 10; fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN; } else { fepriv->delay = 60 * HZ; } } break; default: dprintk("%s: UNDEFINED ALGO !\n", __func__); break; } } else { dvb_frontend_swzigzag(fe); } } if (dvb_powerdown_on_sleep) { if (fe->ops.set_voltage) fe->ops.set_voltage(fe, SEC_VOLTAGE_OFF); if (fe->ops.tuner_ops.sleep) { fe->ops.tuner_ops.sleep(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } if (fe->ops.sleep) fe->ops.sleep(fe); } fepriv->thread = NULL; mb(); dvb_frontend_wakeup(fe); return 0;}static void dvb_frontend_stop(struct dvb_frontend *fe){ struct dvb_frontend_private *fepriv = fe->frontend_priv; dprintk ("%s\n", __func__); fepriv->exit = 1; mb(); if (!fepriv->thread) return; kthread_stop(fepriv->thread); init_MUTEX (&fepriv->sem); fepriv->state = FESTATE_IDLE; /* paranoia check in case a signal arrived */ if (fepriv->thread) printk("dvb_frontend_stop: warning: thread %p won't exit\n", fepriv->thread);}s32 timeval_usec_diff(struct timeval lasttime, struct timeval curtime){ return ((curtime.tv_usec < lasttime.tv_usec) ? 1000000 - lasttime.tv_usec + curtime.tv_usec : curtime.tv_usec - lasttime.tv_usec);}EXPORT_SYMBOL(timeval_usec_diff);static inline void timeval_usec_add(struct timeval *curtime, u32 add_usec){ curtime->tv_usec += add_usec; if (curtime->tv_usec >= 1000000) { curtime->tv_usec -= 1000000; curtime->tv_sec++; }}/* * Sleep until gettimeofday() > waketime + add_usec * This needs to be as precise as possible, but as the delay is * usually between 2ms and 32ms, it is done using a scheduled msleep * followed by usleep (normally a busy-wait loop) for the remainder */void dvb_frontend_sleep_until(struct timeval *waketime, u32 add_usec){ struct timeval lasttime; s32 delta, newdelta; timeval_usec_add(waketime, add_usec); do_gettimeofday(&lasttime); delta = timeval_usec_diff(lasttime, *waketime); if (delta > 2500) { msleep((delta - 1500) / 1000); do_gettimeofday(&lasttime); newdelta = timeval_usec_diff(lasttime, *waketime); delta = (newdelta > delta) ? 0 : newdelta; } if (delta > 0) udelay(delta);}EXPORT_SYMBOL(dvb_frontend_sleep_until);static int dvb_frontend_start(struct dvb_frontend *fe){ int ret; struct dvb_frontend_private *fepriv = fe->frontend_priv; struct task_struct *fe_thread; dprintk ("%s\n", __func__); if (fepriv->thread) { if (!fepriv->exit) return 0; else dvb_frontend_stop (fe); } if (signal_pending(current)) return -EINTR; if (down_interruptible (&fepriv->sem)) return -EINTR; fepriv->state = FESTATE_IDLE; fepriv->exit = 0; fepriv->thread = NULL; mb(); fe_thread = kthread_run(dvb_frontend_thread, fe, "kdvb-ad-%i-fe-%i", fe->dvb->num,fe->id); if (IS_ERR(fe_thread)) { ret = PTR_ERR(fe_thread); printk("dvb_frontend_start: failed to start kthread (%d)\n", ret); up(&fepriv->sem); return ret; } fepriv->thread = fe_thread; return 0;}static void dvb_frontend_get_frequeny_limits(struct dvb_frontend *fe, u32 *freq_min, u32 *freq_max){ *freq_min = max(fe->ops.info.frequency_min, fe->ops.tuner_ops.info.frequency_min); if (fe->ops.info.frequency_max == 0) *freq_max = fe->ops.tuner_ops.info.frequency_max; else if (fe->ops.tuner_ops.info.frequency_max == 0) *freq_max = fe->ops.info.frequency_max; else *freq_max = min(fe->ops.info.frequency_max, fe->ops.tuner_ops.info.frequency_max); if (*freq_min == 0 || *freq_max == 0) printk(KERN_WARNING "DVB: adapter %i frontend %u frequency limits undefined - fix the driver\n", fe->dvb->num,fe->id);}static int dvb_frontend_check_parameters(struct dvb_frontend *fe, struct dvb_frontend_parameters *parms){ u32 freq_min; u32 freq_max; /* range check: frequency */ dvb_frontend_get_frequeny_limits(fe, &freq_min, &freq_max); if ((freq_min && parms->frequency < freq_min) || (freq_max && parms->frequency > freq_max)) { printk(KERN_WARNING "DVB: adapter %i frontend %i frequency %u out of range (%u..%u)\n", fe->dvb->num, fe->id, parms->frequency, freq_min, freq_max); return -EINVAL; } /* range check: symbol rate */ if (fe->ops.info.type == FE_QPSK) { if ((fe->ops.info.symbol_rate_min && parms->u.qpsk.symbol_rate < fe->ops.info.symbol_rate_min) || (fe->ops.info.symbol_rate_max && parms->u.qpsk.symbol_rate > fe->ops.info.symbol_rate_max)) { printk(KERN_WARNING "DVB: adapter %i frontend %i symbol rate %u out of range (%u..%u)\n", fe->dvb->num, fe->id, parms->u.qpsk.symbol_rate, fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max); return -EINVAL; } } else if (fe->ops.info.type == FE_QAM) { if ((fe->ops.info.symbol_rate_min && parms->u.qam.symbol_rate < fe->ops.info.symbol_rate_min) || (fe->ops.info.symbol_rate_max && parms->u.qam.symbol_rate > fe->ops.info.symbol_rate_max)) { printk(KERN_WARNING "DVB: adapter %i frontend %i symbol rate %u out of range (%u..%u)\n", fe->dvb->num, fe->id, parms->u.qam.symbol_rate, fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max); return -EINVAL; } } return 0;}struct dtv_cmds_h dtv_cmds[] = { [DTV_TUNE] = { .name = "DTV_TUNE", .cmd = DTV_TUNE, .set = 1, }, [DTV_CLEAR] = { .name = "DTV_CLEAR", .cmd = DTV_CLEAR, .set = 1, }, /* Set */ [DTV_FREQUENCY] = { .name = "DTV_FREQUENCY", .cmd = DTV_FREQUENCY, .set = 1, }, [DTV_BANDWIDTH_HZ] = { .name = "DTV_BANDWIDTH_HZ", .cmd = DTV_BANDWIDTH_HZ, .set = 1, }, [DTV_MODULATION] = { .name = "DTV_MODULATION", .cmd = DTV_MODULATION, .set = 1, }, [DTV_INVERSION] = { .name = "DTV_INVERSION", .cmd = DTV_INVERSION, .set = 1, }, [DTV_DISEQC_MASTER] = { .name = "DTV_DISEQC_MASTER", .cmd = DTV_DISEQC_MASTER, .set = 1, .buffer = 1, }, [DTV_SYMBOL_RATE] = { .name = "DTV_SYMBOL_RATE", .cmd = DTV_SYMBOL_RATE, .set = 1, }, [DTV_INNER_FEC] = { .name = "DTV_INNER_FEC", .cmd = DTV_INNER_FEC, .set = 1, }, [DTV_VOLTAGE] = { .name = "DTV_VOLTAGE", .cmd = DTV_VOLTAGE, .set = 1, }, [DTV_TONE] = { .name = "DTV_TONE", .cmd = DTV_TONE, .set = 1, }, [DTV_PILOT] = { .name = "DTV_PILOT", .cmd = DTV_PILOT, .set = 1, }, [DTV_ROLLOFF] = { .name = "DTV_ROLLOFF", .cmd = DTV_ROLLOFF, .set = 1, }, [DTV_DELIVERY_SYSTEM] = { .name = "DTV_DELIVERY_SYSTEM", .cmd = DTV_DELIVERY_SYSTEM, .set = 1, }, [DTV_HIERARCHY] = { .name = "DTV_HIERARCHY", .cmd = DTV_HIERARCHY, .set = 1, },#if 0 [DTV_ISDB_SEGMENT_IDX] = { .name = "DTV_ISDB_SEGMENT_IDX", .cmd = DTV_ISDB_SEGMENT_IDX, .set = 1, }, [DTV_ISDB_SEGMENT_WIDTH] = { .name = "DTV_ISDB_SEGMENT_WIDTH", .cmd = DTV_ISDB_SEGMENT_WIDTH, .set = 1, },#endif [DTV_CODE_RATE_HP] = { .name = "DTV_CODE_RATE_HP", .cmd = DTV_CODE_RATE_HP, .set = 1, }, [DTV_CODE_RATE_LP] = { .name = "DTV_CODE_RATE_LP", .cmd = DTV_CODE_RATE_LP, .set = 1, }, [DTV_GUARD_INTERVAL] = { .name = "DTV_GUARD_INTERVAL", .cmd = DTV_GUARD_INTERVAL, .set = 1, }, [DTV_TRANSMISSION_MODE] = { .name = "DTV_TRANSMISSION_MODE", .cmd = DTV_TRANSMISSION_MODE, .set = 1, }, /* Get */ [DTV_DISEQC_SLAVE_REPLY] = { .name = "DTV_DISEQC_SLAVE_REPLY", .cmd = DTV_DISEQC_SLAVE_REPLY, .set = 0, .buffer = 1, },#if 0 [DTV_ISDB_LAYERA_FEC] = { .name = "DTV_ISDB_LAYERA_FEC", .cmd = DTV_ISDB_LAYERA_FEC, .set = 0, }, [DTV_ISDB_LAYERA_MODULATION] = { .name = "DTV_ISDB_LAYERA_MODULATION", .cmd = DTV_ISDB_LAYERA_MODULATION, .set = 0, }, [DTV_ISDB_LAYERA_SEGMENT_WIDTH] = { .name = "DTV_ISDB_LAYERA_SEGMENT_WIDTH", .cmd = DTV_ISDB_LAYERA_SEGMENT_WIDTH, .set = 0, }, [DTV_ISDB_LAYERB_FEC] = { .name = "DTV_ISDB_LAYERB_FEC", .cmd = DTV_ISDB_LAYERB_FEC, .set = 0, }, [DTV_ISDB_LAYERB_MODULATION] = { .name = "DTV_ISDB_LAYERB_MODULATION", .cmd = DTV_ISDB_LAYERB_MODULATION, .set = 0, }, [DTV_ISDB_LAYERB_SEGMENT_WIDTH] = { .name = "DTV_ISDB_LAYERB_SEGMENT_WIDTH", .cmd = DTV_ISDB_LAYERB_SEGMENT_WIDTH, .set = 0, }, [DTV_ISDB_LAYERC_FEC] = { .name = "DTV_ISDB_LAYERC_FEC", .cmd = DTV_ISDB_LAYERC_FEC, .set = 0, }, [DTV_ISDB_LAYERC_MODULATION] = { .name = "DTV_ISDB_LAYERC_MODULATION", .cmd = DTV_ISDB_LAYERC_MODULATION, .set = 0, }, [DTV_ISDB_LAYERC_SEGMENT_WIDTH] = { .name = "DTV_ISDB_LAYERC_SEGMENT_WIDTH", .cmd = DTV_ISDB_LAYERC_SEGMENT_WIDTH, .set = 0, },#endif [DTV_API_VERSION] = { .name = "DTV_API_VERSION", .cmd = DTV_API_VERSION, .set = 0, }, [DTV_CODE_RATE_HP] = { .name = "DTV_CODE_RATE_HP", .cmd = DTV_CODE_RATE_HP, .set = 0, }, [DTV_CODE_RATE_LP] = { .name = "DTV_CODE_RATE_LP", .cmd = DTV_CODE_RATE_LP, .set = 0, }, [DTV_GUARD_INTERVAL] = { .name = "DTV_GUARD_INTERVAL", .cmd = DTV_GUARD_INTERVAL, .set = 0, }, [DTV_TRANSMISSION_MODE] = { .name = "DTV_TRANSMISSION_MODE", .cmd = DTV_TRANSMISSION_MODE, .set = 0, }, [DTV_HIERARCHY] = { .name = "DTV_HIERARCHY", .cmd = DTV_HIERARCHY, .set = 0, },};void dtv_property_dump(struct dtv_property *tvp){ int i; if (tvp->cmd <= 0 || tvp->cmd > DTV_MAX_COMMAND) { printk(KERN_WARNING "%s: tvp.cmd = 0x%08x undefined\n", __func__, tvp->cmd); return; } dprintk("%s() tvp.cmd = 0x%08x (%s)\n" ,__func__ ,tvp->cmd ,dtv_cmds[ tvp->cmd ].name); if(dtv_cmds[ tvp->cmd ].buffer) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?