>>From 6a505dda50ecd5eddffdabb79a9a32ccaf9fe29b Mon Sep 17 00:00:00 2001 From: Manu Abraham Date: Thu, 4 Sep 2008 12:11:15 +0200 Subject: [PATCH] DVB Frontend API update: Frontend core support * Add support for the new datastuctures and ioctls, for the updated API From: Manu Abraham Signed-off-by: Manu Abraham diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 8cbdb21..da7283c 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -8,6 +8,7 @@ * for convergence integrated media GmbH * * Copyright (C) 2004 Andrew de Quincey (tuning thread cleanup) + * Copyright (C) Manu Abraham (Multi protocol support) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -95,7 +96,12 @@ struct dvb_frontend_private { /* thread/frontend values */ struct dvb_device *dvbdev; + /* Legacy datatype, superseded by dvbfe_params */ struct dvb_frontend_parameters parameters; + /* dvbfe_params supersedes dvb_frontend_parameters */ + struct dvbfe_params fe_params; + struct dvbfe_info fe_info; + struct dvb_fe_events events; struct semaphore sem; struct list_head list_head; @@ -124,10 +130,64 @@ struct dvb_frontend_private { unsigned int step_size; int quality; unsigned int check_wrapped; + + enum dvbfe_search algo_status; }; static void dvb_frontend_wakeup(struct dvb_frontend *fe); +struct modcod_table { + u32 dvbfe_modcod; + u32 dvbfe_modulation; + u32 dvbfe_fec; +}; + +static struct modcod_table dvbs2_modcod_lookup[] = { + { DVBFE_MODCOD_DUMMY_PLFRAME, DVBFE_MOD_NONE, DVBFE_FEC_NONE }, + { DVBFE_MODCOD_QPSK_1_4, DVBFE_MOD_QPSK, DVBFE_FEC_1_4 }, + { DVBFE_MODCOD_QPSK_1_3, DVBFE_MOD_QPSK, DVBFE_FEC_1_3 }, + { DVBFE_MODCOD_QPSK_2_5, DVBFE_MOD_QPSK, DVBFE_FEC_2_5 }, + { DVBFE_MODCOD_QPSK_1_2, DVBFE_MOD_QPSK, DVBFE_FEC_1_2 }, + { DVBFE_MODCOD_QPSK_3_5, DVBFE_MOD_QPSK, DVBFE_FEC_3_5 }, + { DVBFE_MODCOD_QPSK_2_3, DVBFE_MOD_QPSK, DVBFE_FEC_2_3 }, + { DVBFE_MODCOD_QPSK_3_4, DVBFE_MOD_QPSK, DVBFE_FEC_3_4 }, + { DVBFE_MODCOD_QPSK_4_5, DVBFE_MOD_QPSK, DVBFE_FEC_4_5 }, + { DVBFE_MODCOD_QPSK_5_6, DVBFE_MOD_QPSK, DVBFE_FEC_5_6 }, + { DVBFE_MODCOD_QPSK_8_9, DVBFE_MOD_QPSK, DVBFE_FEC_8_9 }, + { DVBFE_MODCOD_QPSK_9_10, DVBFE_MOD_QPSK, DVBFE_FEC_9_10 }, + { DVBFE_MODCOD_8PSK_3_5, DVBFE_MOD_8PSK, DVBFE_FEC_3_5 }, + { DVBFE_MODCOD_8PSK_2_3, DVBFE_MOD_8PSK, DVBFE_FEC_2_3 }, + { DVBFE_MODCOD_8PSK_3_4, DVBFE_MOD_8PSK, DVBFE_FEC_3_4 }, + { DVBFE_MODCOD_8PSK_5_6, DVBFE_MOD_8PSK, DVBFE_FEC_5_6 }, + { DVBFE_MODCOD_8PSK_8_9, DVBFE_MOD_8PSK, DVBFE_FEC_8_9 }, + { DVBFE_MODCOD_8PSK_9_10, DVBFE_MOD_8PSK, DVBFE_FEC_9_10 }, + { DVBFE_MODCOD_16APSK_2_3, DVBFE_MOD_16APSK, DVBFE_FEC_2_3 }, + { DVBFE_MODCOD_16APSK_3_4, DVBFE_MOD_16APSK, DVBFE_FEC_3_4 }, + { DVBFE_MODCOD_16APSK_4_5, DVBFE_MOD_16APSK, DVBFE_FEC_4_5 }, + { DVBFE_MODCOD_16APSK_5_6, DVBFE_MOD_16APSK, DVBFE_FEC_5_6 }, + { DVBFE_MODCOD_16APSK_8_9, DVBFE_MOD_16APSK, DVBFE_FEC_8_9 }, + { DVBFE_MODCOD_16APSK_9_10, DVBFE_MOD_16APSK, DVBFE_FEC_9_10 }, + { DVBFE_MODCOD_32APSK_3_4, DVBFE_MOD_32APSK, DVBFE_FEC_3_4 }, + { DVBFE_MODCOD_32APSK_4_5, DVBFE_MOD_32APSK, DVBFE_FEC_4_5 }, + { DVBFE_MODCOD_32APSK_5_6, DVBFE_MOD_32APSK, DVBFE_FEC_5_6 }, + { DVBFE_MODCOD_32APSK_8_9, DVBFE_MOD_32APSK, DVBFE_FEC_8_9 }, + { DVBFE_MODCOD_32APSK_9_10, DVBFE_MOD_32APSK, DVBFE_FEC_9_10 }, + { DVBFE_MODCOD_RESERVED_1, DVBFE_MOD_NONE, DVBFE_FEC_NONE }, + { DVBFE_MODCOD_BPSK_1_3, DVBFE_MOD_BPSK, DVBFE_FEC_1_3 }, + { DVBFE_MODCOD_BPSK_1_4, DVBFE_MOD_BPSK, DVBFE_FEC_1_4 }, + { DVBFE_MODCOD_RESERVED_2, DVBFE_MOD_NONE, DVBFE_FEC_NONE } +}; + +void decode_dvbs2_modcod(u32 dvbfe_modcod, + enum dvbfe_modulation *modulation, + enum dvbfe_fec *fec) +{ + BUG_ON(dvbfe_modcod >= ARRAY_SIZE(dvbs2_modcod_lookup)); + *modulation = dvbs2_modcod_lookup[dvbfe_modcod].dvbfe_modulation; + *fec = dvbs2_modcod_lookup[dvbfe_modcod].dvbfe_fec; +} +EXPORT_SYMBOL(decode_dvbs2_modcod); + static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status) { struct dvb_frontend_private *fepriv = fe->frontend_priv; @@ -149,12 +209,21 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status) e = &events->events[events->eventw]; - memcpy (&e->parameters, &fepriv->parameters, - sizeof (struct dvb_frontend_parameters)); + if (fe->legacy) + memcpy(&e->parameters, &fepriv->parameters, sizeof (struct dvb_frontend_parameters)); + else + memcpy(&e->fe_params, &fepriv->fe_params, sizeof (struct dvbfe_params)); - if (status & FE_HAS_LOCK) - if (fe->ops.get_frontend) - fe->ops.get_frontend(fe, &e->parameters); + if (fe->legacy) { + /* Legacy */ + if (status & FE_HAS_LOCK) + if (fe->ops.get_frontend) + fe->ops.get_frontend(fe, &e->parameters); + } else { + if (status & FE_HAS_LOCK) + if (fe->ops.get_params) + fe->ops.get_params(fe, &e->fe_params); + } events->eventw = wp; @@ -165,6 +234,73 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status) wake_up_interruptible (&events->wait_queue); } +static int dvbfe_sanity_check(struct dvb_frontend *fe) +{ + struct dvb_frontend_private *fepriv = fe->frontend_priv; + + /* Sanity checks */ + if ((fepriv->fe_params.frequency < fepriv->fe_info.frequency_min) || + (fepriv->fe_params.frequency > fepriv->fe_info.frequency_max)) + return -EINVAL; + + switch (fepriv->fe_params.delivery) { + case DVBFE_DELSYS_DVBS: + if (!(fepriv->fe_params.delsys.dvbs.modulation & + fepriv->fe_info.delsys.dvbs.modulation)) + return -EINVAL; + if (!(fepriv->fe_params.delsys.dvbs.fec & + fepriv->fe_info.delsys.dvbs.fec)) + return -EINVAL; + break; + case DVBFE_DELSYS_DVBS2: + if (!(fepriv->fe_params.delsys.dvbs2.modulation & + fepriv->fe_info.delsys.dvbs2.modulation)) + return -EINVAL; + if (!(fepriv->fe_params.delsys.dvbs2.fec & + fepriv->fe_info.delsys.dvbs2.fec)) + return -EINVAL; + break; + case DVBFE_DELSYS_DSS: + if (!(fepriv->fe_params.delsys.dss.modulation & + fepriv->fe_info.delsys.dss.modulation)) + return -EINVAL; + if (!(fepriv->fe_params.delsys.dss.fec & + fepriv->fe_info.delsys.dss.fec)) + return -EINVAL; + break; + case DVBFE_DELSYS_DVBC: + if (!(fepriv->fe_params.delsys.dvbc.modulation & + fepriv->fe_info.delsys.dvbc.modulation)) + return -EINVAL; + break; + case DVBFE_DELSYS_DVBT: + if (!(fepriv->fe_params.delsys.dvbt.constellation & + fepriv->fe_info.delsys.dvbt.modulation)) + return -EINVAL; + if (!(fepriv->fe_params.delsys.dvbt.priority & + fepriv->fe_info.delsys.dvbt.stream_priority)) + return -EINVAL; + break; + case DVBFE_DELSYS_DVBH: + if (!(fepriv->fe_params.delsys.dvbh.constellation & + fepriv->fe_info.delsys.dvbh.modulation)) + return -EINVAL; + if (!(fepriv->fe_params.delsys.dvbh.priority & + fepriv->fe_info.delsys.dvbh.stream_priority)) + return -EINVAL; + break; + case DVBFE_DELSYS_ATSC: + if (!(fepriv->fe_params.delsys.atsc.modulation & + fepriv->fe_info.delsys.atsc.modulation)) + return -EINVAL; + break; + default: + return -EINVAL; + } + + return 0; +} + static int dvb_frontend_get_event(struct dvb_frontend *fe, struct dvb_frontend_event *event, int flags) { @@ -261,13 +397,29 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra { int autoinversion; int ready = 0; + int original_inversion; + u32 original_frequency; + struct dvb_frontend_private *fepriv = fe->frontend_priv; - int original_inversion = fepriv->parameters.inversion; - u32 original_frequency = fepriv->parameters.frequency; - /* are we using autoinversion? */ - autoinversion = ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) && - (fepriv->parameters.inversion == INVERSION_AUTO)); + if (fe->legacy) { + /* Legacy */ + original_inversion = fepriv->parameters.inversion; + original_frequency = fepriv->parameters.frequency; + /* are we using autoinversion ? */ + /* Legacy */ + autoinversion = ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) && + (fepriv->parameters.inversion == INVERSION_AUTO)); + } else { + /* Superseding */ + original_inversion = fepriv->fe_params.inversion; + original_frequency = fepriv->fe_params.frequency; + if (fe->ops.get_info) { + fe->ops.get_info(fe, &fepriv->fe_info); + } + autoinversion = ((!(fepriv->fe_info.inversion & INVERSION_AUTO)) && + (fepriv->fe_params.inversion == INVERSION_AUTO)); + } /* setup parameters correctly */ while(!ready) { @@ -330,17 +482,46 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra dprintk("%s: drift:%i inversion:%i auto_step:%i " "auto_sub_step:%i started_auto_step:%i\n", __func__, fepriv->lnb_drift, fepriv->inversion, - fepriv->auto_step, fepriv->auto_sub_step, fepriv->started_auto_step); + fepriv->auto_step, fepriv->auto_sub_step, + fepriv->started_auto_step); - /* set the frontend itself */ - fepriv->parameters.frequency += fepriv->lnb_drift; - if (autoinversion) - fepriv->parameters.inversion = fepriv->inversion; - if (fe->ops.set_frontend) - fe->ops.set_frontend(fe, &fepriv->parameters); + /* set the frontend itself */ + /* Legacy */ + if (fe->legacy) + fepriv->parameters.frequency += fepriv->lnb_drift; + else + /* Supeseding */ + fepriv->fe_params.frequency += fepriv->lnb_drift; - fepriv->parameters.frequency = original_frequency; - fepriv->parameters.inversion = original_inversion; + if (autoinversion) { + /* Legacy */ + if (fe->legacy) + fepriv->parameters.inversion = fepriv->inversion; + else + /* Superseding */ + fepriv->fe_params.inversion = fepriv->inversion; + } + /* Legacy */ + if (fe->legacy) { + if (fe->ops.set_frontend) + fe->ops.set_frontend(fe, &fepriv->parameters); + } else { +// if ((dvbfe_sanity_check(fe) == 0)) { + /* Superseding */ + if (fe->ops.set_params) + fe->ops.set_params(fe, &fepriv->fe_params); +// } else +// return -EINVAL; + } + /* Legacy */ + if (fe->legacy) { + fepriv->parameters.frequency = original_frequency; + fepriv->parameters.inversion = original_inversion; + } else { + /* Superseding */ + fepriv->fe_params.frequency = original_frequency; + fepriv->fe_params.inversion = original_inversion; + } fepriv->auto_sub_step++; return 0; @@ -355,19 +536,30 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe) if (fepriv->state & FESTATE_IDLE) { fepriv->delay = 3*HZ; fepriv->quality = 0; - return; + return 0; } /* in SCAN mode, we just set the frontend when asked and leave it alone */ if (fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT) { if (fepriv->state & FESTATE_RETUNE) { - if (fe->ops.set_frontend) - fe->ops.set_frontend(fe, &fepriv->parameters); + + if (fe->legacy) { + /* Legacy */ + if (fe->ops.set_frontend) + fe->ops.set_frontend(fe, &fepriv->parameters); + } else { + if (dvbfe_sanity_check(fe) == 0) { + /* Superseding */ + if (fe->ops.set_params) + fe->ops.set_params(fe, &fepriv->fe_params); + } else + return -EINVAL; + } fepriv->state = FESTATE_TUNED; } fepriv->delay = 3*HZ; fepriv->quality = 0; - return; + return 0; } /* get the frontend status */ @@ -388,11 +580,22 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe) fepriv->state = FESTATE_TUNED; /* if we're tuned, then we have determined the correct inversion */ - if ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) && - (fepriv->parameters.inversion == INVERSION_AUTO)) { - fepriv->parameters.inversion = fepriv->inversion; + /* Legacy */ + if (fe->legacy) { + if ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) && + (fepriv->parameters.inversion == INVERSION_AUTO)) { + fepriv->parameters.inversion = fepriv->inversion; + } + } else { + /* Superseding */ + if (fe->ops.get_info) { + fe->ops.get_info(fe, &fepriv->fe_info); + if ((!(fepriv->fe_info.inversion & INVERSION_AUTO)) && + (fepriv->fe_params.inversion == INVERSION_AUTO)) + fepriv->fe_params.inversion = fepriv->inversion; + } } - return; + return 0; } /* if we are tuned already, check we're still locked */ @@ -401,7 +604,7 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe) /* we're tuned, and the lock is still good... */ if (s & FE_HAS_LOCK) { - return; + return 0; } else { /* if we _WERE_ tuned, but now don't have a lock */ fepriv->state = FESTATE_ZIGZAG_FAST; fepriv->started_auto_step = fepriv->auto_step; @@ -410,24 +613,43 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe) } /* don't actually do anything if we're in the LOSTLOCK state, - * the frontend is set to FE_CAN_RECOVER, and the max_drift is 0 */ - if ((fepriv->state & FESTATE_LOSTLOCK) && - (fe->ops.info.caps & FE_CAN_RECOVER) && (fepriv->max_drift == 0)) { - dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK); - return; + * the frontend is set to FE_CAN_RECOVER, and the max_drift is 0 + */ + /* Legacy */ + if (fe->legacy) { + if ((fepriv->state & FESTATE_LOSTLOCK) && (fepriv->max_drift == 0)) { + if (fe->ops.get_frontend_algo) + if (fe->ops.get_frontend_algo(fe) == DVBFE_ALGO_RECOVERY) + dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK); + + return 0; + } + } else { + if (fepriv->state & FESTATE_LOSTLOCK) { + if (fe->ops.get_frontend_algo) { + if ((fe->ops.get_frontend_algo(fe) == DVBFE_ALGO_RECOVERY) && + (fepriv->max_drift == 0)) { + + dvb_frontend_swzigzag_update_delay(fepriv, s & DVBFE_HAS_LOCK); + return 0; + } + } + } } /* don't do anything if we're in the DISEQC state, since this * might be someone with a motorized dish controlled by DISEQC. - * If its actually a re-tune, there will be a SET_FRONTEND soon enough. */ + * If its actually a re-tune, there will be a SET_FRONTEND soon enough. + */ if (fepriv->state & FESTATE_DISEQC) { dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK); - return; + return 0; } /* if we're in the RETUNE state, set everything up for a brand * new scan, keeping the current inversion setting, as the next - * tune is _very_ likely to require the same */ + * tune is _very_ likely to require the same + */ if (fepriv->state & FESTATE_RETUNE) { fepriv->lnb_drift = 0; fepriv->auto_step = 0; @@ -443,17 +665,19 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe) /* peform a tune */ if (dvb_frontend_swzigzag_autotune(fe, fepriv->check_wrapped)) { /* OK, if we've run out of trials at the fast speed. - * Drop back to slow for the _next_ attempt */ + * Drop back to slow for the _next_ attempt + */ fepriv->state = FESTATE_SEARCHING_SLOW; fepriv->started_auto_step = fepriv->auto_step; - return; + return 0; } fepriv->check_wrapped = 1; /* if we've just retuned, enter the ZIGZAG_FAST state. * This ensures we cannot return from an * FE_SET_FRONTEND ioctl before the first frontend tune - * occurs */ + * occurs + */ if (fepriv->state & FESTATE_RETUNE) { fepriv->state = FESTATE_TUNING_FAST; } @@ -464,9 +688,12 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe) dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK); /* Note: don't bother checking for wrapping; we stay in this - * state until we get a lock */ + * state until we get a lock + */ dvb_frontend_swzigzag_autotune(fe, 0); } + + return 0; } static int dvb_frontend_is_exiting(struct dvb_frontend *fe) @@ -509,7 +736,13 @@ static int dvb_frontend_thread(void *data) struct dvb_frontend_private *fepriv = fe->frontend_priv; unsigned long timeout; fe_status_t s; + + enum dvbfe_algo algo; + + /* Legacy datatype */ struct dvb_frontend_parameters *params; + /* Superseding datatype */ + struct dvbfe_params *fe_params = &fepriv->fe_params; dprintk("%s\n", __func__); @@ -555,23 +788,78 @@ restart: /* do an iteration of the tuning loop */ if (fe->ops.get_frontend_algo) { - if (fe->ops.get_frontend_algo(fe) == FE_ALGO_HW) { - /* have we been asked to retune? */ - params = NULL; + 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, FESTAT_RETUNE\n", __func__); params = &fepriv->parameters; fepriv->state = FESTATE_TUNED; } - - fe->ops.tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s); + if (fe->ops.tune) { + fe->ops.tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s); + dprintk("%s: TUNE callback exists at 0x%p\n", __func__, fe->ops.tune); + } if (s != fepriv->status) { + dprintk("%s: state changed, adding current state\n", __func__); dvb_frontend_add_event(fe, s); fepriv->status = s; } - } else + break; + case DVBFE_ALGO_SW: + dprintk("%s: Frontend ALGO = DVBFE_ALGO_SW\n", __func__); dvb_frontend_swzigzag(fe); - } else + 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__); + fe_params = &fepriv->fe_params; + 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, fe_params); + dprintk("%s: SEARCH callback exists at 0x%p\n", __func__, fe->ops.search); + /* We did do a search as was requested, the flags are + * now unset as well and has the flags wrt to search. + */ + } + fepriv->algo_status &= ~DVBFE_ALGO_SEARCH_AGAIN; + } + /* Track the carrier if the search was successful */ + if (fepriv->algo_status == DVBFE_ALGO_SEARCH_SUCCESS) { + if (fepriv->algo_status & DVBFE_ALGO_SEARCH_SUCCESS) + dprintk("%s: status = DVBFE_ALGO_SEARCH_SUCCESS\n", __func__); + if (fepriv->algo_status & DVBFE_ALGO_SEARCH_FAILED) + fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN; + + fe->ops.read_status(fe, &s); + dvb_frontend_add_event(fe, s); /* update event list */ + fepriv->status = s; + if (fe->ops.track) { + dprintk("%s: TRACK callback exists at 0x%p\n", __func__, fe->ops.track); + fe->ops.track(fe, fe_params); + } + } + break; + default: + dprintk("%s: UNDEFINED ALGO !\n", __func__); + break; + } + + } else { dvb_frontend_swzigzag(fe); + } } if (dvb_powerdown_on_sleep) { @@ -589,6 +877,7 @@ restart: fepriv->thread = NULL; mb(); + dprintk("%s: frontend_wakeup\n", __func__); dvb_frontend_wakeup(fe); return 0; } @@ -762,6 +1051,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, struct dvb_frontend *fe = dvbdev->priv; struct dvb_frontend_private *fepriv = fe->frontend_priv; int err = -EOPNOTSUPP; + enum dvbfe_delsys delsys = 0; dprintk ("%s\n", __func__); @@ -947,12 +1237,10 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, break; } - memcpy (&fepriv->parameters, parg, - sizeof (struct dvb_frontend_parameters)); - + fe->legacy = 1; + memcpy(&fepriv->parameters, parg, sizeof (struct dvb_frontend_parameters)); memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings)); - memcpy(&fetunesettings.parameters, parg, - sizeof (struct dvb_frontend_parameters)); + memcpy(&fetunesettings.parameters, parg, sizeof (struct dvb_frontend_parameters)); /* force auto frequency inversion if requested */ if (dvb_force_auto_inversion) { @@ -1015,6 +1303,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, break; case FE_GET_FRONTEND: + fe->legacy = 1; if (fe->ops.get_frontend) { memcpy (parg, &fepriv->parameters, sizeof (struct dvb_frontend_parameters)); err = fe->ops.get_frontend(fe, (struct dvb_frontend_parameters*) parg); @@ -1025,6 +1314,108 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, fepriv->tune_mode_flags = (unsigned long) parg; err = 0; break; + + case DVBFE_SET_PARAMS: { + struct dvb_frontend_tune_settings fetunesettings; + + fe->legacy = 0; + memcpy(&fepriv->fe_params, parg, sizeof (struct dvbfe_params)); + memset(&fetunesettings, 0, sizeof (struct dvb_frontend_tune_settings)); + memcpy(&fetunesettings.fe_params, parg, sizeof (struct dvbfe_params)); + + /* Request the search algorithm to search */ + fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN; + + /* force auto frequency inversion if requested */ + if (dvb_force_auto_inversion) { + fepriv->fe_params.inversion = DVBFE_INVERSION_AUTO; + fetunesettings.fe_params.inversion = DVBFE_INVERSION_AUTO; + } + if (fe->ops.get_delsys) { + fe->ops.get_delsys(fe, &delsys); + if ((delsys == DVBFE_DELSYS_DVBT) || + (delsys == DVBFE_DELSYS_DVBH)) { + + /* without hierachical coding code_rate_LP is irrelevant, + * so we tolerate the otherwise invalid FEC_NONE setting */ + if (fepriv->fe_params.delsys.dvbt.hierarchy == DVBFE_HIERARCHY_OFF && + fepriv->fe_params.delsys.dvbt.code_rate_LP == DVBFE_FEC_NONE) + + fepriv->fe_params.delsys.dvbt.code_rate_LP = DVBFE_FEC_AUTO; + } + } + + /* get frontend-specific tuning settings */ + if (fe->ops.get_tune_settings && + (fe->ops.get_tune_settings(fe, &fetunesettings) == 0)) { + + fepriv->min_delay = (fetunesettings.min_delay_ms * HZ) / 1000; + fepriv->max_drift = fetunesettings.max_drift; + fepriv->step_size = fetunesettings.step_size; + } else { + /* default values */ + switch (fepriv->fe_info.delivery) { + case DVBFE_DELSYS_DVBS: + case DVBFE_DELSYS_DSS: + case DVBFE_DELSYS_DVBS2: + fepriv->min_delay = HZ / 20; + fepriv->step_size = fepriv->fe_params.delsys.dvbs.symbol_rate / 16000; + fepriv->max_drift = fepriv->fe_params.delsys.dvbs.symbol_rate / 2000; + break; + case DVBFE_DELSYS_DVBC: + fepriv->min_delay = HZ / 20; + fepriv->step_size = 0; /* no zigzag */ + fepriv->max_drift = 0; + break; + case DVBFE_DELSYS_DVBT: + case DVBFE_DELSYS_DVBH: + fepriv->min_delay = HZ / 20; + fepriv->step_size = fepriv->fe_info.frequency_step * 2; + fepriv->max_drift = (fepriv->fe_info.frequency_step * 2) + 1; + break; + case DVBFE_DELSYS_ATSC: + fepriv->min_delay = HZ / 20; + fepriv->step_size = 0; + fepriv->max_drift = 0; + break; + default: + return -EINVAL; + } + } + if (dvb_override_tune_delay > 0) + fepriv->min_delay = (dvb_override_tune_delay * HZ) / 1000; + + fepriv->state = FESTATE_RETUNE; + printk("%s: FESTATE_RETUNE: fepriv->state=%d\n", __func__, fepriv->state); + dvb_frontend_wakeup(fe); + dvb_frontend_add_event(fe, 0); + fepriv->status = 0; + err = 0; + break; + } + + case DVBFE_GET_PARAMS: + fe->legacy = 0; + if (fe->ops.get_params) { + memcpy(parg, &fepriv->fe_params, sizeof (struct dvbfe_params)); + err = fe->ops.get_params(fe, (struct dvbfe_params *) parg); + } + break; + case DVBFE_GET_DELSYS: + fe->legacy = 0; + if (fe->ops.get_delsys) { + err = fe->ops.get_delsys(fe, (enum dvbfe_delsys *) parg); + } + break; + case DVBFE_GET_INFO: + printk("%s: DVBFE_GET_INFO\n", __func__); + fe->legacy = 0; + if (fe->ops.get_info) { + memcpy(&fepriv->fe_info, (struct dvbfe_info *) parg, sizeof (struct dvbfe_info)); + err = fe->ops.get_info(fe, &fepriv->fe_info); + memcpy((struct dvbfe_info *) parg, &fepriv->fe_info, sizeof (struct dvbfe_info)); + } + break; }; up (&fepriv->sem);