summaryrefslogtreecommitdiff
path: root/recipes/linux/linux-vusolo2-2.6.37/dvb-core.patch
diff options
context:
space:
mode:
Diffstat (limited to 'recipes/linux/linux-vusolo2-2.6.37/dvb-core.patch')
-rw-r--r--recipes/linux/linux-vusolo2-2.6.37/dvb-core.patch1330
1 files changed, 1330 insertions, 0 deletions
diff --git a/recipes/linux/linux-vusolo2-2.6.37/dvb-core.patch b/recipes/linux/linux-vusolo2-2.6.37/dvb-core.patch
new file mode 100644
index 0000000..87b1738
--- /dev/null
+++ b/recipes/linux/linux-vusolo2-2.6.37/dvb-core.patch
@@ -0,0 +1,1330 @@
+diff --git a/drivers/media/dvb/dvb-core/Makefile b/drivers/media/dvb/dvb-core/Makefile
+index 0b51828..8f22bcd 100644
+--- a/drivers/media/dvb/dvb-core/Makefile
++++ b/drivers/media/dvb/dvb-core/Makefile
+@@ -2,8 +2,10 @@
+ # Makefile for the kernel DVB device drivers.
+ #
+
++dvb-net-$(CONFIG_DVB_NET) := dvb_net.o
++
+ dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o \
+ dvb_ca_en50221.o dvb_frontend.o \
+- dvb_net.o dvb_ringbuffer.o dvb_math.o
++ $(dvb-net-y) dvb_ringbuffer.o dvb_math.o
+
+ obj-$(CONFIG_DVB_CORE) += dvb-core.o
+diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
+index ad1f61d..cb59681 100644
+--- a/drivers/media/dvb/dvb-core/dmxdev.c
++++ b/drivers/media/dvb/dvb-core/dmxdev.c
+@@ -83,7 +83,11 @@ static ssize_t dvb_dmxdev_buffer_read(struct dvb_ringbuffer *src,
+
+ ret = wait_event_interruptible(src->queue,
+ !dvb_ringbuffer_empty(src) ||
+- (src->error != 0));
++ (src->error != 0) ||
++ (src->do_wait != 1));
++ if (src->do_wait != 1)
++ ret = -EINTR;
++
+ if (ret < 0)
+ break;
+
+@@ -572,13 +576,13 @@ static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev,
+ dmx_output_t otype;
+ int ret;
+ int ts_type;
+- enum dmx_ts_pes ts_pes;
++ dmx_pes_type_t ts_pes;
+ struct dmx_ts_feed *tsfeed;
+
+ feed->ts = NULL;
+ otype = para->output;
+
+- ts_pes = (enum dmx_ts_pes)para->pes_type;
++ ts_pes = para->pes_type;
+
+ if (ts_pes < DMX_PES_OTHER)
+ ts_type = TS_DECODER;
+@@ -963,6 +967,22 @@ dvb_demux_read(struct file *file, char __user *buf, size_t count,
+ return ret;
+ }
+
++static int dvb_demux_lock_filter(struct dmxdev_filter *dmxdevfilter)
++{
++ int ret;
++
++ dmxdevfilter->buffer.do_wait = 0;
++
++ if (waitqueue_active(&dmxdevfilter->buffer.queue))
++ wake_up(&dmxdevfilter->buffer.queue);
++
++ ret = mutex_lock_interruptible(&dmxdevfilter->mutex);
++
++ dmxdevfilter->buffer.do_wait = 1;
++
++ return ret;
++}
++
+ static int dvb_demux_do_ioctl(struct file *file,
+ unsigned int cmd, void *parg)
+ {
+@@ -976,7 +996,7 @@ static int dvb_demux_do_ioctl(struct file *file,
+
+ switch (cmd) {
+ case DMX_START:
+- if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
++ if (dvb_demux_lock_filter(dmxdevfilter)) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ERESTARTSYS;
+ }
+@@ -988,7 +1008,7 @@ static int dvb_demux_do_ioctl(struct file *file,
+ break;
+
+ case DMX_STOP:
+- if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
++ if (dvb_demux_lock_filter(dmxdevfilter)) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ERESTARTSYS;
+ }
+@@ -997,7 +1017,7 @@ static int dvb_demux_do_ioctl(struct file *file,
+ break;
+
+ case DMX_SET_FILTER:
+- if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
++ if (dvb_demux_lock_filter(dmxdevfilter)) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ERESTARTSYS;
+ }
+@@ -1006,7 +1026,7 @@ static int dvb_demux_do_ioctl(struct file *file,
+ break;
+
+ case DMX_SET_PES_FILTER:
+- if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
++ if (dvb_demux_lock_filter(dmxdevfilter)) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ERESTARTSYS;
+ }
+@@ -1015,7 +1035,7 @@ static int dvb_demux_do_ioctl(struct file *file,
+ break;
+
+ case DMX_SET_BUFFER_SIZE:
+- if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
++ if (dvb_demux_lock_filter(dmxdevfilter)) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ERESTARTSYS;
+ }
+@@ -1059,7 +1079,7 @@ static int dvb_demux_do_ioctl(struct file *file,
+ break;
+
+ case DMX_ADD_PID:
+- if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
++ if (dvb_demux_lock_filter(dmxdevfilter)) {
+ ret = -ERESTARTSYS;
+ break;
+ }
+@@ -1068,7 +1088,7 @@ static int dvb_demux_do_ioctl(struct file *file,
+ break;
+
+ case DMX_REMOVE_PID:
+- if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
++ if (dvb_demux_lock_filter(dmxdevfilter)) {
+ ret = -ERESTARTSYS;
+ break;
+ }
+diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
+index 4a88a3e..faa3671 100644
+--- a/drivers/media/dvb/dvb-core/dvb_demux.c
++++ b/drivers/media/dvb/dvb-core/dvb_demux.c
+@@ -478,97 +478,94 @@ void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf,
+
+ EXPORT_SYMBOL(dvb_dmx_swfilter_packets);
+
+-void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count)
++static inline int find_next_packet(const u8 *buf, int pos, size_t count,
++ const int pktsize)
+ {
+- int p = 0, i, j;
++ int start = pos, lost;
+
+- spin_lock(&demux->lock);
+-
+- if (demux->tsbufp) {
+- i = demux->tsbufp;
+- j = 188 - i;
+- if (count < j) {
+- memcpy(&demux->tsbuf[i], buf, count);
+- demux->tsbufp += count;
+- goto bailout;
+- }
+- memcpy(&demux->tsbuf[i], buf, j);
+- if (demux->tsbuf[0] == 0x47)
+- dvb_dmx_swfilter_packet(demux, demux->tsbuf);
+- demux->tsbufp = 0;
+- p += j;
++ while (pos < count) {
++ if (buf[pos] == 0x47 ||
++ (pktsize == 204 && buf[pos] == 0xB8))
++ break;
++ pos++;
+ }
+
+- while (p < count) {
+- if (buf[p] == 0x47) {
+- if (count - p >= 188) {
+- dvb_dmx_swfilter_packet(demux, &buf[p]);
+- p += 188;
+- } else {
+- i = count - p;
+- memcpy(demux->tsbuf, &buf[p], i);
+- demux->tsbufp = i;
+- goto bailout;
+- }
+- } else
+- p++;
++ lost = pos - start;
++ if (lost) {
++ /* This garbage is part of a valid packet? */
++ int backtrack = pos - pktsize;
++ if (backtrack >= 0 && (buf[backtrack] == 0x47 ||
++ (pktsize == 204 && buf[backtrack] == 0xB8)))
++ return backtrack;
+ }
+
+-bailout:
+- spin_unlock(&demux->lock);
++ return pos;
+ }
+
+-EXPORT_SYMBOL(dvb_dmx_swfilter);
+-
+-void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count)
++/* Filter all pktsize= 188 or 204 sized packets and skip garbage. */
++static inline void _dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf,
++ size_t count, const int pktsize)
+ {
+ int p = 0, i, j;
+- u8 tmppack[188];
++ const u8 *q;
+
+ spin_lock(&demux->lock);
+
+- if (demux->tsbufp) {
++ if (demux->tsbufp) { /* tsbuf[0] is now 0x47. */
+ i = demux->tsbufp;
+- j = 204 - i;
++ j = pktsize - i;
+ if (count < j) {
+ memcpy(&demux->tsbuf[i], buf, count);
+ demux->tsbufp += count;
+ goto bailout;
+ }
+ memcpy(&demux->tsbuf[i], buf, j);
+- if ((demux->tsbuf[0] == 0x47) || (demux->tsbuf[0] == 0xB8)) {
+- memcpy(tmppack, demux->tsbuf, 188);
+- if (tmppack[0] == 0xB8)
+- tmppack[0] = 0x47;
+- dvb_dmx_swfilter_packet(demux, tmppack);
+- }
++ if (demux->tsbuf[0] == 0x47) /* double check */
++ dvb_dmx_swfilter_packet(demux, demux->tsbuf);
+ demux->tsbufp = 0;
+ p += j;
+ }
+
+- while (p < count) {
+- if ((buf[p] == 0x47) || (buf[p] == 0xB8)) {
+- if (count - p >= 204) {
+- memcpy(tmppack, &buf[p], 188);
+- if (tmppack[0] == 0xB8)
+- tmppack[0] = 0x47;
+- dvb_dmx_swfilter_packet(demux, tmppack);
+- p += 204;
+- } else {
+- i = count - p;
+- memcpy(demux->tsbuf, &buf[p], i);
+- demux->tsbufp = i;
+- goto bailout;
+- }
+- } else {
+- p++;
++ while (1) {
++ p = find_next_packet(buf, p, count, pktsize);
++ if (p >= count)
++ break;
++ if (count - p < pktsize)
++ break;
++
++ q = &buf[p];
++
++ if (pktsize == 204 && (*q == 0xB8)) {
++ memcpy(demux->tsbuf, q, 188);
++ demux->tsbuf[0] = 0x47;
++ q = demux->tsbuf;
+ }
++ dvb_dmx_swfilter_packet(demux, q);
++ p += pktsize;
++ }
++
++ i = count - p;
++ if (i) {
++ memcpy(demux->tsbuf, &buf[p], i);
++ demux->tsbufp = i;
++ if (pktsize == 204 && demux->tsbuf[0] == 0xB8)
++ demux->tsbuf[0] = 0x47;
+ }
+
+ bailout:
+ spin_unlock(&demux->lock);
+ }
+
++void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count)
++{
++ _dvb_dmx_swfilter(demux, buf, count, 188);
++}
++EXPORT_SYMBOL(dvb_dmx_swfilter);
++
++void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count)
++{
++ _dvb_dmx_swfilter(demux, buf, count, 204);
++}
+ EXPORT_SYMBOL(dvb_dmx_swfilter_204);
+
+ static struct dvb_demux_filter *dvb_dmx_filter_alloc(struct dvb_demux *demux)
+diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
+index cad6634..efe9c30 100644
+--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
++++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
+@@ -105,7 +105,8 @@ struct dvb_frontend_private {
+
+ /* thread/frontend values */
+ struct dvb_device *dvbdev;
+- struct dvb_frontend_parameters parameters;
++ struct dvb_frontend_parameters parameters_in;
++ struct dvb_frontend_parameters parameters_out;
+ struct dvb_fe_events events;
+ struct semaphore sem;
+ struct list_head list_head;
+@@ -160,12 +161,11 @@ 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 (status & FE_HAS_LOCK)
+ if (fe->ops.get_frontend)
+- fe->ops.get_frontend(fe, &e->parameters);
++ fe->ops.get_frontend(fe, &fepriv->parameters_out);
++
++ e->parameters = fepriv->parameters_out;
+
+ events->eventw = wp;
+
+@@ -277,12 +277,12 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra
+ int ready = 0;
+ int fe_set_err = 0;
+ struct dvb_frontend_private *fepriv = fe->frontend_priv;
+- int original_inversion = fepriv->parameters.inversion;
+- u32 original_frequency = fepriv->parameters.frequency;
++ int original_inversion = fepriv->parameters_in.inversion;
++ u32 original_frequency = fepriv->parameters_in.frequency;
+
+ /* are we using autoinversion? */
+ autoinversion = ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) &&
+- (fepriv->parameters.inversion == INVERSION_AUTO));
++ (fepriv->parameters_in.inversion == INVERSION_AUTO));
+
+ /* setup parameters correctly */
+ while(!ready) {
+@@ -348,18 +348,19 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra
+ fepriv->auto_step, fepriv->auto_sub_step, fepriv->started_auto_step);
+
+ /* set the frontend itself */
+- fepriv->parameters.frequency += fepriv->lnb_drift;
++ fepriv->parameters_in.frequency += fepriv->lnb_drift;
+ if (autoinversion)
+- fepriv->parameters.inversion = fepriv->inversion;
++ fepriv->parameters_in.inversion = fepriv->inversion;
+ if (fe->ops.set_frontend)
+- fe_set_err = fe->ops.set_frontend(fe, &fepriv->parameters);
++ fe_set_err = fe->ops.set_frontend(fe, &fepriv->parameters_in);
++ fepriv->parameters_out = fepriv->parameters_in;
+ if (fe_set_err < 0) {
+ fepriv->state = FESTATE_ERROR;
+ return fe_set_err;
+ }
+
+- fepriv->parameters.frequency = original_frequency;
+- fepriv->parameters.inversion = original_inversion;
++ fepriv->parameters_in.frequency = original_frequency;
++ fepriv->parameters_in.inversion = original_inversion;
+
+ fepriv->auto_sub_step++;
+ return 0;
+@@ -383,7 +384,8 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
+ if (fepriv->state & FESTATE_RETUNE) {
+ if (fe->ops.set_frontend)
+ retval = fe->ops.set_frontend(fe,
+- &fepriv->parameters);
++ &fepriv->parameters_in);
++ fepriv->parameters_out = fepriv->parameters_in;
+ if (retval < 0)
+ fepriv->state = FESTATE_ERROR;
+ else
+@@ -413,8 +415,8 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
+
+ /* 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;
++ (fepriv->parameters_in.inversion == INVERSION_AUTO)) {
++ fepriv->parameters_in.inversion = fepriv->inversion;
+ }
+ return;
+ }
+@@ -594,12 +596,14 @@ restart:
+
+ if (fepriv->state & FESTATE_RETUNE) {
+ dprintk("%s: Retune requested, FESTATE_RETUNE\n", __func__);
+- params = &fepriv->parameters;
++ params = &fepriv->parameters_in;
+ fepriv->state = FESTATE_TUNED;
+ }
+
+ if (fe->ops.tune)
+ fe->ops.tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s);
++ if (params)
++ fepriv->parameters_out = *params;
+
+ if (s != fepriv->status && !(fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT)) {
+ dprintk("%s: state changed, adding current state\n", __func__);
+@@ -612,11 +616,9 @@ restart:
+ 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__);
+- params = &fepriv->parameters;
+ fepriv->state = FESTATE_TUNED;
+ }
+ /* Case where we are going to search for a carrier
+@@ -625,7 +627,7 @@ restart:
+ */
+ if (fepriv->algo_status & DVBFE_ALGO_SEARCH_AGAIN) {
+ if (fe->ops.search) {
+- fepriv->algo_status = fe->ops.search(fe, &fepriv->parameters);
++ fepriv->algo_status = fe->ops.search(fe, &fepriv->parameters_in);
+ /* We did do a search as was requested, the flags are
+ * now unset as well and has the flags wrt to search.
+ */
+@@ -636,11 +638,12 @@ restart:
+ /* 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);
++ fe->ops.track(fe, &fepriv->parameters_in);
+ } else {
+ fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
+ fepriv->delay = HZ / 2;
+ }
++ fepriv->parameters_out = fepriv->parameters_in;
+ fe->ops.read_status(fe, &s);
+ if (s != fepriv->status) {
+ dvb_frontend_add_event(fe, s); /* update event list */
+@@ -860,34 +863,34 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe,
+
+ static int dvb_frontend_clear_cache(struct dvb_frontend *fe)
+ {
++ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int i;
+
+- memset(&(fe->dtv_property_cache), 0,
+- sizeof(struct dtv_frontend_properties));
+-
+- fe->dtv_property_cache.state = DTV_CLEAR;
+- fe->dtv_property_cache.delivery_system = SYS_UNDEFINED;
+- fe->dtv_property_cache.inversion = INVERSION_AUTO;
+- fe->dtv_property_cache.fec_inner = FEC_AUTO;
+- fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_AUTO;
+- fe->dtv_property_cache.bandwidth_hz = BANDWIDTH_AUTO;
+- fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_AUTO;
+- fe->dtv_property_cache.hierarchy = HIERARCHY_AUTO;
+- fe->dtv_property_cache.symbol_rate = QAM_AUTO;
+- fe->dtv_property_cache.code_rate_HP = FEC_AUTO;
+- fe->dtv_property_cache.code_rate_LP = FEC_AUTO;
+-
+- fe->dtv_property_cache.isdbt_partial_reception = -1;
+- fe->dtv_property_cache.isdbt_sb_mode = -1;
+- fe->dtv_property_cache.isdbt_sb_subchannel = -1;
+- fe->dtv_property_cache.isdbt_sb_segment_idx = -1;
+- fe->dtv_property_cache.isdbt_sb_segment_count = -1;
+- fe->dtv_property_cache.isdbt_layer_enabled = 0x7;
++ memset(c, 0, sizeof(struct dtv_frontend_properties));
++
++ c->state = DTV_CLEAR;
++ c->delivery_system = SYS_UNDEFINED;
++ c->inversion = INVERSION_AUTO;
++ c->fec_inner = FEC_AUTO;
++ c->transmission_mode = TRANSMISSION_MODE_AUTO;
++ c->bandwidth_hz = BANDWIDTH_AUTO;
++ c->guard_interval = GUARD_INTERVAL_AUTO;
++ c->hierarchy = HIERARCHY_AUTO;
++ c->symbol_rate = QAM_AUTO;
++ c->code_rate_HP = FEC_AUTO;
++ c->code_rate_LP = FEC_AUTO;
++
++ c->isdbt_partial_reception = -1;
++ c->isdbt_sb_mode = -1;
++ c->isdbt_sb_subchannel = -1;
++ c->isdbt_sb_segment_idx = -1;
++ c->isdbt_sb_segment_count = -1;
++ c->isdbt_layer_enabled = 0x7;
+ for (i = 0; i < 3; i++) {
+- fe->dtv_property_cache.layer[i].fec = FEC_AUTO;
+- fe->dtv_property_cache.layer[i].modulation = QAM_AUTO;
+- fe->dtv_property_cache.layer[i].interleaving = -1;
+- fe->dtv_property_cache.layer[i].segment_count = -1;
++ c->layer[i].fec = FEC_AUTO;
++ c->layer[i].modulation = QAM_AUTO;
++ c->layer[i].interleaving = -1;
++ c->layer[i].segment_count = -1;
+ }
+
+ return 0;
+@@ -901,7 +904,7 @@ static int dvb_frontend_clear_cache(struct dvb_frontend *fe)
+ .buffer = b \
+ }
+
+-static struct dtv_cmds_h dtv_cmds[] = {
++static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = {
+ _DTV_CMD(DTV_TUNE, 1, 0),
+ _DTV_CMD(DTV_CLEAR, 1, 0),
+
+@@ -963,6 +966,7 @@ static struct dtv_cmds_h dtv_cmds[] = {
+ _DTV_CMD(DTV_ISDBT_LAYERC_TIME_INTERLEAVING, 0, 0),
+
+ _DTV_CMD(DTV_ISDBS_TS_ID, 1, 0),
++ _DTV_CMD(DTV_DVBT2_PLP_ID, 1, 0),
+
+ /* Get */
+ _DTV_CMD(DTV_DISEQC_SLAVE_REPLY, 0, 1),
+@@ -1020,10 +1024,9 @@ static int is_legacy_delivery_system(fe_delivery_system_t s)
+ * it's being used for the legacy or new API, reducing code and complexity.
+ */
+ static void dtv_property_cache_sync(struct dvb_frontend *fe,
+- struct dvb_frontend_parameters *p)
++ struct dtv_frontend_properties *c,
++ const struct dvb_frontend_parameters *p)
+ {
+- struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+-
+ c->frequency = p->frequency;
+ c->inversion = p->inversion;
+
+@@ -1074,9 +1077,9 @@ static void dtv_property_cache_sync(struct dvb_frontend *fe,
+ */
+ static void dtv_property_legacy_params_sync(struct dvb_frontend *fe)
+ {
+- struct dtv_frontend_properties *c = &fe->dtv_property_cache;
++ const struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ struct dvb_frontend_private *fepriv = fe->frontend_priv;
+- struct dvb_frontend_parameters *p = &fepriv->parameters;
++ struct dvb_frontend_parameters *p = &fepriv->parameters_in;
+
+ p->frequency = c->frequency;
+ p->inversion = c->inversion;
+@@ -1086,14 +1089,12 @@ static void dtv_property_legacy_params_sync(struct dvb_frontend *fe)
+ dprintk("%s() Preparing QPSK req\n", __func__);
+ p->u.qpsk.symbol_rate = c->symbol_rate;
+ p->u.qpsk.fec_inner = c->fec_inner;
+- c->delivery_system = SYS_DVBS;
+ break;
+ case FE_QAM:
+ dprintk("%s() Preparing QAM req\n", __func__);
+ p->u.qam.symbol_rate = c->symbol_rate;
+ p->u.qam.fec_inner = c->fec_inner;
+ p->u.qam.modulation = c->modulation;
+- c->delivery_system = SYS_DVBC_ANNEX_AC;
+ break;
+ case FE_OFDM:
+ dprintk("%s() Preparing OFDM req\n", __func__);
+@@ -1111,15 +1112,10 @@ static void dtv_property_legacy_params_sync(struct dvb_frontend *fe)
+ p->u.ofdm.transmission_mode = c->transmission_mode;
+ p->u.ofdm.guard_interval = c->guard_interval;
+ p->u.ofdm.hierarchy_information = c->hierarchy;
+- c->delivery_system = SYS_DVBT;
+ break;
+ case FE_ATSC:
+ dprintk("%s() Preparing VSB req\n", __func__);
+ p->u.vsb.modulation = c->modulation;
+- if ((c->modulation == VSB_8) || (c->modulation == VSB_16))
+- c->delivery_system = SYS_ATSC;
+- else
+- c->delivery_system = SYS_DVBC_ANNEX_B;
+ break;
+ }
+ }
+@@ -1129,9 +1125,9 @@ static void dtv_property_legacy_params_sync(struct dvb_frontend *fe)
+ */
+ static void dtv_property_adv_params_sync(struct dvb_frontend *fe)
+ {
+- struct dtv_frontend_properties *c = &fe->dtv_property_cache;
++ const struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ struct dvb_frontend_private *fepriv = fe->frontend_priv;
+- struct dvb_frontend_parameters *p = &fepriv->parameters;
++ struct dvb_frontend_parameters *p = &fepriv->parameters_in;
+
+ p->frequency = c->frequency;
+ p->inversion = c->inversion;
+@@ -1148,10 +1144,9 @@ static void dtv_property_adv_params_sync(struct dvb_frontend *fe)
+ break;
+ }
+
+- if(c->delivery_system == SYS_ISDBT) {
+- /* Fake out a generic DVB-T request so we pass validation in the ioctl */
+- p->frequency = c->frequency;
+- p->inversion = c->inversion;
++ /* Fake out a generic DVB-T request so we pass validation in the ioctl */
++ if ((c->delivery_system == SYS_ISDBT) ||
++ (c->delivery_system == SYS_DVBT2)) {
+ p->u.ofdm.constellation = QAM_AUTO;
+ p->u.ofdm.code_rate_HP = FEC_AUTO;
+ p->u.ofdm.code_rate_LP = FEC_AUTO;
+@@ -1171,7 +1166,7 @@ static void dtv_property_adv_params_sync(struct dvb_frontend *fe)
+
+ static void dtv_property_cache_submit(struct dvb_frontend *fe)
+ {
+- struct dtv_frontend_properties *c = &fe->dtv_property_cache;
++ const struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
+ /* For legacy delivery systems we don't need the delivery_system to
+ * be specified, but we populate the older structures from the cache
+@@ -1204,133 +1199,149 @@ static int dtv_property_process_get(struct dvb_frontend *fe,
+ struct dtv_property *tvp,
+ struct file *file)
+ {
+- int r = 0;
+-
+- /* Allow the frontend to validate incoming properties */
+- if (fe->ops.get_property)
+- r = fe->ops.get_property(fe, tvp);
++ const struct dtv_frontend_properties *c = &fe->dtv_property_cache;
++ struct dvb_frontend_private *fepriv = fe->frontend_priv;
++ struct dtv_frontend_properties cdetected;
++ int r;
+
+- if (r < 0)
+- return r;
++ /*
++ * If the driver implements a get_frontend function, then convert
++ * detected parameters to S2API properties.
++ */
++ if (fe->ops.get_frontend) {
++ cdetected = *c;
++ dtv_property_cache_sync(fe, &cdetected, &fepriv->parameters_out);
++ c = &cdetected;
++ }
+
+ switch(tvp->cmd) {
+ case DTV_FREQUENCY:
+- tvp->u.data = fe->dtv_property_cache.frequency;
++ tvp->u.data = c->frequency;
+ break;
+ case DTV_MODULATION:
+- tvp->u.data = fe->dtv_property_cache.modulation;
++ tvp->u.data = c->modulation;
+ break;
+ case DTV_BANDWIDTH_HZ:
+- tvp->u.data = fe->dtv_property_cache.bandwidth_hz;
++ tvp->u.data = c->bandwidth_hz;
+ break;
+ case DTV_INVERSION:
+- tvp->u.data = fe->dtv_property_cache.inversion;
++ tvp->u.data = c->inversion;
+ break;
+ case DTV_SYMBOL_RATE:
+- tvp->u.data = fe->dtv_property_cache.symbol_rate;
++ tvp->u.data = c->symbol_rate;
+ break;
+ case DTV_INNER_FEC:
+- tvp->u.data = fe->dtv_property_cache.fec_inner;
++ tvp->u.data = c->fec_inner;
+ break;
+ case DTV_PILOT:
+- tvp->u.data = fe->dtv_property_cache.pilot;
++ tvp->u.data = c->pilot;
+ break;
+ case DTV_ROLLOFF:
+- tvp->u.data = fe->dtv_property_cache.rolloff;
++ tvp->u.data = c->rolloff;
+ break;
+ case DTV_DELIVERY_SYSTEM:
+- tvp->u.data = fe->dtv_property_cache.delivery_system;
++ tvp->u.data = c->delivery_system;
+ break;
+ case DTV_VOLTAGE:
+- tvp->u.data = fe->dtv_property_cache.voltage;
++ tvp->u.data = c->voltage;
+ break;
+ case DTV_TONE:
+- tvp->u.data = fe->dtv_property_cache.sectone;
++ tvp->u.data = c->sectone;
+ break;
+ case DTV_API_VERSION:
+ tvp->u.data = (DVB_API_VERSION << 8) | DVB_API_VERSION_MINOR;
+ break;
+ case DTV_CODE_RATE_HP:
+- tvp->u.data = fe->dtv_property_cache.code_rate_HP;
++ tvp->u.data = c->code_rate_HP;
+ break;
+ case DTV_CODE_RATE_LP:
+- tvp->u.data = fe->dtv_property_cache.code_rate_LP;
++ tvp->u.data = c->code_rate_LP;
+ break;
+ case DTV_GUARD_INTERVAL:
+- tvp->u.data = fe->dtv_property_cache.guard_interval;
++ tvp->u.data = c->guard_interval;
+ break;
+ case DTV_TRANSMISSION_MODE:
+- tvp->u.data = fe->dtv_property_cache.transmission_mode;
++ tvp->u.data = c->transmission_mode;
+ break;
+ case DTV_HIERARCHY:
+- tvp->u.data = fe->dtv_property_cache.hierarchy;
++ tvp->u.data = c->hierarchy;
+ break;
+
+ /* ISDB-T Support here */
+ case DTV_ISDBT_PARTIAL_RECEPTION:
+- tvp->u.data = fe->dtv_property_cache.isdbt_partial_reception;
++ tvp->u.data = c->isdbt_partial_reception;
+ break;
+ case DTV_ISDBT_SOUND_BROADCASTING:
+- tvp->u.data = fe->dtv_property_cache.isdbt_sb_mode;
++ tvp->u.data = c->isdbt_sb_mode;
+ break;
+ case DTV_ISDBT_SB_SUBCHANNEL_ID:
+- tvp->u.data = fe->dtv_property_cache.isdbt_sb_subchannel;
++ tvp->u.data = c->isdbt_sb_subchannel;
+ break;
+ case DTV_ISDBT_SB_SEGMENT_IDX:
+- tvp->u.data = fe->dtv_property_cache.isdbt_sb_segment_idx;
++ tvp->u.data = c->isdbt_sb_segment_idx;
+ break;
+ case DTV_ISDBT_SB_SEGMENT_COUNT:
+- tvp->u.data = fe->dtv_property_cache.isdbt_sb_segment_count;
++ tvp->u.data = c->isdbt_sb_segment_count;
+ break;
+ case DTV_ISDBT_LAYER_ENABLED:
+- tvp->u.data = fe->dtv_property_cache.isdbt_layer_enabled;
++ tvp->u.data = c->isdbt_layer_enabled;
+ break;
+ case DTV_ISDBT_LAYERA_FEC:
+- tvp->u.data = fe->dtv_property_cache.layer[0].fec;
++ tvp->u.data = c->layer[0].fec;
+ break;
+ case DTV_ISDBT_LAYERA_MODULATION:
+- tvp->u.data = fe->dtv_property_cache.layer[0].modulation;
++ tvp->u.data = c->layer[0].modulation;
+ break;
+ case DTV_ISDBT_LAYERA_SEGMENT_COUNT:
+- tvp->u.data = fe->dtv_property_cache.layer[0].segment_count;
++ tvp->u.data = c->layer[0].segment_count;
+ break;
+ case DTV_ISDBT_LAYERA_TIME_INTERLEAVING:
+- tvp->u.data = fe->dtv_property_cache.layer[0].interleaving;
++ tvp->u.data = c->layer[0].interleaving;
+ break;
+ case DTV_ISDBT_LAYERB_FEC:
+- tvp->u.data = fe->dtv_property_cache.layer[1].fec;
++ tvp->u.data = c->layer[1].fec;
+ break;
+ case DTV_ISDBT_LAYERB_MODULATION:
+- tvp->u.data = fe->dtv_property_cache.layer[1].modulation;
++ tvp->u.data = c->layer[1].modulation;
+ break;
+ case DTV_ISDBT_LAYERB_SEGMENT_COUNT:
+- tvp->u.data = fe->dtv_property_cache.layer[1].segment_count;
++ tvp->u.data = c->layer[1].segment_count;
+ break;
+ case DTV_ISDBT_LAYERB_TIME_INTERLEAVING:
+- tvp->u.data = fe->dtv_property_cache.layer[1].interleaving;
++ tvp->u.data = c->layer[1].interleaving;
+ break;
+ case DTV_ISDBT_LAYERC_FEC:
+- tvp->u.data = fe->dtv_property_cache.layer[2].fec;
++ tvp->u.data = c->layer[2].fec;
+ break;
+ case DTV_ISDBT_LAYERC_MODULATION:
+- tvp->u.data = fe->dtv_property_cache.layer[2].modulation;
++ tvp->u.data = c->layer[2].modulation;
+ break;
+ case DTV_ISDBT_LAYERC_SEGMENT_COUNT:
+- tvp->u.data = fe->dtv_property_cache.layer[2].segment_count;
++ tvp->u.data = c->layer[2].segment_count;
+ break;
+ case DTV_ISDBT_LAYERC_TIME_INTERLEAVING:
+- tvp->u.data = fe->dtv_property_cache.layer[2].interleaving;
++ tvp->u.data = c->layer[2].interleaving;
+ break;
+ case DTV_ISDBS_TS_ID:
+- tvp->u.data = fe->dtv_property_cache.isdbs_ts_id;
++ tvp->u.data = c->isdbs_ts_id;
++ break;
++ case DTV_DVBT2_PLP_ID:
++ tvp->u.data = c->dvbt2_plp_id;
+ break;
+ default:
+- r = -1;
++ return -EINVAL;
++ }
++
++ /* Allow the frontend to override outgoing properties */
++ if (fe->ops.get_property) {
++ r = fe->ops.get_property(fe, tvp);
++ if (r < 0)
++ return r;
+ }
+
+ dtv_property_dump(tvp);
+
+- return r;
++ return 0;
+ }
+
+ static int dtv_property_process_set(struct dvb_frontend *fe,
+@@ -1338,15 +1349,16 @@ static int dtv_property_process_set(struct dvb_frontend *fe,
+ struct file *file)
+ {
+ int r = 0;
++ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ struct dvb_frontend_private *fepriv = fe->frontend_priv;
+ dtv_property_dump(tvp);
+
+ /* Allow the frontend to validate incoming properties */
+- if (fe->ops.set_property)
++ if (fe->ops.set_property) {
+ r = fe->ops.set_property(fe, tvp);
+-
+- if (r < 0)
+- return r;
++ if (r < 0)
++ return r;
++ }
+
+ switch(tvp->cmd) {
+ case DTV_CLEAR:
+@@ -1361,126 +1373,129 @@ static int dtv_property_process_set(struct dvb_frontend *fe,
+ * tunerequest so we can pass validation in the FE_SET_FRONTEND
+ * ioctl.
+ */
+- fe->dtv_property_cache.state = tvp->cmd;
++ c->state = tvp->cmd;
+ dprintk("%s() Finalised property cache\n", __func__);
+ dtv_property_cache_submit(fe);
+
+- r |= dvb_frontend_ioctl_legacy(file, FE_SET_FRONTEND,
+- &fepriv->parameters);
++ r = dvb_frontend_ioctl_legacy(file, FE_SET_FRONTEND,
++ &fepriv->parameters_in);
+ break;
+ case DTV_FREQUENCY:
+- fe->dtv_property_cache.frequency = tvp->u.data;
++ c->frequency = tvp->u.data;
+ break;
+ case DTV_MODULATION:
+- fe->dtv_property_cache.modulation = tvp->u.data;
++ c->modulation = tvp->u.data;
+ break;
+ case DTV_BANDWIDTH_HZ:
+- fe->dtv_property_cache.bandwidth_hz = tvp->u.data;
++ c->bandwidth_hz = tvp->u.data;
+ break;
+ case DTV_INVERSION:
+- fe->dtv_property_cache.inversion = tvp->u.data;
++ c->inversion = tvp->u.data;
+ break;
+ case DTV_SYMBOL_RATE:
+- fe->dtv_property_cache.symbol_rate = tvp->u.data;
++ c->symbol_rate = tvp->u.data;
+ break;
+ case DTV_INNER_FEC:
+- fe->dtv_property_cache.fec_inner = tvp->u.data;
++ c->fec_inner = tvp->u.data;
+ break;
+ case DTV_PILOT:
+- fe->dtv_property_cache.pilot = tvp->u.data;
++ c->pilot = tvp->u.data;
+ break;
+ case DTV_ROLLOFF:
+- fe->dtv_property_cache.rolloff = tvp->u.data;
++ c->rolloff = tvp->u.data;
+ break;
+ case DTV_DELIVERY_SYSTEM:
+- fe->dtv_property_cache.delivery_system = tvp->u.data;
++ c->delivery_system = tvp->u.data;
+ break;
+ case DTV_VOLTAGE:
+- fe->dtv_property_cache.voltage = tvp->u.data;
++ c->voltage = tvp->u.data;
+ r = dvb_frontend_ioctl_legacy(file, FE_SET_VOLTAGE,
+- (void *)fe->dtv_property_cache.voltage);
++ (void *)c->voltage);
+ break;
+ case DTV_TONE:
+- fe->dtv_property_cache.sectone = tvp->u.data;
++ c->sectone = tvp->u.data;
+ r = dvb_frontend_ioctl_legacy(file, FE_SET_TONE,
+- (void *)fe->dtv_property_cache.sectone);
++ (void *)c->sectone);
+ break;
+ case DTV_CODE_RATE_HP:
+- fe->dtv_property_cache.code_rate_HP = tvp->u.data;
++ c->code_rate_HP = tvp->u.data;
+ break;
+ case DTV_CODE_RATE_LP:
+- fe->dtv_property_cache.code_rate_LP = tvp->u.data;
++ c->code_rate_LP = tvp->u.data;
+ break;
+ case DTV_GUARD_INTERVAL:
+- fe->dtv_property_cache.guard_interval = tvp->u.data;
++ c->guard_interval = tvp->u.data;
+ break;
+ case DTV_TRANSMISSION_MODE:
+- fe->dtv_property_cache.transmission_mode = tvp->u.data;
++ c->transmission_mode = tvp->u.data;
+ break;
+ case DTV_HIERARCHY:
+- fe->dtv_property_cache.hierarchy = tvp->u.data;
++ c->hierarchy = tvp->u.data;
+ break;
+
+ /* ISDB-T Support here */
+ case DTV_ISDBT_PARTIAL_RECEPTION:
+- fe->dtv_property_cache.isdbt_partial_reception = tvp->u.data;
++ c->isdbt_partial_reception = tvp->u.data;
+ break;
+ case DTV_ISDBT_SOUND_BROADCASTING:
+- fe->dtv_property_cache.isdbt_sb_mode = tvp->u.data;
++ c->isdbt_sb_mode = tvp->u.data;
+ break;
+ case DTV_ISDBT_SB_SUBCHANNEL_ID:
+- fe->dtv_property_cache.isdbt_sb_subchannel = tvp->u.data;
++ c->isdbt_sb_subchannel = tvp->u.data;
+ break;
+ case DTV_ISDBT_SB_SEGMENT_IDX:
+- fe->dtv_property_cache.isdbt_sb_segment_idx = tvp->u.data;
++ c->isdbt_sb_segment_idx = tvp->u.data;
+ break;
+ case DTV_ISDBT_SB_SEGMENT_COUNT:
+- fe->dtv_property_cache.isdbt_sb_segment_count = tvp->u.data;
++ c->isdbt_sb_segment_count = tvp->u.data;
+ break;
+ case DTV_ISDBT_LAYER_ENABLED:
+- fe->dtv_property_cache.isdbt_layer_enabled = tvp->u.data;
++ c->isdbt_layer_enabled = tvp->u.data;
+ break;
+ case DTV_ISDBT_LAYERA_FEC:
+- fe->dtv_property_cache.layer[0].fec = tvp->u.data;
++ c->layer[0].fec = tvp->u.data;
+ break;
+ case DTV_ISDBT_LAYERA_MODULATION:
+- fe->dtv_property_cache.layer[0].modulation = tvp->u.data;
++ c->layer[0].modulation = tvp->u.data;
+ break;
+ case DTV_ISDBT_LAYERA_SEGMENT_COUNT:
+- fe->dtv_property_cache.layer[0].segment_count = tvp->u.data;
++ c->layer[0].segment_count = tvp->u.data;
+ break;
+ case DTV_ISDBT_LAYERA_TIME_INTERLEAVING:
+- fe->dtv_property_cache.layer[0].interleaving = tvp->u.data;
++ c->layer[0].interleaving = tvp->u.data;
+ break;
+ case DTV_ISDBT_LAYERB_FEC:
+- fe->dtv_property_cache.layer[1].fec = tvp->u.data;
++ c->layer[1].fec = tvp->u.data;
+ break;
+ case DTV_ISDBT_LAYERB_MODULATION:
+- fe->dtv_property_cache.layer[1].modulation = tvp->u.data;
++ c->layer[1].modulation = tvp->u.data;
+ break;
+ case DTV_ISDBT_LAYERB_SEGMENT_COUNT:
+- fe->dtv_property_cache.layer[1].segment_count = tvp->u.data;
++ c->layer[1].segment_count = tvp->u.data;
+ break;
+ case DTV_ISDBT_LAYERB_TIME_INTERLEAVING:
+- fe->dtv_property_cache.layer[1].interleaving = tvp->u.data;
++ c->layer[1].interleaving = tvp->u.data;
+ break;
+ case DTV_ISDBT_LAYERC_FEC:
+- fe->dtv_property_cache.layer[2].fec = tvp->u.data;
++ c->layer[2].fec = tvp->u.data;
+ break;
+ case DTV_ISDBT_LAYERC_MODULATION:
+- fe->dtv_property_cache.layer[2].modulation = tvp->u.data;
++ c->layer[2].modulation = tvp->u.data;
+ break;
+ case DTV_ISDBT_LAYERC_SEGMENT_COUNT:
+- fe->dtv_property_cache.layer[2].segment_count = tvp->u.data;
++ c->layer[2].segment_count = tvp->u.data;
+ break;
+ case DTV_ISDBT_LAYERC_TIME_INTERLEAVING:
+- fe->dtv_property_cache.layer[2].interleaving = tvp->u.data;
++ c->layer[2].interleaving = tvp->u.data;
+ break;
+ case DTV_ISDBS_TS_ID:
+- fe->dtv_property_cache.isdbs_ts_id = tvp->u.data;
++ c->isdbs_ts_id = tvp->u.data;
++ break;
++ case DTV_DVBT2_PLP_ID:
++ c->dvbt2_plp_id = tvp->u.data;
+ break;
+ default:
+- r = -1;
++ return -EINVAL;
+ }
+
+ return r;
+@@ -1491,6 +1506,7 @@ static int dvb_frontend_ioctl(struct file *file,
+ {
+ struct dvb_device *dvbdev = file->private_data;
+ struct dvb_frontend *fe = dvbdev->priv;
++ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ struct dvb_frontend_private *fepriv = fe->frontend_priv;
+ int err = -EOPNOTSUPP;
+
+@@ -1510,7 +1526,7 @@ static int dvb_frontend_ioctl(struct file *file,
+ if ((cmd == FE_SET_PROPERTY) || (cmd == FE_GET_PROPERTY))
+ err = dvb_frontend_ioctl_properties(file, cmd, parg);
+ else {
+- fe->dtv_property_cache.state = DTV_UNDEFINED;
++ c->state = DTV_UNDEFINED;
+ err = dvb_frontend_ioctl_legacy(file, cmd, parg);
+ }
+
+@@ -1523,6 +1539,7 @@ static int dvb_frontend_ioctl_properties(struct file *file,
+ {
+ struct dvb_device *dvbdev = file->private_data;
+ struct dvb_frontend *fe = dvbdev->priv;
++ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int err = 0;
+
+ struct dtv_properties *tvps = NULL;
+@@ -1554,11 +1571,13 @@ static int dvb_frontend_ioctl_properties(struct file *file,
+ }
+
+ for (i = 0; i < tvps->num; i++) {
+- (tvp + i)->result = dtv_property_process_set(fe, tvp + i, file);
+- err |= (tvp + i)->result;
++ err = dtv_property_process_set(fe, tvp + i, file);
++ if (err < 0)
++ goto out;
++ (tvp + i)->result = err;
+ }
+
+- if(fe->dtv_property_cache.state == DTV_TUNE)
++ if (c->state == DTV_TUNE)
+ dprintk("%s() Property cache is full, tuning\n", __func__);
+
+ } else
+@@ -1586,8 +1605,10 @@ static int dvb_frontend_ioctl_properties(struct file *file,
+ }
+
+ for (i = 0; i < tvps->num; i++) {
+- (tvp + i)->result = dtv_property_process_get(fe, tvp + i, file);
+- err |= (tvp + i)->result;
++ err = dtv_property_process_get(fe, tvp + i, file);
++ if (err < 0)
++ goto out;
++ (tvp + i)->result = err;
+ }
+
+ if (copy_to_user(tvps->props, tvp, tvps->num * sizeof(struct dtv_property))) {
+@@ -1638,7 +1659,7 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
+ case FE_READ_STATUS: {
+ fe_status_t* status = parg;
+
+- /* if retune was requested but hasn't occured yet, prevent
++ /* if retune was requested but hasn't occurred yet, prevent
+ * that user get signal state from previous tuning */
+ if (fepriv->state == FESTATE_RETUNE ||
+ fepriv->state == FESTATE_ERROR) {
+@@ -1729,7 +1750,7 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
+ * Dish network legacy switches (as used by Dish500)
+ * are controlled by sending 9-bit command words
+ * spaced 8msec apart.
+- * the actual command word is switch/port dependant
++ * the actual command word is switch/port dependent
+ * so it is up to the userspace application to send
+ * the right command.
+ * The command must always start with a '0' after
+@@ -1787,10 +1808,11 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
+ break;
+
+ case FE_SET_FRONTEND: {
++ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ struct dvb_frontend_tune_settings fetunesettings;
+
+- if(fe->dtv_property_cache.state == DTV_TUNE) {
+- if (dvb_frontend_check_parameters(fe, &fepriv->parameters) < 0) {
++ if (c->state == DTV_TUNE) {
++ if (dvb_frontend_check_parameters(fe, &fepriv->parameters_in) < 0) {
+ err = -EINVAL;
+ break;
+ }
+@@ -1800,9 +1822,9 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
+ break;
+ }
+
+- memcpy (&fepriv->parameters, parg,
++ memcpy (&fepriv->parameters_in, parg,
+ sizeof (struct dvb_frontend_parameters));
+- dtv_property_cache_sync(fe, &fepriv->parameters);
++ dtv_property_cache_sync(fe, c, &fepriv->parameters_in);
+ }
+
+ memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings));
+@@ -1811,15 +1833,15 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
+
+ /* force auto frequency inversion if requested */
+ if (dvb_force_auto_inversion) {
+- fepriv->parameters.inversion = INVERSION_AUTO;
++ fepriv->parameters_in.inversion = INVERSION_AUTO;
+ fetunesettings.parameters.inversion = INVERSION_AUTO;
+ }
+ if (fe->ops.info.type == FE_OFDM) {
+ /* without hierarchical coding code_rate_LP is irrelevant,
+ * so we tolerate the otherwise invalid FEC_NONE setting */
+- if (fepriv->parameters.u.ofdm.hierarchy_information == HIERARCHY_NONE &&
+- fepriv->parameters.u.ofdm.code_rate_LP == FEC_NONE)
+- fepriv->parameters.u.ofdm.code_rate_LP = FEC_AUTO;
++ if (fepriv->parameters_in.u.ofdm.hierarchy_information == HIERARCHY_NONE &&
++ fepriv->parameters_in.u.ofdm.code_rate_LP == FEC_NONE)
++ fepriv->parameters_in.u.ofdm.code_rate_LP = FEC_AUTO;
+ }
+
+ /* get frontend-specific tuning settings */
+@@ -1832,8 +1854,8 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
+ switch(fe->ops.info.type) {
+ case FE_QPSK:
+ fepriv->min_delay = HZ/20;
+- fepriv->step_size = fepriv->parameters.u.qpsk.symbol_rate / 16000;
+- fepriv->max_drift = fepriv->parameters.u.qpsk.symbol_rate / 2000;
++ fepriv->step_size = fepriv->parameters_in.u.qpsk.symbol_rate / 16000;
++ fepriv->max_drift = fepriv->parameters_in.u.qpsk.symbol_rate / 2000;
+ break;
+
+ case FE_QAM:
+@@ -1875,8 +1897,8 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
+
+ case FE_GET_FRONTEND:
+ 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);
++ err = fe->ops.get_frontend(fe, &fepriv->parameters_out);
++ memcpy(parg, &fepriv->parameters_out, sizeof(struct dvb_frontend_parameters));
+ }
+ break;
+
+@@ -1967,6 +1989,14 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
+ if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl) {
+ if ((ret = fe->ops.ts_bus_ctrl(fe, 1)) < 0)
+ goto err0;
++
++ /* If we took control of the bus, we need to force
++ reinitialization. This is because many ts_bus_ctrl()
++ functions strobe the RESET pin on the demod, and if the
++ frontend thread already exists then the dvb_init() routine
++ won't get called (which is what usually does initial
++ register configuration). */
++ fepriv->reinitialise = 1;
+ }
+
+ if ((ret = dvb_generic_open (inode, file)) < 0)
+diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h
+index f9f19be..5590eb6 100644
+--- a/drivers/media/dvb/dvb-core/dvb_frontend.h
++++ b/drivers/media/dvb/dvb-core/dvb_frontend.h
+@@ -239,7 +239,6 @@ struct analog_demod_ops {
+ void (*set_params)(struct dvb_frontend *fe,
+ struct analog_parameters *params);
+ int (*has_signal)(struct dvb_frontend *fe);
+- int (*is_stereo)(struct dvb_frontend *fe);
+ int (*get_afc)(struct dvb_frontend *fe);
+ void (*tuner_status)(struct dvb_frontend *fe);
+ void (*standby)(struct dvb_frontend *fe);
+@@ -359,6 +358,9 @@ struct dtv_frontend_properties {
+
+ /* ISDB-T specifics */
+ u32 isdbs_ts_id;
++
++ /* DVB-T2 specifics */
++ u32 dvbt2_plp_id;
+ };
+
+ struct dvb_frontend {
+diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
+index 4df42aa..51752a9 100644
+--- a/drivers/media/dvb/dvb-core/dvb_net.c
++++ b/drivers/media/dvb/dvb-core/dvb_net.c
+@@ -1329,7 +1329,8 @@ static int dvb_net_remove_if(struct dvb_net *dvbnet, unsigned long num)
+ return -EBUSY;
+
+ dvb_net_stop(net);
+- flush_scheduled_work();
++ flush_work_sync(&priv->set_multicast_list_wq);
++ flush_work_sync(&priv->restart_net_feed_wq);
+ printk("dvb_net: removed network interface %s\n", net->name);
+ unregister_netdev(net);
+ dvbnet->state[num]=0;
+diff --git a/drivers/media/dvb/dvb-core/dvb_net.h b/drivers/media/dvb/dvb-core/dvb_net.h
+index 3a3126c..1e53acd 100644
+--- a/drivers/media/dvb/dvb-core/dvb_net.h
++++ b/drivers/media/dvb/dvb-core/dvb_net.h
+@@ -32,6 +32,8 @@
+
+ #define DVB_NET_DEVICES_MAX 10
+
++#ifdef CONFIG_DVB_NET
++
+ struct dvb_net {
+ struct dvb_device *dvbdev;
+ struct net_device *device[DVB_NET_DEVICES_MAX];
+@@ -40,8 +42,25 @@ struct dvb_net {
+ struct dmx_demux *demux;
+ };
+
+-
+ void dvb_net_release(struct dvb_net *);
+ int dvb_net_init(struct dvb_adapter *, struct dvb_net *, struct dmx_demux *);
+
++#else
++
++struct dvb_net {
++ struct dvb_device *dvbdev;
++};
++
++static inline void dvb_net_release(struct dvb_net *dvbnet)
++{
++}
++
++static inline int dvb_net_init(struct dvb_adapter *adap,
++ struct dvb_net *dvbnet, struct dmx_demux *dmx)
++{
++ return 0;
++}
++
++#endif /* ifdef CONFIG_DVB_NET */
++
+ #endif
+diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
+index a5712cd..d5333f3 100644
+--- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
++++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
+@@ -45,6 +45,7 @@ void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data, size_t len)
+ rbuf->data=data;
+ rbuf->size=len;
+ rbuf->error=0;
++ rbuf->do_wait=1;
+
+ init_waitqueue_head(&rbuf->queue);
+
+diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.h b/drivers/media/dvb/dvb-core/dvb_ringbuffer.h
+index 41f04da..6951dd3 100644
+--- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.h
++++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.h
+@@ -39,6 +39,7 @@ struct dvb_ringbuffer {
+
+ wait_queue_head_t queue;
+ spinlock_t lock;
++ int do_wait;
+ };
+
+ #define DVB_RINGBUFFER_PKTHDRSIZE 3
+diff --git a/include/linux/dvb/audio.h b/include/linux/dvb/audio.h
+index fec66bd..d47bccd 100644
+--- a/include/linux/dvb/audio.h
++++ b/include/linux/dvb/audio.h
+@@ -67,7 +67,7 @@ typedef struct audio_status {
+
+
+ typedef
+-struct audio_karaoke{ /* if Vocal1 or Vocal2 are non-zero, they get mixed */
++struct audio_karaoke { /* if Vocal1 or Vocal2 are non-zero, they get mixed */
+ int vocal1; /* into left and right t at 70% each */
+ int vocal2; /* if both, Vocal1 and Vocal2 are non-zero, Vocal1 gets*/
+ int melody; /* mixed into the left channel and */
+diff --git a/include/linux/dvb/frontend.h b/include/linux/dvb/frontend.h
+index 493a2bf..36a3ed6 100644
+--- a/include/linux/dvb/frontend.h
++++ b/include/linux/dvb/frontend.h
+@@ -175,14 +175,20 @@ typedef enum fe_transmit_mode {
+ TRANSMISSION_MODE_2K,
+ TRANSMISSION_MODE_8K,
+ TRANSMISSION_MODE_AUTO,
+- TRANSMISSION_MODE_4K
++ TRANSMISSION_MODE_4K,
++ TRANSMISSION_MODE_1K,
++ TRANSMISSION_MODE_16K,
++ TRANSMISSION_MODE_32K,
+ } fe_transmit_mode_t;
+
+ typedef enum fe_bandwidth {
+ BANDWIDTH_8_MHZ,
+ BANDWIDTH_7_MHZ,
+ BANDWIDTH_6_MHZ,
+- BANDWIDTH_AUTO
++ BANDWIDTH_AUTO,
++ BANDWIDTH_5_MHZ,
++ BANDWIDTH_10_MHZ,
++ BANDWIDTH_1_712_MHZ,
+ } fe_bandwidth_t;
+
+
+@@ -191,7 +197,10 @@ typedef enum fe_guard_interval {
+ GUARD_INTERVAL_1_16,
+ GUARD_INTERVAL_1_8,
+ GUARD_INTERVAL_1_4,
+- GUARD_INTERVAL_AUTO
++ GUARD_INTERVAL_AUTO,
++ GUARD_INTERVAL_1_128,
++ GUARD_INTERVAL_19_128,
++ GUARD_INTERVAL_19_256,
+ } fe_guard_interval_t;
+
+
+@@ -305,7 +314,9 @@ struct dvb_frontend_event {
+
+ #define DTV_ISDBS_TS_ID 42
+
+-#define DTV_MAX_COMMAND DTV_ISDBS_TS_ID
++#define DTV_DVBT2_PLP_ID 43
++
++#define DTV_MAX_COMMAND DTV_DVBT2_PLP_ID
+
+ typedef enum fe_pilot {
+ PILOT_ON,
+@@ -337,6 +348,7 @@ typedef enum fe_delivery_system {
+ SYS_DMBTH,
+ SYS_CMMB,
+ SYS_DAB,
++ SYS_DVBT2,
+ } fe_delivery_system_t;
+
+ struct dtv_cmds_h {
+diff --git a/include/linux/dvb/version.h b/include/linux/dvb/version.h
+index 5a7546c..1421cc8 100644
+--- a/include/linux/dvb/version.h
++++ b/include/linux/dvb/version.h
+@@ -24,6 +24,6 @@
+ #define _DVBVERSION_H_
+
+ #define DVB_API_VERSION 5
+-#define DVB_API_VERSION_MINOR 2
++#define DVB_API_VERSION_MINOR 3
+
+ #endif /*_DVBVERSION_H_*/