Path: blob/master/drivers/media/dvb/dvb-core/dvb_frontend.c
15112 views
/*1* dvb_frontend.c: DVB frontend tuning interface/thread2*3*4* Copyright (C) 1999-2001 Ralph Metzler5* Marcus Metzler6* Holger Waechtler7* for convergence integrated media GmbH8*9* Copyright (C) 2004 Andrew de Quincey (tuning thread cleanup)10*11* This program is free software; you can redistribute it and/or12* modify it under the terms of the GNU General Public License13* as published by the Free Software Foundation; either version 214* of the License, or (at your option) any later version.15*16* This program is distributed in the hope that it will be useful,17* but WITHOUT ANY WARRANTY; without even the implied warranty of18* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the19* GNU General Public License for more details.20*21* You should have received a copy of the GNU General Public License22* along with this program; if not, write to the Free Software23* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.24* Or, point your browser to http://www.gnu.org/copyleft/gpl.html25*/2627#include <linux/string.h>28#include <linux/kernel.h>29#include <linux/sched.h>30#include <linux/wait.h>31#include <linux/slab.h>32#include <linux/poll.h>33#include <linux/semaphore.h>34#include <linux/module.h>35#include <linux/list.h>36#include <linux/freezer.h>37#include <linux/jiffies.h>38#include <linux/kthread.h>39#include <asm/processor.h>4041#include "dvb_frontend.h"42#include "dvbdev.h"43#include <linux/dvb/version.h>4445static int dvb_frontend_debug;46static int dvb_shutdown_timeout;47static int dvb_force_auto_inversion;48static int dvb_override_tune_delay;49static int dvb_powerdown_on_sleep = 1;50static int dvb_mfe_wait_time = 5;5152module_param_named(frontend_debug, dvb_frontend_debug, int, 0644);53MODULE_PARM_DESC(frontend_debug, "Turn on/off frontend core debugging (default:off).");54module_param(dvb_shutdown_timeout, int, 0644);55MODULE_PARM_DESC(dvb_shutdown_timeout, "wait <shutdown_timeout> seconds after close() before suspending hardware");56module_param(dvb_force_auto_inversion, int, 0644);57MODULE_PARM_DESC(dvb_force_auto_inversion, "0: normal (default), 1: INVERSION_AUTO forced always");58module_param(dvb_override_tune_delay, int, 0644);59MODULE_PARM_DESC(dvb_override_tune_delay, "0: normal (default), >0 => delay in milliseconds to wait for lock after a tune attempt");60module_param(dvb_powerdown_on_sleep, int, 0644);61MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB voltage off on sleep (default)");62module_param(dvb_mfe_wait_time, int, 0644);63MODULE_PARM_DESC(dvb_mfe_wait_time, "Wait up to <mfe_wait_time> seconds on open() for multi-frontend to become available (default:5 seconds)");6465#define dprintk if (dvb_frontend_debug) printk6667#define FESTATE_IDLE 168#define FESTATE_RETUNE 269#define FESTATE_TUNING_FAST 470#define FESTATE_TUNING_SLOW 871#define FESTATE_TUNED 1672#define FESTATE_ZIGZAG_FAST 3273#define FESTATE_ZIGZAG_SLOW 6474#define FESTATE_DISEQC 12875#define FESTATE_ERROR 25676#define FESTATE_WAITFORLOCK (FESTATE_TUNING_FAST | FESTATE_TUNING_SLOW | FESTATE_ZIGZAG_FAST | FESTATE_ZIGZAG_SLOW | FESTATE_DISEQC)77#define FESTATE_SEARCHING_FAST (FESTATE_TUNING_FAST | FESTATE_ZIGZAG_FAST)78#define FESTATE_SEARCHING_SLOW (FESTATE_TUNING_SLOW | FESTATE_ZIGZAG_SLOW)79#define FESTATE_LOSTLOCK (FESTATE_ZIGZAG_FAST | FESTATE_ZIGZAG_SLOW)8081#define FE_ALGO_HW 182/*83* FESTATE_IDLE. No tuning parameters have been supplied and the loop is idling.84* FESTATE_RETUNE. Parameters have been supplied, but we have not yet performed the first tune.85* FESTATE_TUNING_FAST. Tuning parameters have been supplied and fast zigzag scan is in progress.86* FESTATE_TUNING_SLOW. Tuning parameters have been supplied. Fast zigzag failed, so we're trying again, but slower.87* FESTATE_TUNED. The frontend has successfully locked on.88* FESTATE_ZIGZAG_FAST. The lock has been lost, and a fast zigzag has been initiated to try and regain it.89* FESTATE_ZIGZAG_SLOW. The lock has been lost. Fast zigzag has been failed, so we're trying again, but slower.90* FESTATE_DISEQC. A DISEQC command has just been issued.91* FESTATE_WAITFORLOCK. When we're waiting for a lock.92* FESTATE_SEARCHING_FAST. When we're searching for a signal using a fast zigzag scan.93* FESTATE_SEARCHING_SLOW. When we're searching for a signal using a slow zigzag scan.94* FESTATE_LOSTLOCK. When the lock has been lost, and we're searching it again.95*/9697#define DVB_FE_NO_EXIT 098#define DVB_FE_NORMAL_EXIT 199#define DVB_FE_DEVICE_REMOVED 2100101static DEFINE_MUTEX(frontend_mutex);102103struct dvb_frontend_private {104105/* thread/frontend values */106struct dvb_device *dvbdev;107struct dvb_frontend_parameters parameters_in;108struct dvb_frontend_parameters parameters_out;109struct dvb_fe_events events;110struct semaphore sem;111struct list_head list_head;112wait_queue_head_t wait_queue;113struct task_struct *thread;114unsigned long release_jiffies;115unsigned int exit;116unsigned int wakeup;117fe_status_t status;118unsigned long tune_mode_flags;119unsigned int delay;120unsigned int reinitialise;121int tone;122int voltage;123124/* swzigzag values */125unsigned int state;126unsigned int bending;127int lnb_drift;128unsigned int inversion;129unsigned int auto_step;130unsigned int auto_sub_step;131unsigned int started_auto_step;132unsigned int min_delay;133unsigned int max_drift;134unsigned int step_size;135int quality;136unsigned int check_wrapped;137enum dvbfe_search algo_status;138};139140static void dvb_frontend_wakeup(struct dvb_frontend *fe);141142static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status)143{144struct dvb_frontend_private *fepriv = fe->frontend_priv;145struct dvb_fe_events *events = &fepriv->events;146struct dvb_frontend_event *e;147int wp;148149dprintk ("%s\n", __func__);150151if (mutex_lock_interruptible (&events->mtx))152return;153154wp = (events->eventw + 1) % MAX_EVENT;155156if (wp == events->eventr) {157events->overflow = 1;158events->eventr = (events->eventr + 1) % MAX_EVENT;159}160161e = &events->events[events->eventw];162163if (status & FE_HAS_LOCK)164if (fe->ops.get_frontend)165fe->ops.get_frontend(fe, &fepriv->parameters_out);166167e->parameters = fepriv->parameters_out;168169events->eventw = wp;170171mutex_unlock(&events->mtx);172173e->status = status;174175wake_up_interruptible (&events->wait_queue);176}177178static int dvb_frontend_get_event(struct dvb_frontend *fe,179struct dvb_frontend_event *event, int flags)180{181struct dvb_frontend_private *fepriv = fe->frontend_priv;182struct dvb_fe_events *events = &fepriv->events;183184dprintk ("%s\n", __func__);185186if (events->overflow) {187events->overflow = 0;188return -EOVERFLOW;189}190191if (events->eventw == events->eventr) {192int ret;193194if (flags & O_NONBLOCK)195return -EWOULDBLOCK;196197up(&fepriv->sem);198199ret = wait_event_interruptible (events->wait_queue,200events->eventw != events->eventr);201202if (down_interruptible (&fepriv->sem))203return -ERESTARTSYS;204205if (ret < 0)206return ret;207}208209if (mutex_lock_interruptible (&events->mtx))210return -ERESTARTSYS;211212memcpy (event, &events->events[events->eventr],213sizeof(struct dvb_frontend_event));214215events->eventr = (events->eventr + 1) % MAX_EVENT;216217mutex_unlock(&events->mtx);218219return 0;220}221222static void dvb_frontend_init(struct dvb_frontend *fe)223{224dprintk ("DVB: initialising adapter %i frontend %i (%s)...\n",225fe->dvb->num,226fe->id,227fe->ops.info.name);228229if (fe->ops.init)230fe->ops.init(fe);231if (fe->ops.tuner_ops.init) {232if (fe->ops.i2c_gate_ctrl)233fe->ops.i2c_gate_ctrl(fe, 1);234fe->ops.tuner_ops.init(fe);235if (fe->ops.i2c_gate_ctrl)236fe->ops.i2c_gate_ctrl(fe, 0);237}238}239240void dvb_frontend_reinitialise(struct dvb_frontend *fe)241{242struct dvb_frontend_private *fepriv = fe->frontend_priv;243244fepriv->reinitialise = 1;245dvb_frontend_wakeup(fe);246}247EXPORT_SYMBOL(dvb_frontend_reinitialise);248249static void dvb_frontend_swzigzag_update_delay(struct dvb_frontend_private *fepriv, int locked)250{251int q2;252253dprintk ("%s\n", __func__);254255if (locked)256(fepriv->quality) = (fepriv->quality * 220 + 36*256) / 256;257else258(fepriv->quality) = (fepriv->quality * 220 + 0) / 256;259260q2 = fepriv->quality - 128;261q2 *= q2;262263fepriv->delay = fepriv->min_delay + q2 * HZ / (128*128);264}265266/**267* Performs automatic twiddling of frontend parameters.268*269* @param fe The frontend concerned.270* @param check_wrapped Checks if an iteration has completed. DO NOT SET ON THE FIRST ATTEMPT271* @returns Number of complete iterations that have been performed.272*/273static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wrapped)274{275int autoinversion;276int ready = 0;277int fe_set_err = 0;278struct dvb_frontend_private *fepriv = fe->frontend_priv;279int original_inversion = fepriv->parameters_in.inversion;280u32 original_frequency = fepriv->parameters_in.frequency;281282/* are we using autoinversion? */283autoinversion = ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) &&284(fepriv->parameters_in.inversion == INVERSION_AUTO));285286/* setup parameters correctly */287while(!ready) {288/* calculate the lnb_drift */289fepriv->lnb_drift = fepriv->auto_step * fepriv->step_size;290291/* wrap the auto_step if we've exceeded the maximum drift */292if (fepriv->lnb_drift > fepriv->max_drift) {293fepriv->auto_step = 0;294fepriv->auto_sub_step = 0;295fepriv->lnb_drift = 0;296}297298/* perform inversion and +/- zigzag */299switch(fepriv->auto_sub_step) {300case 0:301/* try with the current inversion and current drift setting */302ready = 1;303break;304305case 1:306if (!autoinversion) break;307308fepriv->inversion = (fepriv->inversion == INVERSION_OFF) ? INVERSION_ON : INVERSION_OFF;309ready = 1;310break;311312case 2:313if (fepriv->lnb_drift == 0) break;314315fepriv->lnb_drift = -fepriv->lnb_drift;316ready = 1;317break;318319case 3:320if (fepriv->lnb_drift == 0) break;321if (!autoinversion) break;322323fepriv->inversion = (fepriv->inversion == INVERSION_OFF) ? INVERSION_ON : INVERSION_OFF;324fepriv->lnb_drift = -fepriv->lnb_drift;325ready = 1;326break;327328default:329fepriv->auto_step++;330fepriv->auto_sub_step = -1; /* it'll be incremented to 0 in a moment */331break;332}333334if (!ready) fepriv->auto_sub_step++;335}336337/* if this attempt would hit where we started, indicate a complete338* iteration has occurred */339if ((fepriv->auto_step == fepriv->started_auto_step) &&340(fepriv->auto_sub_step == 0) && check_wrapped) {341return 1;342}343344dprintk("%s: drift:%i inversion:%i auto_step:%i "345"auto_sub_step:%i started_auto_step:%i\n",346__func__, fepriv->lnb_drift, fepriv->inversion,347fepriv->auto_step, fepriv->auto_sub_step, fepriv->started_auto_step);348349/* set the frontend itself */350fepriv->parameters_in.frequency += fepriv->lnb_drift;351if (autoinversion)352fepriv->parameters_in.inversion = fepriv->inversion;353if (fe->ops.set_frontend)354fe_set_err = fe->ops.set_frontend(fe, &fepriv->parameters_in);355fepriv->parameters_out = fepriv->parameters_in;356if (fe_set_err < 0) {357fepriv->state = FESTATE_ERROR;358return fe_set_err;359}360361fepriv->parameters_in.frequency = original_frequency;362fepriv->parameters_in.inversion = original_inversion;363364fepriv->auto_sub_step++;365return 0;366}367368static void dvb_frontend_swzigzag(struct dvb_frontend *fe)369{370fe_status_t s = 0;371int retval = 0;372struct dvb_frontend_private *fepriv = fe->frontend_priv;373374/* if we've got no parameters, just keep idling */375if (fepriv->state & FESTATE_IDLE) {376fepriv->delay = 3*HZ;377fepriv->quality = 0;378return;379}380381/* in SCAN mode, we just set the frontend when asked and leave it alone */382if (fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT) {383if (fepriv->state & FESTATE_RETUNE) {384if (fe->ops.set_frontend)385retval = fe->ops.set_frontend(fe,386&fepriv->parameters_in);387fepriv->parameters_out = fepriv->parameters_in;388if (retval < 0)389fepriv->state = FESTATE_ERROR;390else391fepriv->state = FESTATE_TUNED;392}393fepriv->delay = 3*HZ;394fepriv->quality = 0;395return;396}397398/* get the frontend status */399if (fepriv->state & FESTATE_RETUNE) {400s = 0;401} else {402if (fe->ops.read_status)403fe->ops.read_status(fe, &s);404if (s != fepriv->status) {405dvb_frontend_add_event(fe, s);406fepriv->status = s;407}408}409410/* if we're not tuned, and we have a lock, move to the TUNED state */411if ((fepriv->state & FESTATE_WAITFORLOCK) && (s & FE_HAS_LOCK)) {412dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);413fepriv->state = FESTATE_TUNED;414415/* if we're tuned, then we have determined the correct inversion */416if ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) &&417(fepriv->parameters_in.inversion == INVERSION_AUTO)) {418fepriv->parameters_in.inversion = fepriv->inversion;419}420return;421}422423/* if we are tuned already, check we're still locked */424if (fepriv->state & FESTATE_TUNED) {425dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);426427/* we're tuned, and the lock is still good... */428if (s & FE_HAS_LOCK) {429return;430} else { /* if we _WERE_ tuned, but now don't have a lock */431fepriv->state = FESTATE_ZIGZAG_FAST;432fepriv->started_auto_step = fepriv->auto_step;433fepriv->check_wrapped = 0;434}435}436437/* don't actually do anything if we're in the LOSTLOCK state,438* the frontend is set to FE_CAN_RECOVER, and the max_drift is 0 */439if ((fepriv->state & FESTATE_LOSTLOCK) &&440(fe->ops.info.caps & FE_CAN_RECOVER) && (fepriv->max_drift == 0)) {441dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);442return;443}444445/* don't do anything if we're in the DISEQC state, since this446* might be someone with a motorized dish controlled by DISEQC.447* If its actually a re-tune, there will be a SET_FRONTEND soon enough. */448if (fepriv->state & FESTATE_DISEQC) {449dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);450return;451}452453/* if we're in the RETUNE state, set everything up for a brand454* new scan, keeping the current inversion setting, as the next455* tune is _very_ likely to require the same */456if (fepriv->state & FESTATE_RETUNE) {457fepriv->lnb_drift = 0;458fepriv->auto_step = 0;459fepriv->auto_sub_step = 0;460fepriv->started_auto_step = 0;461fepriv->check_wrapped = 0;462}463464/* fast zigzag. */465if ((fepriv->state & FESTATE_SEARCHING_FAST) || (fepriv->state & FESTATE_RETUNE)) {466fepriv->delay = fepriv->min_delay;467468/* perform a tune */469retval = dvb_frontend_swzigzag_autotune(fe,470fepriv->check_wrapped);471if (retval < 0) {472return;473} else if (retval) {474/* OK, if we've run out of trials at the fast speed.475* Drop back to slow for the _next_ attempt */476fepriv->state = FESTATE_SEARCHING_SLOW;477fepriv->started_auto_step = fepriv->auto_step;478return;479}480fepriv->check_wrapped = 1;481482/* if we've just retuned, enter the ZIGZAG_FAST state.483* This ensures we cannot return from an484* FE_SET_FRONTEND ioctl before the first frontend tune485* occurs */486if (fepriv->state & FESTATE_RETUNE) {487fepriv->state = FESTATE_TUNING_FAST;488}489}490491/* slow zigzag */492if (fepriv->state & FESTATE_SEARCHING_SLOW) {493dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);494495/* Note: don't bother checking for wrapping; we stay in this496* state until we get a lock */497dvb_frontend_swzigzag_autotune(fe, 0);498}499}500501static int dvb_frontend_is_exiting(struct dvb_frontend *fe)502{503struct dvb_frontend_private *fepriv = fe->frontend_priv;504505if (fepriv->exit != DVB_FE_NO_EXIT)506return 1;507508if (fepriv->dvbdev->writers == 1)509if (time_after(jiffies, fepriv->release_jiffies +510dvb_shutdown_timeout * HZ))511return 1;512513return 0;514}515516static int dvb_frontend_should_wakeup(struct dvb_frontend *fe)517{518struct dvb_frontend_private *fepriv = fe->frontend_priv;519520if (fepriv->wakeup) {521fepriv->wakeup = 0;522return 1;523}524return dvb_frontend_is_exiting(fe);525}526527static void dvb_frontend_wakeup(struct dvb_frontend *fe)528{529struct dvb_frontend_private *fepriv = fe->frontend_priv;530531fepriv->wakeup = 1;532wake_up_interruptible(&fepriv->wait_queue);533}534535static int dvb_frontend_thread(void *data)536{537struct dvb_frontend *fe = data;538struct dvb_frontend_private *fepriv = fe->frontend_priv;539unsigned long timeout;540fe_status_t s;541enum dvbfe_algo algo;542543struct dvb_frontend_parameters *params;544545dprintk("%s\n", __func__);546547fepriv->check_wrapped = 0;548fepriv->quality = 0;549fepriv->delay = 3*HZ;550fepriv->status = 0;551fepriv->wakeup = 0;552fepriv->reinitialise = 0;553554dvb_frontend_init(fe);555556set_freezable();557while (1) {558up(&fepriv->sem); /* is locked when we enter the thread... */559restart:560timeout = wait_event_interruptible_timeout(fepriv->wait_queue,561dvb_frontend_should_wakeup(fe) || kthread_should_stop()562|| freezing(current),563fepriv->delay);564565if (kthread_should_stop() || dvb_frontend_is_exiting(fe)) {566/* got signal or quitting */567fepriv->exit = DVB_FE_NORMAL_EXIT;568break;569}570571if (try_to_freeze())572goto restart;573574if (down_interruptible(&fepriv->sem))575break;576577if (fepriv->reinitialise) {578dvb_frontend_init(fe);579if (fepriv->tone != -1) {580fe->ops.set_tone(fe, fepriv->tone);581}582if (fepriv->voltage != -1) {583fe->ops.set_voltage(fe, fepriv->voltage);584}585fepriv->reinitialise = 0;586}587588/* do an iteration of the tuning loop */589if (fe->ops.get_frontend_algo) {590algo = fe->ops.get_frontend_algo(fe);591switch (algo) {592case DVBFE_ALGO_HW:593dprintk("%s: Frontend ALGO = DVBFE_ALGO_HW\n", __func__);594params = NULL; /* have we been asked to RETUNE ? */595596if (fepriv->state & FESTATE_RETUNE) {597dprintk("%s: Retune requested, FESTATE_RETUNE\n", __func__);598params = &fepriv->parameters_in;599fepriv->state = FESTATE_TUNED;600}601602if (fe->ops.tune)603fe->ops.tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s);604if (params)605fepriv->parameters_out = *params;606607if (s != fepriv->status && !(fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT)) {608dprintk("%s: state changed, adding current state\n", __func__);609dvb_frontend_add_event(fe, s);610fepriv->status = s;611}612break;613case DVBFE_ALGO_SW:614dprintk("%s: Frontend ALGO = DVBFE_ALGO_SW\n", __func__);615dvb_frontend_swzigzag(fe);616break;617case DVBFE_ALGO_CUSTOM:618dprintk("%s: Frontend ALGO = DVBFE_ALGO_CUSTOM, state=%d\n", __func__, fepriv->state);619if (fepriv->state & FESTATE_RETUNE) {620dprintk("%s: Retune requested, FESTAT_RETUNE\n", __func__);621fepriv->state = FESTATE_TUNED;622}623/* Case where we are going to search for a carrier624* User asked us to retune again for some reason, possibly625* requesting a search with a new set of parameters626*/627if (fepriv->algo_status & DVBFE_ALGO_SEARCH_AGAIN) {628if (fe->ops.search) {629fepriv->algo_status = fe->ops.search(fe, &fepriv->parameters_in);630/* We did do a search as was requested, the flags are631* now unset as well and has the flags wrt to search.632*/633} else {634fepriv->algo_status &= ~DVBFE_ALGO_SEARCH_AGAIN;635}636}637/* Track the carrier if the search was successful */638if (fepriv->algo_status == DVBFE_ALGO_SEARCH_SUCCESS) {639if (fe->ops.track)640fe->ops.track(fe, &fepriv->parameters_in);641} else {642fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;643fepriv->delay = HZ / 2;644}645fepriv->parameters_out = fepriv->parameters_in;646fe->ops.read_status(fe, &s);647if (s != fepriv->status) {648dvb_frontend_add_event(fe, s); /* update event list */649fepriv->status = s;650if (!(s & FE_HAS_LOCK)) {651fepriv->delay = HZ / 10;652fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;653} else {654fepriv->delay = 60 * HZ;655}656}657break;658default:659dprintk("%s: UNDEFINED ALGO !\n", __func__);660break;661}662} else {663dvb_frontend_swzigzag(fe);664}665}666667if (dvb_powerdown_on_sleep) {668if (fe->ops.set_voltage)669fe->ops.set_voltage(fe, SEC_VOLTAGE_OFF);670if (fe->ops.tuner_ops.sleep) {671if (fe->ops.i2c_gate_ctrl)672fe->ops.i2c_gate_ctrl(fe, 1);673fe->ops.tuner_ops.sleep(fe);674if (fe->ops.i2c_gate_ctrl)675fe->ops.i2c_gate_ctrl(fe, 0);676}677if (fe->ops.sleep)678fe->ops.sleep(fe);679}680681fepriv->thread = NULL;682if (kthread_should_stop())683fepriv->exit = DVB_FE_DEVICE_REMOVED;684else685fepriv->exit = DVB_FE_NO_EXIT;686mb();687688dvb_frontend_wakeup(fe);689return 0;690}691692static void dvb_frontend_stop(struct dvb_frontend *fe)693{694struct dvb_frontend_private *fepriv = fe->frontend_priv;695696dprintk ("%s\n", __func__);697698fepriv->exit = DVB_FE_NORMAL_EXIT;699mb();700701if (!fepriv->thread)702return;703704kthread_stop(fepriv->thread);705706sema_init(&fepriv->sem, 1);707fepriv->state = FESTATE_IDLE;708709/* paranoia check in case a signal arrived */710if (fepriv->thread)711printk("dvb_frontend_stop: warning: thread %p won't exit\n",712fepriv->thread);713}714715s32 timeval_usec_diff(struct timeval lasttime, struct timeval curtime)716{717return ((curtime.tv_usec < lasttime.tv_usec) ?7181000000 - lasttime.tv_usec + curtime.tv_usec :719curtime.tv_usec - lasttime.tv_usec);720}721EXPORT_SYMBOL(timeval_usec_diff);722723static inline void timeval_usec_add(struct timeval *curtime, u32 add_usec)724{725curtime->tv_usec += add_usec;726if (curtime->tv_usec >= 1000000) {727curtime->tv_usec -= 1000000;728curtime->tv_sec++;729}730}731732/*733* Sleep until gettimeofday() > waketime + add_usec734* This needs to be as precise as possible, but as the delay is735* usually between 2ms and 32ms, it is done using a scheduled msleep736* followed by usleep (normally a busy-wait loop) for the remainder737*/738void dvb_frontend_sleep_until(struct timeval *waketime, u32 add_usec)739{740struct timeval lasttime;741s32 delta, newdelta;742743timeval_usec_add(waketime, add_usec);744745do_gettimeofday(&lasttime);746delta = timeval_usec_diff(lasttime, *waketime);747if (delta > 2500) {748msleep((delta - 1500) / 1000);749do_gettimeofday(&lasttime);750newdelta = timeval_usec_diff(lasttime, *waketime);751delta = (newdelta > delta) ? 0 : newdelta;752}753if (delta > 0)754udelay(delta);755}756EXPORT_SYMBOL(dvb_frontend_sleep_until);757758static int dvb_frontend_start(struct dvb_frontend *fe)759{760int ret;761struct dvb_frontend_private *fepriv = fe->frontend_priv;762struct task_struct *fe_thread;763764dprintk ("%s\n", __func__);765766if (fepriv->thread) {767if (fepriv->exit == DVB_FE_NO_EXIT)768return 0;769else770dvb_frontend_stop (fe);771}772773if (signal_pending(current))774return -EINTR;775if (down_interruptible (&fepriv->sem))776return -EINTR;777778fepriv->state = FESTATE_IDLE;779fepriv->exit = DVB_FE_NO_EXIT;780fepriv->thread = NULL;781mb();782783fe_thread = kthread_run(dvb_frontend_thread, fe,784"kdvb-ad-%i-fe-%i", fe->dvb->num,fe->id);785if (IS_ERR(fe_thread)) {786ret = PTR_ERR(fe_thread);787printk("dvb_frontend_start: failed to start kthread (%d)\n", ret);788up(&fepriv->sem);789return ret;790}791fepriv->thread = fe_thread;792return 0;793}794795static void dvb_frontend_get_frequency_limits(struct dvb_frontend *fe,796u32 *freq_min, u32 *freq_max)797{798*freq_min = max(fe->ops.info.frequency_min, fe->ops.tuner_ops.info.frequency_min);799800if (fe->ops.info.frequency_max == 0)801*freq_max = fe->ops.tuner_ops.info.frequency_max;802else if (fe->ops.tuner_ops.info.frequency_max == 0)803*freq_max = fe->ops.info.frequency_max;804else805*freq_max = min(fe->ops.info.frequency_max, fe->ops.tuner_ops.info.frequency_max);806807if (*freq_min == 0 || *freq_max == 0)808printk(KERN_WARNING "DVB: adapter %i frontend %u frequency limits undefined - fix the driver\n",809fe->dvb->num,fe->id);810}811812static int dvb_frontend_check_parameters(struct dvb_frontend *fe,813struct dvb_frontend_parameters *parms)814{815u32 freq_min;816u32 freq_max;817818/* range check: frequency */819dvb_frontend_get_frequency_limits(fe, &freq_min, &freq_max);820if ((freq_min && parms->frequency < freq_min) ||821(freq_max && parms->frequency > freq_max)) {822printk(KERN_WARNING "DVB: adapter %i frontend %i frequency %u out of range (%u..%u)\n",823fe->dvb->num, fe->id, parms->frequency, freq_min, freq_max);824return -EINVAL;825}826827/* range check: symbol rate */828if (fe->ops.info.type == FE_QPSK) {829if ((fe->ops.info.symbol_rate_min &&830parms->u.qpsk.symbol_rate < fe->ops.info.symbol_rate_min) ||831(fe->ops.info.symbol_rate_max &&832parms->u.qpsk.symbol_rate > fe->ops.info.symbol_rate_max)) {833printk(KERN_WARNING "DVB: adapter %i frontend %i symbol rate %u out of range (%u..%u)\n",834fe->dvb->num, fe->id, parms->u.qpsk.symbol_rate,835fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max);836return -EINVAL;837}838839} else if (fe->ops.info.type == FE_QAM) {840if ((fe->ops.info.symbol_rate_min &&841parms->u.qam.symbol_rate < fe->ops.info.symbol_rate_min) ||842(fe->ops.info.symbol_rate_max &&843parms->u.qam.symbol_rate > fe->ops.info.symbol_rate_max)) {844printk(KERN_WARNING "DVB: adapter %i frontend %i symbol rate %u out of range (%u..%u)\n",845fe->dvb->num, fe->id, parms->u.qam.symbol_rate,846fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max);847return -EINVAL;848}849}850851/* check for supported modulation */852if (fe->ops.info.type == FE_QAM &&853(parms->u.qam.modulation > QAM_AUTO ||854!((1 << (parms->u.qam.modulation + 10)) & fe->ops.info.caps))) {855printk(KERN_WARNING "DVB: adapter %i frontend %i modulation %u not supported\n",856fe->dvb->num, fe->id, parms->u.qam.modulation);857return -EINVAL;858}859860return 0;861}862863static int dvb_frontend_clear_cache(struct dvb_frontend *fe)864{865struct dtv_frontend_properties *c = &fe->dtv_property_cache;866int i;867868memset(c, 0, sizeof(struct dtv_frontend_properties));869870c->state = DTV_CLEAR;871c->delivery_system = SYS_UNDEFINED;872c->inversion = INVERSION_AUTO;873c->fec_inner = FEC_AUTO;874c->transmission_mode = TRANSMISSION_MODE_AUTO;875c->bandwidth_hz = BANDWIDTH_AUTO;876c->guard_interval = GUARD_INTERVAL_AUTO;877c->hierarchy = HIERARCHY_AUTO;878c->symbol_rate = QAM_AUTO;879c->code_rate_HP = FEC_AUTO;880c->code_rate_LP = FEC_AUTO;881882c->isdbt_partial_reception = -1;883c->isdbt_sb_mode = -1;884c->isdbt_sb_subchannel = -1;885c->isdbt_sb_segment_idx = -1;886c->isdbt_sb_segment_count = -1;887c->isdbt_layer_enabled = 0x7;888for (i = 0; i < 3; i++) {889c->layer[i].fec = FEC_AUTO;890c->layer[i].modulation = QAM_AUTO;891c->layer[i].interleaving = -1;892c->layer[i].segment_count = -1;893}894895return 0;896}897898#define _DTV_CMD(n, s, b) \899[n] = { \900.name = #n, \901.cmd = n, \902.set = s,\903.buffer = b \904}905906static struct dtv_cmds_h dtv_cmds[] = {907_DTV_CMD(DTV_TUNE, 1, 0),908_DTV_CMD(DTV_CLEAR, 1, 0),909910/* Set */911_DTV_CMD(DTV_FREQUENCY, 1, 0),912_DTV_CMD(DTV_BANDWIDTH_HZ, 1, 0),913_DTV_CMD(DTV_MODULATION, 1, 0),914_DTV_CMD(DTV_INVERSION, 1, 0),915_DTV_CMD(DTV_DISEQC_MASTER, 1, 1),916_DTV_CMD(DTV_SYMBOL_RATE, 1, 0),917_DTV_CMD(DTV_INNER_FEC, 1, 0),918_DTV_CMD(DTV_VOLTAGE, 1, 0),919_DTV_CMD(DTV_TONE, 1, 0),920_DTV_CMD(DTV_PILOT, 1, 0),921_DTV_CMD(DTV_ROLLOFF, 1, 0),922_DTV_CMD(DTV_DELIVERY_SYSTEM, 1, 0),923_DTV_CMD(DTV_HIERARCHY, 1, 0),924_DTV_CMD(DTV_CODE_RATE_HP, 1, 0),925_DTV_CMD(DTV_CODE_RATE_LP, 1, 0),926_DTV_CMD(DTV_GUARD_INTERVAL, 1, 0),927_DTV_CMD(DTV_TRANSMISSION_MODE, 1, 0),928929_DTV_CMD(DTV_ISDBT_PARTIAL_RECEPTION, 1, 0),930_DTV_CMD(DTV_ISDBT_SOUND_BROADCASTING, 1, 0),931_DTV_CMD(DTV_ISDBT_SB_SUBCHANNEL_ID, 1, 0),932_DTV_CMD(DTV_ISDBT_SB_SEGMENT_IDX, 1, 0),933_DTV_CMD(DTV_ISDBT_SB_SEGMENT_COUNT, 1, 0),934_DTV_CMD(DTV_ISDBT_LAYER_ENABLED, 1, 0),935_DTV_CMD(DTV_ISDBT_LAYERA_FEC, 1, 0),936_DTV_CMD(DTV_ISDBT_LAYERA_MODULATION, 1, 0),937_DTV_CMD(DTV_ISDBT_LAYERA_SEGMENT_COUNT, 1, 0),938_DTV_CMD(DTV_ISDBT_LAYERA_TIME_INTERLEAVING, 1, 0),939_DTV_CMD(DTV_ISDBT_LAYERB_FEC, 1, 0),940_DTV_CMD(DTV_ISDBT_LAYERB_MODULATION, 1, 0),941_DTV_CMD(DTV_ISDBT_LAYERB_SEGMENT_COUNT, 1, 0),942_DTV_CMD(DTV_ISDBT_LAYERB_TIME_INTERLEAVING, 1, 0),943_DTV_CMD(DTV_ISDBT_LAYERC_FEC, 1, 0),944_DTV_CMD(DTV_ISDBT_LAYERC_MODULATION, 1, 0),945_DTV_CMD(DTV_ISDBT_LAYERC_SEGMENT_COUNT, 1, 0),946_DTV_CMD(DTV_ISDBT_LAYERC_TIME_INTERLEAVING, 1, 0),947948_DTV_CMD(DTV_ISDBT_PARTIAL_RECEPTION, 0, 0),949_DTV_CMD(DTV_ISDBT_SOUND_BROADCASTING, 0, 0),950_DTV_CMD(DTV_ISDBT_SB_SUBCHANNEL_ID, 0, 0),951_DTV_CMD(DTV_ISDBT_SB_SEGMENT_IDX, 0, 0),952_DTV_CMD(DTV_ISDBT_SB_SEGMENT_COUNT, 0, 0),953_DTV_CMD(DTV_ISDBT_LAYER_ENABLED, 0, 0),954_DTV_CMD(DTV_ISDBT_LAYERA_FEC, 0, 0),955_DTV_CMD(DTV_ISDBT_LAYERA_MODULATION, 0, 0),956_DTV_CMD(DTV_ISDBT_LAYERA_SEGMENT_COUNT, 0, 0),957_DTV_CMD(DTV_ISDBT_LAYERA_TIME_INTERLEAVING, 0, 0),958_DTV_CMD(DTV_ISDBT_LAYERB_FEC, 0, 0),959_DTV_CMD(DTV_ISDBT_LAYERB_MODULATION, 0, 0),960_DTV_CMD(DTV_ISDBT_LAYERB_SEGMENT_COUNT, 0, 0),961_DTV_CMD(DTV_ISDBT_LAYERB_TIME_INTERLEAVING, 0, 0),962_DTV_CMD(DTV_ISDBT_LAYERC_FEC, 0, 0),963_DTV_CMD(DTV_ISDBT_LAYERC_MODULATION, 0, 0),964_DTV_CMD(DTV_ISDBT_LAYERC_SEGMENT_COUNT, 0, 0),965_DTV_CMD(DTV_ISDBT_LAYERC_TIME_INTERLEAVING, 0, 0),966967_DTV_CMD(DTV_ISDBS_TS_ID, 1, 0),968969/* Get */970_DTV_CMD(DTV_DISEQC_SLAVE_REPLY, 0, 1),971_DTV_CMD(DTV_API_VERSION, 0, 0),972_DTV_CMD(DTV_CODE_RATE_HP, 0, 0),973_DTV_CMD(DTV_CODE_RATE_LP, 0, 0),974_DTV_CMD(DTV_GUARD_INTERVAL, 0, 0),975_DTV_CMD(DTV_TRANSMISSION_MODE, 0, 0),976_DTV_CMD(DTV_HIERARCHY, 0, 0),977};978979static void dtv_property_dump(struct dtv_property *tvp)980{981int i;982983if (tvp->cmd <= 0 || tvp->cmd > DTV_MAX_COMMAND) {984printk(KERN_WARNING "%s: tvp.cmd = 0x%08x undefined\n",985__func__, tvp->cmd);986return;987}988989dprintk("%s() tvp.cmd = 0x%08x (%s)\n"990,__func__991,tvp->cmd992,dtv_cmds[ tvp->cmd ].name);993994if(dtv_cmds[ tvp->cmd ].buffer) {995996dprintk("%s() tvp.u.buffer.len = 0x%02x\n"997,__func__998,tvp->u.buffer.len);9991000for(i = 0; i < tvp->u.buffer.len; i++)1001dprintk("%s() tvp.u.buffer.data[0x%02x] = 0x%02x\n"1002,__func__1003,i1004,tvp->u.buffer.data[i]);10051006} else1007dprintk("%s() tvp.u.data = 0x%08x\n", __func__, tvp->u.data);1008}10091010static int is_legacy_delivery_system(fe_delivery_system_t s)1011{1012if((s == SYS_UNDEFINED) || (s == SYS_DVBC_ANNEX_AC) ||1013(s == SYS_DVBC_ANNEX_B) || (s == SYS_DVBT) || (s == SYS_DVBS) ||1014(s == SYS_ATSC))1015return 1;10161017return 0;1018}10191020/* Synchronise the legacy tuning parameters into the cache, so that demodulator1021* drivers can use a single set_frontend tuning function, regardless of whether1022* it's being used for the legacy or new API, reducing code and complexity.1023*/1024static void dtv_property_cache_sync(struct dvb_frontend *fe,1025struct dtv_frontend_properties *c,1026const struct dvb_frontend_parameters *p)1027{1028c->frequency = p->frequency;1029c->inversion = p->inversion;10301031switch (fe->ops.info.type) {1032case FE_QPSK:1033c->modulation = QPSK; /* implied for DVB-S in legacy API */1034c->rolloff = ROLLOFF_35;/* implied for DVB-S */1035c->symbol_rate = p->u.qpsk.symbol_rate;1036c->fec_inner = p->u.qpsk.fec_inner;1037c->delivery_system = SYS_DVBS;1038break;1039case FE_QAM:1040c->symbol_rate = p->u.qam.symbol_rate;1041c->fec_inner = p->u.qam.fec_inner;1042c->modulation = p->u.qam.modulation;1043c->delivery_system = SYS_DVBC_ANNEX_AC;1044break;1045case FE_OFDM:1046if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ)1047c->bandwidth_hz = 6000000;1048else if (p->u.ofdm.bandwidth == BANDWIDTH_7_MHZ)1049c->bandwidth_hz = 7000000;1050else if (p->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)1051c->bandwidth_hz = 8000000;1052else1053/* Including BANDWIDTH_AUTO */1054c->bandwidth_hz = 0;1055c->code_rate_HP = p->u.ofdm.code_rate_HP;1056c->code_rate_LP = p->u.ofdm.code_rate_LP;1057c->modulation = p->u.ofdm.constellation;1058c->transmission_mode = p->u.ofdm.transmission_mode;1059c->guard_interval = p->u.ofdm.guard_interval;1060c->hierarchy = p->u.ofdm.hierarchy_information;1061c->delivery_system = SYS_DVBT;1062break;1063case FE_ATSC:1064c->modulation = p->u.vsb.modulation;1065if ((c->modulation == VSB_8) || (c->modulation == VSB_16))1066c->delivery_system = SYS_ATSC;1067else1068c->delivery_system = SYS_DVBC_ANNEX_B;1069break;1070}1071}10721073/* Ensure the cached values are set correctly in the frontend1074* legacy tuning structures, for the advanced tuning API.1075*/1076static void dtv_property_legacy_params_sync(struct dvb_frontend *fe)1077{1078const struct dtv_frontend_properties *c = &fe->dtv_property_cache;1079struct dvb_frontend_private *fepriv = fe->frontend_priv;1080struct dvb_frontend_parameters *p = &fepriv->parameters_in;10811082p->frequency = c->frequency;1083p->inversion = c->inversion;10841085switch (fe->ops.info.type) {1086case FE_QPSK:1087dprintk("%s() Preparing QPSK req\n", __func__);1088p->u.qpsk.symbol_rate = c->symbol_rate;1089p->u.qpsk.fec_inner = c->fec_inner;1090break;1091case FE_QAM:1092dprintk("%s() Preparing QAM req\n", __func__);1093p->u.qam.symbol_rate = c->symbol_rate;1094p->u.qam.fec_inner = c->fec_inner;1095p->u.qam.modulation = c->modulation;1096break;1097case FE_OFDM:1098dprintk("%s() Preparing OFDM req\n", __func__);1099if (c->bandwidth_hz == 6000000)1100p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;1101else if (c->bandwidth_hz == 7000000)1102p->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;1103else if (c->bandwidth_hz == 8000000)1104p->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;1105else1106p->u.ofdm.bandwidth = BANDWIDTH_AUTO;1107p->u.ofdm.code_rate_HP = c->code_rate_HP;1108p->u.ofdm.code_rate_LP = c->code_rate_LP;1109p->u.ofdm.constellation = c->modulation;1110p->u.ofdm.transmission_mode = c->transmission_mode;1111p->u.ofdm.guard_interval = c->guard_interval;1112p->u.ofdm.hierarchy_information = c->hierarchy;1113break;1114case FE_ATSC:1115dprintk("%s() Preparing VSB req\n", __func__);1116p->u.vsb.modulation = c->modulation;1117break;1118}1119}11201121/* Ensure the cached values are set correctly in the frontend1122* legacy tuning structures, for the legacy tuning API.1123*/1124static void dtv_property_adv_params_sync(struct dvb_frontend *fe)1125{1126const struct dtv_frontend_properties *c = &fe->dtv_property_cache;1127struct dvb_frontend_private *fepriv = fe->frontend_priv;1128struct dvb_frontend_parameters *p = &fepriv->parameters_in;11291130p->frequency = c->frequency;1131p->inversion = c->inversion;11321133switch(c->modulation) {1134case PSK_8:1135case APSK_16:1136case APSK_32:1137case QPSK:1138p->u.qpsk.symbol_rate = c->symbol_rate;1139p->u.qpsk.fec_inner = c->fec_inner;1140break;1141default:1142break;1143}11441145/* Fake out a generic DVB-T request so we pass validation in the ioctl */1146if ((c->delivery_system == SYS_ISDBT) ||1147(c->delivery_system == SYS_DVBT2)) {1148p->u.ofdm.constellation = QAM_AUTO;1149p->u.ofdm.code_rate_HP = FEC_AUTO;1150p->u.ofdm.code_rate_LP = FEC_AUTO;1151p->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO;1152p->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO;1153p->u.ofdm.hierarchy_information = HIERARCHY_AUTO;1154if (c->bandwidth_hz == 8000000)1155p->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;1156else if (c->bandwidth_hz == 7000000)1157p->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;1158else if (c->bandwidth_hz == 6000000)1159p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;1160else1161p->u.ofdm.bandwidth = BANDWIDTH_AUTO;1162}1163}11641165static void dtv_property_cache_submit(struct dvb_frontend *fe)1166{1167const struct dtv_frontend_properties *c = &fe->dtv_property_cache;11681169/* For legacy delivery systems we don't need the delivery_system to1170* be specified, but we populate the older structures from the cache1171* so we can call set_frontend on older drivers.1172*/1173if(is_legacy_delivery_system(c->delivery_system)) {11741175dprintk("%s() legacy, modulation = %d\n", __func__, c->modulation);1176dtv_property_legacy_params_sync(fe);11771178} else {1179dprintk("%s() adv, modulation = %d\n", __func__, c->modulation);11801181/* For advanced delivery systems / modulation types ...1182* we seed the lecacy dvb_frontend_parameters structure1183* so that the sanity checking code later in the IOCTL processing1184* can validate our basic frequency ranges, symbolrates, modulation1185* etc.1186*/1187dtv_property_adv_params_sync(fe);1188}1189}11901191static int dvb_frontend_ioctl_legacy(struct file *file,1192unsigned int cmd, void *parg);1193static int dvb_frontend_ioctl_properties(struct file *file,1194unsigned int cmd, void *parg);11951196static int dtv_property_process_get(struct dvb_frontend *fe,1197struct dtv_property *tvp,1198struct file *file)1199{1200const struct dtv_frontend_properties *c = &fe->dtv_property_cache;1201struct dvb_frontend_private *fepriv = fe->frontend_priv;1202struct dtv_frontend_properties cdetected;1203int r;12041205/*1206* If the driver implements a get_frontend function, then convert1207* detected parameters to S2API properties.1208*/1209if (fe->ops.get_frontend) {1210cdetected = *c;1211dtv_property_cache_sync(fe, &cdetected, &fepriv->parameters_out);1212c = &cdetected;1213}12141215switch(tvp->cmd) {1216case DTV_FREQUENCY:1217tvp->u.data = c->frequency;1218break;1219case DTV_MODULATION:1220tvp->u.data = c->modulation;1221break;1222case DTV_BANDWIDTH_HZ:1223tvp->u.data = c->bandwidth_hz;1224break;1225case DTV_INVERSION:1226tvp->u.data = c->inversion;1227break;1228case DTV_SYMBOL_RATE:1229tvp->u.data = c->symbol_rate;1230break;1231case DTV_INNER_FEC:1232tvp->u.data = c->fec_inner;1233break;1234case DTV_PILOT:1235tvp->u.data = c->pilot;1236break;1237case DTV_ROLLOFF:1238tvp->u.data = c->rolloff;1239break;1240case DTV_DELIVERY_SYSTEM:1241tvp->u.data = c->delivery_system;1242break;1243case DTV_VOLTAGE:1244tvp->u.data = c->voltage;1245break;1246case DTV_TONE:1247tvp->u.data = c->sectone;1248break;1249case DTV_API_VERSION:1250tvp->u.data = (DVB_API_VERSION << 8) | DVB_API_VERSION_MINOR;1251break;1252case DTV_CODE_RATE_HP:1253tvp->u.data = c->code_rate_HP;1254break;1255case DTV_CODE_RATE_LP:1256tvp->u.data = c->code_rate_LP;1257break;1258case DTV_GUARD_INTERVAL:1259tvp->u.data = c->guard_interval;1260break;1261case DTV_TRANSMISSION_MODE:1262tvp->u.data = c->transmission_mode;1263break;1264case DTV_HIERARCHY:1265tvp->u.data = c->hierarchy;1266break;12671268/* ISDB-T Support here */1269case DTV_ISDBT_PARTIAL_RECEPTION:1270tvp->u.data = c->isdbt_partial_reception;1271break;1272case DTV_ISDBT_SOUND_BROADCASTING:1273tvp->u.data = c->isdbt_sb_mode;1274break;1275case DTV_ISDBT_SB_SUBCHANNEL_ID:1276tvp->u.data = c->isdbt_sb_subchannel;1277break;1278case DTV_ISDBT_SB_SEGMENT_IDX:1279tvp->u.data = c->isdbt_sb_segment_idx;1280break;1281case DTV_ISDBT_SB_SEGMENT_COUNT:1282tvp->u.data = c->isdbt_sb_segment_count;1283break;1284case DTV_ISDBT_LAYER_ENABLED:1285tvp->u.data = c->isdbt_layer_enabled;1286break;1287case DTV_ISDBT_LAYERA_FEC:1288tvp->u.data = c->layer[0].fec;1289break;1290case DTV_ISDBT_LAYERA_MODULATION:1291tvp->u.data = c->layer[0].modulation;1292break;1293case DTV_ISDBT_LAYERA_SEGMENT_COUNT:1294tvp->u.data = c->layer[0].segment_count;1295break;1296case DTV_ISDBT_LAYERA_TIME_INTERLEAVING:1297tvp->u.data = c->layer[0].interleaving;1298break;1299case DTV_ISDBT_LAYERB_FEC:1300tvp->u.data = c->layer[1].fec;1301break;1302case DTV_ISDBT_LAYERB_MODULATION:1303tvp->u.data = c->layer[1].modulation;1304break;1305case DTV_ISDBT_LAYERB_SEGMENT_COUNT:1306tvp->u.data = c->layer[1].segment_count;1307break;1308case DTV_ISDBT_LAYERB_TIME_INTERLEAVING:1309tvp->u.data = c->layer[1].interleaving;1310break;1311case DTV_ISDBT_LAYERC_FEC:1312tvp->u.data = c->layer[2].fec;1313break;1314case DTV_ISDBT_LAYERC_MODULATION:1315tvp->u.data = c->layer[2].modulation;1316break;1317case DTV_ISDBT_LAYERC_SEGMENT_COUNT:1318tvp->u.data = c->layer[2].segment_count;1319break;1320case DTV_ISDBT_LAYERC_TIME_INTERLEAVING:1321tvp->u.data = c->layer[2].interleaving;1322break;1323case DTV_ISDBS_TS_ID:1324tvp->u.data = c->isdbs_ts_id;1325break;1326case DTV_DVBT2_PLP_ID:1327tvp->u.data = c->dvbt2_plp_id;1328break;1329default:1330return -EINVAL;1331}13321333/* Allow the frontend to override outgoing properties */1334if (fe->ops.get_property) {1335r = fe->ops.get_property(fe, tvp);1336if (r < 0)1337return r;1338}13391340dtv_property_dump(tvp);13411342return 0;1343}13441345static int dtv_property_process_set(struct dvb_frontend *fe,1346struct dtv_property *tvp,1347struct file *file)1348{1349int r = 0;1350struct dtv_frontend_properties *c = &fe->dtv_property_cache;1351struct dvb_frontend_private *fepriv = fe->frontend_priv;1352dtv_property_dump(tvp);13531354/* Allow the frontend to validate incoming properties */1355if (fe->ops.set_property) {1356r = fe->ops.set_property(fe, tvp);1357if (r < 0)1358return r;1359}13601361switch(tvp->cmd) {1362case DTV_CLEAR:1363/* Reset a cache of data specific to the frontend here. This does1364* not effect hardware.1365*/1366dvb_frontend_clear_cache(fe);1367dprintk("%s() Flushing property cache\n", __func__);1368break;1369case DTV_TUNE:1370/* interpret the cache of data, build either a traditional frontend1371* tunerequest so we can pass validation in the FE_SET_FRONTEND1372* ioctl.1373*/1374c->state = tvp->cmd;1375dprintk("%s() Finalised property cache\n", __func__);1376dtv_property_cache_submit(fe);13771378r = dvb_frontend_ioctl_legacy(file, FE_SET_FRONTEND,1379&fepriv->parameters_in);1380break;1381case DTV_FREQUENCY:1382c->frequency = tvp->u.data;1383break;1384case DTV_MODULATION:1385c->modulation = tvp->u.data;1386break;1387case DTV_BANDWIDTH_HZ:1388c->bandwidth_hz = tvp->u.data;1389break;1390case DTV_INVERSION:1391c->inversion = tvp->u.data;1392break;1393case DTV_SYMBOL_RATE:1394c->symbol_rate = tvp->u.data;1395break;1396case DTV_INNER_FEC:1397c->fec_inner = tvp->u.data;1398break;1399case DTV_PILOT:1400c->pilot = tvp->u.data;1401break;1402case DTV_ROLLOFF:1403c->rolloff = tvp->u.data;1404break;1405case DTV_DELIVERY_SYSTEM:1406c->delivery_system = tvp->u.data;1407break;1408case DTV_VOLTAGE:1409c->voltage = tvp->u.data;1410r = dvb_frontend_ioctl_legacy(file, FE_SET_VOLTAGE,1411(void *)c->voltage);1412break;1413case DTV_TONE:1414c->sectone = tvp->u.data;1415r = dvb_frontend_ioctl_legacy(file, FE_SET_TONE,1416(void *)c->sectone);1417break;1418case DTV_CODE_RATE_HP:1419c->code_rate_HP = tvp->u.data;1420break;1421case DTV_CODE_RATE_LP:1422c->code_rate_LP = tvp->u.data;1423break;1424case DTV_GUARD_INTERVAL:1425c->guard_interval = tvp->u.data;1426break;1427case DTV_TRANSMISSION_MODE:1428c->transmission_mode = tvp->u.data;1429break;1430case DTV_HIERARCHY:1431c->hierarchy = tvp->u.data;1432break;14331434/* ISDB-T Support here */1435case DTV_ISDBT_PARTIAL_RECEPTION:1436c->isdbt_partial_reception = tvp->u.data;1437break;1438case DTV_ISDBT_SOUND_BROADCASTING:1439c->isdbt_sb_mode = tvp->u.data;1440break;1441case DTV_ISDBT_SB_SUBCHANNEL_ID:1442c->isdbt_sb_subchannel = tvp->u.data;1443break;1444case DTV_ISDBT_SB_SEGMENT_IDX:1445c->isdbt_sb_segment_idx = tvp->u.data;1446break;1447case DTV_ISDBT_SB_SEGMENT_COUNT:1448c->isdbt_sb_segment_count = tvp->u.data;1449break;1450case DTV_ISDBT_LAYER_ENABLED:1451c->isdbt_layer_enabled = tvp->u.data;1452break;1453case DTV_ISDBT_LAYERA_FEC:1454c->layer[0].fec = tvp->u.data;1455break;1456case DTV_ISDBT_LAYERA_MODULATION:1457c->layer[0].modulation = tvp->u.data;1458break;1459case DTV_ISDBT_LAYERA_SEGMENT_COUNT:1460c->layer[0].segment_count = tvp->u.data;1461break;1462case DTV_ISDBT_LAYERA_TIME_INTERLEAVING:1463c->layer[0].interleaving = tvp->u.data;1464break;1465case DTV_ISDBT_LAYERB_FEC:1466c->layer[1].fec = tvp->u.data;1467break;1468case DTV_ISDBT_LAYERB_MODULATION:1469c->layer[1].modulation = tvp->u.data;1470break;1471case DTV_ISDBT_LAYERB_SEGMENT_COUNT:1472c->layer[1].segment_count = tvp->u.data;1473break;1474case DTV_ISDBT_LAYERB_TIME_INTERLEAVING:1475c->layer[1].interleaving = tvp->u.data;1476break;1477case DTV_ISDBT_LAYERC_FEC:1478c->layer[2].fec = tvp->u.data;1479break;1480case DTV_ISDBT_LAYERC_MODULATION:1481c->layer[2].modulation = tvp->u.data;1482break;1483case DTV_ISDBT_LAYERC_SEGMENT_COUNT:1484c->layer[2].segment_count = tvp->u.data;1485break;1486case DTV_ISDBT_LAYERC_TIME_INTERLEAVING:1487c->layer[2].interleaving = tvp->u.data;1488break;1489case DTV_ISDBS_TS_ID:1490c->isdbs_ts_id = tvp->u.data;1491break;1492case DTV_DVBT2_PLP_ID:1493c->dvbt2_plp_id = tvp->u.data;1494break;1495default:1496return -EINVAL;1497}14981499return r;1500}15011502static int dvb_frontend_ioctl(struct file *file,1503unsigned int cmd, void *parg)1504{1505struct dvb_device *dvbdev = file->private_data;1506struct dvb_frontend *fe = dvbdev->priv;1507struct dtv_frontend_properties *c = &fe->dtv_property_cache;1508struct dvb_frontend_private *fepriv = fe->frontend_priv;1509int err = -EOPNOTSUPP;15101511dprintk("%s (%d)\n", __func__, _IOC_NR(cmd));15121513if (fepriv->exit != DVB_FE_NO_EXIT)1514return -ENODEV;15151516if ((file->f_flags & O_ACCMODE) == O_RDONLY &&1517(_IOC_DIR(cmd) != _IOC_READ || cmd == FE_GET_EVENT ||1518cmd == FE_DISEQC_RECV_SLAVE_REPLY))1519return -EPERM;15201521if (down_interruptible (&fepriv->sem))1522return -ERESTARTSYS;15231524if ((cmd == FE_SET_PROPERTY) || (cmd == FE_GET_PROPERTY))1525err = dvb_frontend_ioctl_properties(file, cmd, parg);1526else {1527c->state = DTV_UNDEFINED;1528err = dvb_frontend_ioctl_legacy(file, cmd, parg);1529}15301531up(&fepriv->sem);1532return err;1533}15341535static int dvb_frontend_ioctl_properties(struct file *file,1536unsigned int cmd, void *parg)1537{1538struct dvb_device *dvbdev = file->private_data;1539struct dvb_frontend *fe = dvbdev->priv;1540struct dtv_frontend_properties *c = &fe->dtv_property_cache;1541int err = 0;15421543struct dtv_properties *tvps = NULL;1544struct dtv_property *tvp = NULL;1545int i;15461547dprintk("%s\n", __func__);15481549if(cmd == FE_SET_PROPERTY) {1550tvps = (struct dtv_properties __user *)parg;15511552dprintk("%s() properties.num = %d\n", __func__, tvps->num);1553dprintk("%s() properties.props = %p\n", __func__, tvps->props);15541555/* Put an arbitrary limit on the number of messages that can1556* be sent at once */1557if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS))1558return -EINVAL;15591560tvp = kmalloc(tvps->num * sizeof(struct dtv_property), GFP_KERNEL);1561if (!tvp) {1562err = -ENOMEM;1563goto out;1564}15651566if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) {1567err = -EFAULT;1568goto out;1569}15701571for (i = 0; i < tvps->num; i++) {1572err = dtv_property_process_set(fe, tvp + i, file);1573if (err < 0)1574goto out;1575(tvp + i)->result = err;1576}15771578if (c->state == DTV_TUNE)1579dprintk("%s() Property cache is full, tuning\n", __func__);15801581} else1582if(cmd == FE_GET_PROPERTY) {15831584tvps = (struct dtv_properties __user *)parg;15851586dprintk("%s() properties.num = %d\n", __func__, tvps->num);1587dprintk("%s() properties.props = %p\n", __func__, tvps->props);15881589/* Put an arbitrary limit on the number of messages that can1590* be sent at once */1591if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS))1592return -EINVAL;15931594tvp = kmalloc(tvps->num * sizeof(struct dtv_property), GFP_KERNEL);1595if (!tvp) {1596err = -ENOMEM;1597goto out;1598}15991600if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) {1601err = -EFAULT;1602goto out;1603}16041605for (i = 0; i < tvps->num; i++) {1606err = dtv_property_process_get(fe, tvp + i, file);1607if (err < 0)1608goto out;1609(tvp + i)->result = err;1610}16111612if (copy_to_user(tvps->props, tvp, tvps->num * sizeof(struct dtv_property))) {1613err = -EFAULT;1614goto out;1615}16161617} else1618err = -EOPNOTSUPP;16191620out:1621kfree(tvp);1622return err;1623}16241625static int dvb_frontend_ioctl_legacy(struct file *file,1626unsigned int cmd, void *parg)1627{1628struct dvb_device *dvbdev = file->private_data;1629struct dvb_frontend *fe = dvbdev->priv;1630struct dvb_frontend_private *fepriv = fe->frontend_priv;1631int cb_err, err = -EOPNOTSUPP;16321633if (fe->dvb->fe_ioctl_override) {1634cb_err = fe->dvb->fe_ioctl_override(fe, cmd, parg,1635DVB_FE_IOCTL_PRE);1636if (cb_err < 0)1637return cb_err;1638if (cb_err > 0)1639return 0;1640/* fe_ioctl_override returning 0 allows1641* dvb-core to continue handling the ioctl */1642}16431644switch (cmd) {1645case FE_GET_INFO: {1646struct dvb_frontend_info* info = parg;1647memcpy(info, &fe->ops.info, sizeof(struct dvb_frontend_info));1648dvb_frontend_get_frequency_limits(fe, &info->frequency_min, &info->frequency_max);16491650/* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't1651* do it, it is done for it. */1652info->caps |= FE_CAN_INVERSION_AUTO;1653err = 0;1654break;1655}16561657case FE_READ_STATUS: {1658fe_status_t* status = parg;16591660/* if retune was requested but hasn't occurred yet, prevent1661* that user get signal state from previous tuning */1662if (fepriv->state == FESTATE_RETUNE ||1663fepriv->state == FESTATE_ERROR) {1664err=0;1665*status = 0;1666break;1667}16681669if (fe->ops.read_status)1670err = fe->ops.read_status(fe, status);1671break;1672}1673case FE_READ_BER:1674if (fe->ops.read_ber)1675err = fe->ops.read_ber(fe, (__u32*) parg);1676break;16771678case FE_READ_SIGNAL_STRENGTH:1679if (fe->ops.read_signal_strength)1680err = fe->ops.read_signal_strength(fe, (__u16*) parg);1681break;16821683case FE_READ_SNR:1684if (fe->ops.read_snr)1685err = fe->ops.read_snr(fe, (__u16*) parg);1686break;16871688case FE_READ_UNCORRECTED_BLOCKS:1689if (fe->ops.read_ucblocks)1690err = fe->ops.read_ucblocks(fe, (__u32*) parg);1691break;169216931694case FE_DISEQC_RESET_OVERLOAD:1695if (fe->ops.diseqc_reset_overload) {1696err = fe->ops.diseqc_reset_overload(fe);1697fepriv->state = FESTATE_DISEQC;1698fepriv->status = 0;1699}1700break;17011702case FE_DISEQC_SEND_MASTER_CMD:1703if (fe->ops.diseqc_send_master_cmd) {1704err = fe->ops.diseqc_send_master_cmd(fe, (struct dvb_diseqc_master_cmd*) parg);1705fepriv->state = FESTATE_DISEQC;1706fepriv->status = 0;1707}1708break;17091710case FE_DISEQC_SEND_BURST:1711if (fe->ops.diseqc_send_burst) {1712err = fe->ops.diseqc_send_burst(fe, (fe_sec_mini_cmd_t) parg);1713fepriv->state = FESTATE_DISEQC;1714fepriv->status = 0;1715}1716break;17171718case FE_SET_TONE:1719if (fe->ops.set_tone) {1720err = fe->ops.set_tone(fe, (fe_sec_tone_mode_t) parg);1721fepriv->tone = (fe_sec_tone_mode_t) parg;1722fepriv->state = FESTATE_DISEQC;1723fepriv->status = 0;1724}1725break;17261727case FE_SET_VOLTAGE:1728if (fe->ops.set_voltage) {1729err = fe->ops.set_voltage(fe, (fe_sec_voltage_t) parg);1730fepriv->voltage = (fe_sec_voltage_t) parg;1731fepriv->state = FESTATE_DISEQC;1732fepriv->status = 0;1733}1734break;17351736case FE_DISHNETWORK_SEND_LEGACY_CMD:1737if (fe->ops.dishnetwork_send_legacy_command) {1738err = fe->ops.dishnetwork_send_legacy_command(fe, (unsigned long) parg);1739fepriv->state = FESTATE_DISEQC;1740fepriv->status = 0;1741} else if (fe->ops.set_voltage) {1742/*1743* NOTE: This is a fallback condition. Some frontends1744* (stv0299 for instance) take longer than 8msec to1745* respond to a set_voltage command. Those switches1746* need custom routines to switch properly. For all1747* other frontends, the following should work ok.1748* Dish network legacy switches (as used by Dish500)1749* are controlled by sending 9-bit command words1750* spaced 8msec apart.1751* the actual command word is switch/port dependent1752* so it is up to the userspace application to send1753* the right command.1754* The command must always start with a '0' after1755* initialization, so parg is 8 bits and does not1756* include the initialization or start bit1757*/1758unsigned long swcmd = ((unsigned long) parg) << 1;1759struct timeval nexttime;1760struct timeval tv[10];1761int i;1762u8 last = 1;1763if (dvb_frontend_debug)1764printk("%s switch command: 0x%04lx\n", __func__, swcmd);1765do_gettimeofday(&nexttime);1766if (dvb_frontend_debug)1767memcpy(&tv[0], &nexttime, sizeof(struct timeval));1768/* before sending a command, initialize by sending1769* a 32ms 18V to the switch1770*/1771fe->ops.set_voltage(fe, SEC_VOLTAGE_18);1772dvb_frontend_sleep_until(&nexttime, 32000);17731774for (i = 0; i < 9; i++) {1775if (dvb_frontend_debug)1776do_gettimeofday(&tv[i + 1]);1777if ((swcmd & 0x01) != last) {1778/* set voltage to (last ? 13V : 18V) */1779fe->ops.set_voltage(fe, (last) ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18);1780last = (last) ? 0 : 1;1781}1782swcmd = swcmd >> 1;1783if (i != 8)1784dvb_frontend_sleep_until(&nexttime, 8000);1785}1786if (dvb_frontend_debug) {1787printk("%s(%d): switch delay (should be 32k followed by all 8k\n",1788__func__, fe->dvb->num);1789for (i = 1; i < 10; i++)1790printk("%d: %d\n", i, timeval_usec_diff(tv[i-1] , tv[i]));1791}1792err = 0;1793fepriv->state = FESTATE_DISEQC;1794fepriv->status = 0;1795}1796break;17971798case FE_DISEQC_RECV_SLAVE_REPLY:1799if (fe->ops.diseqc_recv_slave_reply)1800err = fe->ops.diseqc_recv_slave_reply(fe, (struct dvb_diseqc_slave_reply*) parg);1801break;18021803case FE_ENABLE_HIGH_LNB_VOLTAGE:1804if (fe->ops.enable_high_lnb_voltage)1805err = fe->ops.enable_high_lnb_voltage(fe, (long) parg);1806break;18071808case FE_SET_FRONTEND: {1809struct dtv_frontend_properties *c = &fe->dtv_property_cache;1810struct dvb_frontend_tune_settings fetunesettings;18111812if (c->state == DTV_TUNE) {1813if (dvb_frontend_check_parameters(fe, &fepriv->parameters_in) < 0) {1814err = -EINVAL;1815break;1816}1817} else {1818if (dvb_frontend_check_parameters(fe, parg) < 0) {1819err = -EINVAL;1820break;1821}18221823memcpy (&fepriv->parameters_in, parg,1824sizeof (struct dvb_frontend_parameters));1825dtv_property_cache_sync(fe, c, &fepriv->parameters_in);1826}18271828memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings));1829memcpy(&fetunesettings.parameters, parg,1830sizeof (struct dvb_frontend_parameters));18311832/* force auto frequency inversion if requested */1833if (dvb_force_auto_inversion) {1834fepriv->parameters_in.inversion = INVERSION_AUTO;1835fetunesettings.parameters.inversion = INVERSION_AUTO;1836}1837if (fe->ops.info.type == FE_OFDM) {1838/* without hierarchical coding code_rate_LP is irrelevant,1839* so we tolerate the otherwise invalid FEC_NONE setting */1840if (fepriv->parameters_in.u.ofdm.hierarchy_information == HIERARCHY_NONE &&1841fepriv->parameters_in.u.ofdm.code_rate_LP == FEC_NONE)1842fepriv->parameters_in.u.ofdm.code_rate_LP = FEC_AUTO;1843}18441845/* get frontend-specific tuning settings */1846if (fe->ops.get_tune_settings && (fe->ops.get_tune_settings(fe, &fetunesettings) == 0)) {1847fepriv->min_delay = (fetunesettings.min_delay_ms * HZ) / 1000;1848fepriv->max_drift = fetunesettings.max_drift;1849fepriv->step_size = fetunesettings.step_size;1850} else {1851/* default values */1852switch(fe->ops.info.type) {1853case FE_QPSK:1854fepriv->min_delay = HZ/20;1855fepriv->step_size = fepriv->parameters_in.u.qpsk.symbol_rate / 16000;1856fepriv->max_drift = fepriv->parameters_in.u.qpsk.symbol_rate / 2000;1857break;18581859case FE_QAM:1860fepriv->min_delay = HZ/20;1861fepriv->step_size = 0; /* no zigzag */1862fepriv->max_drift = 0;1863break;18641865case FE_OFDM:1866fepriv->min_delay = HZ/20;1867fepriv->step_size = fe->ops.info.frequency_stepsize * 2;1868fepriv->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1;1869break;1870case FE_ATSC:1871fepriv->min_delay = HZ/20;1872fepriv->step_size = 0;1873fepriv->max_drift = 0;1874break;1875}1876}1877if (dvb_override_tune_delay > 0)1878fepriv->min_delay = (dvb_override_tune_delay * HZ) / 1000;18791880fepriv->state = FESTATE_RETUNE;18811882/* Request the search algorithm to search */1883fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;18841885dvb_frontend_wakeup(fe);1886dvb_frontend_add_event(fe, 0);1887fepriv->status = 0;1888err = 0;1889break;1890}18911892case FE_GET_EVENT:1893err = dvb_frontend_get_event (fe, parg, file->f_flags);1894break;18951896case FE_GET_FRONTEND:1897if (fe->ops.get_frontend) {1898err = fe->ops.get_frontend(fe, &fepriv->parameters_out);1899memcpy(parg, &fepriv->parameters_out, sizeof(struct dvb_frontend_parameters));1900}1901break;19021903case FE_SET_FRONTEND_TUNE_MODE:1904fepriv->tune_mode_flags = (unsigned long) parg;1905err = 0;1906break;1907};19081909if (fe->dvb->fe_ioctl_override) {1910cb_err = fe->dvb->fe_ioctl_override(fe, cmd, parg,1911DVB_FE_IOCTL_POST);1912if (cb_err < 0)1913return cb_err;1914}19151916return err;1917}191819191920static unsigned int dvb_frontend_poll(struct file *file, struct poll_table_struct *wait)1921{1922struct dvb_device *dvbdev = file->private_data;1923struct dvb_frontend *fe = dvbdev->priv;1924struct dvb_frontend_private *fepriv = fe->frontend_priv;19251926dprintk ("%s\n", __func__);19271928poll_wait (file, &fepriv->events.wait_queue, wait);19291930if (fepriv->events.eventw != fepriv->events.eventr)1931return (POLLIN | POLLRDNORM | POLLPRI);19321933return 0;1934}19351936static int dvb_frontend_open(struct inode *inode, struct file *file)1937{1938struct dvb_device *dvbdev = file->private_data;1939struct dvb_frontend *fe = dvbdev->priv;1940struct dvb_frontend_private *fepriv = fe->frontend_priv;1941struct dvb_adapter *adapter = fe->dvb;1942int ret;19431944dprintk ("%s\n", __func__);1945if (fepriv->exit == DVB_FE_DEVICE_REMOVED)1946return -ENODEV;19471948if (adapter->mfe_shared) {1949mutex_lock (&adapter->mfe_lock);19501951if (adapter->mfe_dvbdev == NULL)1952adapter->mfe_dvbdev = dvbdev;19531954else if (adapter->mfe_dvbdev != dvbdev) {1955struct dvb_device1956*mfedev = adapter->mfe_dvbdev;1957struct dvb_frontend1958*mfe = mfedev->priv;1959struct dvb_frontend_private1960*mfepriv = mfe->frontend_priv;1961int mferetry = (dvb_mfe_wait_time << 1);19621963mutex_unlock (&adapter->mfe_lock);1964while (mferetry-- && (mfedev->users != -1 ||1965mfepriv->thread != NULL)) {1966if(msleep_interruptible(500)) {1967if(signal_pending(current))1968return -EINTR;1969}1970}19711972mutex_lock (&adapter->mfe_lock);1973if(adapter->mfe_dvbdev != dvbdev) {1974mfedev = adapter->mfe_dvbdev;1975mfe = mfedev->priv;1976mfepriv = mfe->frontend_priv;1977if (mfedev->users != -1 ||1978mfepriv->thread != NULL) {1979mutex_unlock (&adapter->mfe_lock);1980return -EBUSY;1981}1982adapter->mfe_dvbdev = dvbdev;1983}1984}1985}19861987if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl) {1988if ((ret = fe->ops.ts_bus_ctrl(fe, 1)) < 0)1989goto err0;19901991/* If we took control of the bus, we need to force1992reinitialization. This is because many ts_bus_ctrl()1993functions strobe the RESET pin on the demod, and if the1994frontend thread already exists then the dvb_init() routine1995won't get called (which is what usually does initial1996register configuration). */1997fepriv->reinitialise = 1;1998}19992000if ((ret = dvb_generic_open (inode, file)) < 0)2001goto err1;20022003if ((file->f_flags & O_ACCMODE) != O_RDONLY) {2004/* normal tune mode when opened R/W */2005fepriv->tune_mode_flags &= ~FE_TUNE_MODE_ONESHOT;2006fepriv->tone = -1;2007fepriv->voltage = -1;20082009ret = dvb_frontend_start (fe);2010if (ret)2011goto err2;20122013/* empty event queue */2014fepriv->events.eventr = fepriv->events.eventw = 0;2015}20162017if (adapter->mfe_shared)2018mutex_unlock (&adapter->mfe_lock);2019return ret;20202021err2:2022dvb_generic_release(inode, file);2023err1:2024if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl)2025fe->ops.ts_bus_ctrl(fe, 0);2026err0:2027if (adapter->mfe_shared)2028mutex_unlock (&adapter->mfe_lock);2029return ret;2030}20312032static int dvb_frontend_release(struct inode *inode, struct file *file)2033{2034struct dvb_device *dvbdev = file->private_data;2035struct dvb_frontend *fe = dvbdev->priv;2036struct dvb_frontend_private *fepriv = fe->frontend_priv;2037int ret;20382039dprintk ("%s\n", __func__);20402041if ((file->f_flags & O_ACCMODE) != O_RDONLY)2042fepriv->release_jiffies = jiffies;20432044ret = dvb_generic_release (inode, file);20452046if (dvbdev->users == -1) {2047if (fepriv->exit != DVB_FE_NO_EXIT) {2048fops_put(file->f_op);2049file->f_op = NULL;2050wake_up(&dvbdev->wait_queue);2051}2052if (fe->ops.ts_bus_ctrl)2053fe->ops.ts_bus_ctrl(fe, 0);2054}20552056return ret;2057}20582059static const struct file_operations dvb_frontend_fops = {2060.owner = THIS_MODULE,2061.unlocked_ioctl = dvb_generic_ioctl,2062.poll = dvb_frontend_poll,2063.open = dvb_frontend_open,2064.release = dvb_frontend_release,2065.llseek = noop_llseek,2066};20672068int dvb_register_frontend(struct dvb_adapter* dvb,2069struct dvb_frontend* fe)2070{2071struct dvb_frontend_private *fepriv;2072static const struct dvb_device dvbdev_template = {2073.users = ~0,2074.writers = 1,2075.readers = (~0)-1,2076.fops = &dvb_frontend_fops,2077.kernel_ioctl = dvb_frontend_ioctl2078};20792080dprintk ("%s\n", __func__);20812082if (mutex_lock_interruptible(&frontend_mutex))2083return -ERESTARTSYS;20842085fe->frontend_priv = kzalloc(sizeof(struct dvb_frontend_private), GFP_KERNEL);2086if (fe->frontend_priv == NULL) {2087mutex_unlock(&frontend_mutex);2088return -ENOMEM;2089}2090fepriv = fe->frontend_priv;20912092sema_init(&fepriv->sem, 1);2093init_waitqueue_head (&fepriv->wait_queue);2094init_waitqueue_head (&fepriv->events.wait_queue);2095mutex_init(&fepriv->events.mtx);2096fe->dvb = dvb;2097fepriv->inversion = INVERSION_OFF;20982099printk ("DVB: registering adapter %i frontend %i (%s)...\n",2100fe->dvb->num,2101fe->id,2102fe->ops.info.name);21032104dvb_register_device (fe->dvb, &fepriv->dvbdev, &dvbdev_template,2105fe, DVB_DEVICE_FRONTEND);21062107mutex_unlock(&frontend_mutex);2108return 0;2109}2110EXPORT_SYMBOL(dvb_register_frontend);21112112int dvb_unregister_frontend(struct dvb_frontend* fe)2113{2114struct dvb_frontend_private *fepriv = fe->frontend_priv;2115dprintk ("%s\n", __func__);21162117mutex_lock(&frontend_mutex);2118dvb_frontend_stop (fe);2119mutex_unlock(&frontend_mutex);21202121if (fepriv->dvbdev->users < -1)2122wait_event(fepriv->dvbdev->wait_queue,2123fepriv->dvbdev->users==-1);21242125mutex_lock(&frontend_mutex);2126dvb_unregister_device (fepriv->dvbdev);21272128/* fe is invalid now */2129kfree(fepriv);2130mutex_unlock(&frontend_mutex);2131return 0;2132}2133EXPORT_SYMBOL(dvb_unregister_frontend);21342135#ifdef CONFIG_MEDIA_ATTACH2136void dvb_frontend_detach(struct dvb_frontend* fe)2137{2138void *ptr;21392140if (fe->ops.release_sec) {2141fe->ops.release_sec(fe);2142symbol_put_addr(fe->ops.release_sec);2143}2144if (fe->ops.tuner_ops.release) {2145fe->ops.tuner_ops.release(fe);2146symbol_put_addr(fe->ops.tuner_ops.release);2147}2148if (fe->ops.analog_ops.release) {2149fe->ops.analog_ops.release(fe);2150symbol_put_addr(fe->ops.analog_ops.release);2151}2152ptr = (void*)fe->ops.release;2153if (ptr) {2154fe->ops.release(fe);2155symbol_put_addr(ptr);2156}2157}2158#else2159void dvb_frontend_detach(struct dvb_frontend* fe)2160{2161if (fe->ops.release_sec)2162fe->ops.release_sec(fe);2163if (fe->ops.tuner_ops.release)2164fe->ops.tuner_ops.release(fe);2165if (fe->ops.analog_ops.release)2166fe->ops.analog_ops.release(fe);2167if (fe->ops.release)2168fe->ops.release(fe);2169}2170#endif2171EXPORT_SYMBOL(dvb_frontend_detach);217221732174