diff -r 05965994551c linux/drivers/media/dvb/dvb-core/dvb_frontend.c
--- a/linux/drivers/media/dvb/dvb-core/dvb_frontend.c	Fri Nov 02 18:40:13 2007 -0200
+++ b/linux/drivers/media/dvb/dvb-core/dvb_frontend.c	Wed Jan 16 21:23:40 2008 -0500
@@ -766,6 +766,330 @@ static int dvb_frontend_check_parameters
 	return 0;
 }
 
+struct tv_cmds_h tv_cmds[] = {
+	[TV_SEQ_UNDEFINED] = {
+		.name	= "TV_SEQ_UNDEFINED",
+		.cmd	= TV_SEQ_UNDEFINED,
+		.set	= 1,
+	},
+	[TV_SEQ_START] = {
+		.name	= "TV_SEQ_START",
+		.cmd	= TV_SEQ_START,
+		.set	= 1,
+	},
+	[TV_SEQ_CONTINUE] = {
+		.name	= "TV_SEQ_CONTINUE",
+		.cmd	= TV_SEQ_CONTINUE,
+		.set	= 1,
+	},
+	[TV_SEQ_COMPLETE] = {
+		.name	= "TV_SEQ_COMPLETE",
+		.cmd	= TV_SEQ_COMPLETE,
+		.set	= 1,
+	},
+	[TV_SEQ_TERMINATE] = {
+		.name	= "TV_SEQ_TERMINATE",
+		.cmd	= TV_SEQ_TERMINATE,
+		.set	= 1,
+	},
+
+	/* Set */
+	[TV_SET_FREQUENCY] = {
+		.name	= "TV_SET_FREQUENCY",
+		.cmd	= TV_SET_FREQUENCY,	
+		.set	= 1,
+	},
+	[TV_SET_BANDWIDTH] = {
+		.name	= "TV_SET_BANDWIDTH",
+		.cmd	= TV_SET_BANDWIDTH,	
+		.set	= 1,
+	},
+	[TV_SET_MODULATION] = {
+		.name	= "TV_SET_MODULATION",
+		.cmd	= TV_SET_MODULATION,	
+		.set	= 1,
+	},
+	[TV_SET_INVERSION] = {
+		.name	= "TV_SET_INVERSION",
+		.cmd	= TV_SET_INVERSION,	
+		.set	= 1,
+	},
+	[TV_SET_DISEQC_MASTER] = {
+		.name	= "TV_SET_DISEQC_MASTER",
+		.cmd	= TV_SET_DISEQC_MASTER,	
+		.set	= 1,
+		.buffer	= 1,
+	},
+	[TV_SET_SYMBOLRATE] = {
+		.name	= "TV_SET_SYMBOLRATE",
+		.cmd	= TV_SET_SYMBOLRATE,	
+		.set	= 1,
+	},
+	[TV_SET_INNERFEC] = {
+		.name	= "TV_SET_INNERFEC",
+		.cmd	= TV_SET_INNERFEC,	
+		.set	= 1,
+	},
+	[TV_SET_VOLTAGE] = {
+		.name	= "TV_SET_VOLTAGE",
+		.cmd	= TV_SET_VOLTAGE,	
+		.set	= 1,
+	},
+	[TV_SET_TONE] = {
+		.name	= "TV_SET_TONE",
+		.cmd	= TV_SET_TONE,	
+		.set	= 1,
+	},
+	[TV_SET_PILOT] = {
+		.name	= "TV_SET_PILOT",
+		.cmd	= TV_SET_PILOT,	
+		.set	= 1,
+	},
+	[TV_SET_ROLLOFF] = {
+		.name	= "TV_SET_ROLLOFF",
+		.cmd	= TV_SET_ROLLOFF,	
+		.set	= 1,
+	},
+
+	/* Get */
+	[TV_GET_FREQUENCY] = {
+		.name	= "TV_GET_FREQUENCY",
+		.cmd	= TV_GET_FREQUENCY,	
+		.set	= 0,
+	},
+	[TV_GET_BANDWIDTH] = {
+		.name	= "TV_GET_BANDWIDTH",
+		.cmd	= TV_GET_BANDWIDTH,	
+		.set	= 0,
+	},
+	[TV_GET_MODULATION] = {
+		.name	= "TV_GET_MODULATION",
+		.cmd	= TV_GET_MODULATION,	
+		.set	= 0,
+	},
+	[TV_GET_INVERSION] = {
+		.name	= "TV_GET_INVERSION",
+		.cmd	= TV_GET_INVERSION,	
+		.set	= 0,
+	},
+	[TV_GET_DISEQC_SLAVE_REPLY] = {
+		.name	= "TV_GET_DISEQC_SLAVE_REPLY",
+		.cmd	= TV_GET_DISEQC_SLAVE_REPLY,	
+		.set	= 0,
+		.buffer	= 1,
+	},
+	[TV_GET_SYMBOLRATE] = {
+		.name	= "TV_GET_SYMBOLRATE",
+		.cmd	= TV_GET_SYMBOLRATE,	
+		.set	= 0,
+	},
+	[TV_GET_INNERFEC] = {
+		.name	= "TV_GET_INNERFEC",
+		.cmd	= TV_GET_INNERFEC,	
+		.set	= 0,
+	},
+	[TV_GET_VOLTAGE] = {
+		.name	= "TV_GET_VOLTAGE",
+		.cmd	= TV_GET_VOLTAGE,	
+		.set	= 0,
+	},
+	[TV_GET_TONE] = {
+		.name	= "TV_GET_TONE",
+		.cmd	= TV_GET_TONE,	
+		.set	= 0,
+	},
+	[TV_GET_PILOT] = {
+		.name	= "TV_GET_PILOT",
+		.cmd	= TV_GET_PILOT,	
+		.set	= 0,
+	},
+	[TV_GET_ROLLOFF] = {
+		.name	= "TV_GET_ROLLOFF",
+		.cmd	= TV_GET_ROLLOFF,	
+		.set	= 0,
+	},
+};
+
+void tv_property_dump(tv_property_t *tvp)
+{
+	int i;
+
+	printk("%s() tvp.cmd    = 0x%08x (%s)\n"
+		,__FUNCTION__
+		,tvp->cmd
+		,tv_cmds[ tvp->cmd ].name);
+
+	if(tv_cmds[ tvp->cmd ].buffer) {
+
+		printk("%s() tvp.u.buffer.len = 0x%02x\n"
+			,__FUNCTION__
+			,tvp->u.buffer.len);
+
+		for(i = 0; i < tvp->u.buffer.len; i++)
+			printk("%s() tvp.u.buffer.data[0x%02x] = 0x%02x\n"
+				,__FUNCTION__
+				,i
+				,tvp->u.buffer.data[i]);
+
+	} else
+		printk("%s() tvp.u.data = 0x%08x\n", __FUNCTION__, tvp->u.data);
+}
+
+int tv_property_cache_submit(struct dvb_frontend *fe)
+{
+
+	/* Build a fully formed legacy or new tune request and send it
+	 * to the driver.
+	 * Make a rudamentary judgement based on modulation type.
+	 */
+
+	int r;
+
+	struct tv_frontend_properties *c = &fe->tv_property_cache;
+	struct dvb_frontend_private *fepriv = fe->frontend_priv;
+	struct dvb_frontend_parameters p;
+
+	printk("%s()\n", __FUNCTION__);
+
+	switch(c->modulation) {
+	case _8PSK:
+	case _16APSK:
+		/* Just post a notification to the demof driver and let it pull
+		 * the specific values it wants from its tv_property_cache.
+		 * It can decide how best to use those parameters.
+		 */
+		if (fe->ops.set_params)
+			r = fe->ops.set_params(fe);
+		else
+			r = -1;
+		break;
+	case QPSK:
+		printk("%s() Preparing QPSK req\n", __FUNCTION__);
+		/* TODO: Insert sanity code to validate a little. */
+		p.frequency = c->frequency;
+		p.inversion = c->inversion;
+		p.u.qpsk.symbol_rate = c->symbol_rate;		
+		p.u.qpsk.fec_inner = c->fec_inner;
+		memcpy(&fepriv->parameters, &p,
+			sizeof (struct dvb_frontend_parameters));
+
+		/* Call the traditional tuning mechanisms. */
+
+		r = 0;
+		break;
+	case QAM_16:
+	case QAM_32:
+	case QAM_64:
+	case QAM_128:
+	case QAM_256:
+	case QAM_AUTO:
+		printk("%s() Preparing QAM req\n", __FUNCTION__);
+		/* TODO: Insert sanity code to validate a little. */
+		p.frequency = c->frequency;
+		p.inversion = c->inversion;
+		p.u.qam.symbol_rate = c->symbol_rate;		
+		p.u.vsb.modulation = c->modulation;
+		printk("%s() frequency = %d\n", __FUNCTION__, p.frequency);
+		printk("%s() QAM       = %d\n", __FUNCTION__, p.u.vsb.modulation);
+		memcpy(&fepriv->parameters, &p,
+			sizeof (struct dvb_frontend_parameters));
+
+		/* At this point we're fully formed for backwards
+		 * compatability and we need to submit this
+		 * via the ioctl handler as SET_FRONTEND (arg).
+		 * ioctl handler needs to be split before
+		 * we can do that, to avoid semaphore issues etc.
+		 */
+
+		r = 0;
+		break;
+	default:
+		/* Implement other modulation types */
+		r = -1;
+	}
+
+	return r;
+}
+
+int tv_property_process(struct dvb_frontend *fe, tv_property_t *tvp)
+{
+	int r = 0;
+	printk("%s()\n", __FUNCTION__);
+	tv_property_dump(tvp);
+
+	switch(tvp->cmd) {
+	case TV_SEQ_START:
+	case TV_SEQ_TERMINATE:
+		/* Reset a cache of data specific to the frontend here. This does
+		 * not effect hardware.
+		 */
+		printk("%s() Flushing property cache\n", __FUNCTION__);
+		memset(&fe->tv_property_cache, 0, sizeof(struct tv_frontend_properties));
+		fe->tv_property_cache.state = TV_SEQ_START;
+		break;
+	case TV_SEQ_COMPLETE:
+		/* interpret the cache of data, build either a traditional frontend
+		 * tunerequest and submit it to a subset of the ioctl handler,
+		 * or, call a new undefined method on the frontend to deal with
+		 * all new tune requests.
+		 */
+		fe->tv_property_cache.state = TV_SEQ_COMPLETE;
+		printk("%s() Finalised property cache\n", __FUNCTION__);
+		r = tv_property_cache_submit(fe);
+		break;
+	case TV_SET_FREQUENCY:
+		fe->tv_property_cache.frequency = tvp->u.data;
+		break;
+	case TV_GET_FREQUENCY:
+		tvp->u.data = fe->tv_property_cache.frequency;
+		break;
+	case TV_SET_MODULATION:
+		fe->tv_property_cache.modulation = tvp->u.data;
+		break;
+	case TV_GET_MODULATION:
+		tvp->u.data = fe->tv_property_cache.modulation;
+		break;
+	case TV_SET_BANDWIDTH:
+		fe->tv_property_cache.bandwidth = tvp->u.data;
+		break;
+	case TV_GET_BANDWIDTH:
+		tvp->u.data = fe->tv_property_cache.bandwidth;
+		break;
+	case TV_SET_INVERSION:
+		fe->tv_property_cache.inversion = tvp->u.data;
+		break;
+	case TV_GET_INVERSION:
+		tvp->u.data = fe->tv_property_cache.inversion;
+		break;
+	case TV_SET_SYMBOLRATE:
+		fe->tv_property_cache.symbol_rate = tvp->u.data;
+		break;
+	case TV_GET_SYMBOLRATE:
+		tvp->u.data = fe->tv_property_cache.symbol_rate;
+		break;
+	case TV_SET_INNERFEC:
+		fe->tv_property_cache.fec_inner = tvp->u.data;
+		break;
+	case TV_GET_INNERFEC:
+		tvp->u.data = fe->tv_property_cache.fec_inner;
+		break;
+	case TV_SET_PILOT:
+		fe->tv_property_cache.pilot = tvp->u.data;
+		break;
+	case TV_GET_PILOT:
+		tvp->u.data = fe->tv_property_cache.pilot;
+		break;
+	case TV_SET_ROLLOFF:
+		fe->tv_property_cache.rolloff = tvp->u.data;
+		break;
+	case TV_GET_ROLLOFF:
+		tvp->u.data = fe->tv_property_cache.rolloff;
+		break;
+	}
+
+	return 0;
+}
+
 static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
 			unsigned int cmd, void *parg)
 {
@@ -787,6 +1111,27 @@ static int dvb_frontend_ioctl(struct ino
 	if (down_interruptible (&fepriv->sem))
 		return -ERESTARTSYS;
 
+	if(cmd == FE_SET_PROPERTY) {
+		printk("%s() FE_SET_PROPERTY\n", __FUNCTION__);
+
+		/* TODO: basic property validation here */
+
+		/* TODO: ioctl userdata out of range check here */
+		tv_property_t* tvp = parg;
+		while(tvp->cmd != TV_SEQ_UNDEFINED) {
+			tv_property_process(fe, tvp);
+			if( (tvp->cmd == TV_SEQ_TERMINATE) || (tvp->cmd == TV_SEQ_COMPLETE) )
+				break;
+			tvp++;
+		}
+
+		if(fe->tv_property_cache.state == TV_SEQ_COMPLETE) {
+			printk("%s() Property cache is full, tuning\n", __FUNCTION__);
+			cmd = FE_SET_FRONTEND;
+		}
+		err = 0;
+	}
+	
 	switch (cmd) {
 	case FE_GET_INFO: {
 		struct dvb_frontend_info* info = parg;
@@ -953,13 +1298,20 @@ static int dvb_frontend_ioctl(struct ino
 	case FE_SET_FRONTEND: {
 		struct dvb_frontend_tune_settings fetunesettings;
 
-		if (dvb_frontend_check_parameters(fe, parg) < 0) {
-			err = -EINVAL;
-			break;
-		}
-
-		memcpy (&fepriv->parameters, parg,
-			sizeof (struct dvb_frontend_parameters));
+		if(fe->tv_property_cache.state == TV_SEQ_COMPLETE) {
+			if (dvb_frontend_check_parameters(fe, &fepriv->parameters) < 0) {
+				err = -EINVAL;
+				break;
+			}
+		} else {
+			if (dvb_frontend_check_parameters(fe, parg) < 0) {
+				err = -EINVAL;
+				break;
+			}
+
+			memcpy (&fepriv->parameters, parg,
+				sizeof (struct dvb_frontend_parameters));
+		}
 
 		memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings));
 		memcpy(&fetunesettings.parameters, parg,
@@ -1042,6 +1394,7 @@ static int dvb_frontend_ioctl(struct ino
 	return err;
 }
 
+
 static unsigned int dvb_frontend_poll(struct file *file, struct poll_table_struct *wait)
 {
 	struct dvb_device *dvbdev = file->private_data;
diff -r 05965994551c linux/drivers/media/dvb/dvb-core/dvb_frontend.h
--- a/linux/drivers/media/dvb/dvb-core/dvb_frontend.h	Fri Nov 02 18:40:13 2007 -0200
+++ b/linux/drivers/media/dvb/dvb-core/dvb_frontend.h	Wed Jan 16 21:23:40 2008 -0500
@@ -151,6 +151,10 @@ struct dvb_frontend_ops {
 
 	struct dvb_tuner_ops tuner_ops;
 	struct analog_tuner_ops *analog_demod_ops;
+
+	int (*set_property)(struct dvb_frontend* fe, tv_property_t* tvp);
+	int (*get_property)(struct dvb_frontend* fe, tv_property_t* tvp);
+	int (*set_params)(struct dvb_frontend* fe);
 };
 
 #define MAX_EVENT 8
@@ -168,6 +172,30 @@ struct dvb_fe_events {
 #endif
 };
 
+struct tv_frontend_properties {
+
+	/* Cache State */
+	u32			state;
+
+	u32			frequency;
+	fe_modulation_t		modulation;
+
+	fe_sec_voltage_t	voltage;
+	fe_sec_tone_mode_t	sectone;
+	fe_spectral_inversion_t	inversion;
+	fe_code_rate_t		fec_inner;
+	fe_transmit_mode_t	transmission_mode;
+	fe_bandwidth_t		bandwidth;
+	fe_guard_interval_t	guard_interval;
+	fe_hierarchy_t		hierarchy;
+	u32			symbol_rate;
+	fe_code_rate_t		code_rate_HP;
+	fe_code_rate_t		code_rate_LP;
+
+	fe_pilot_t		pilot;
+	fe_rolloff_t		rolloff;
+};
+
 struct dvb_frontend {
 	struct dvb_frontend_ops ops;
 	struct dvb_adapter *dvb;
@@ -176,6 +204,7 @@ struct dvb_frontend {
 	void *frontend_priv;
 	void *sec_priv;
 	void *analog_demod_priv;
+	struct tv_frontend_properties tv_property_cache;
 };
 
 extern int dvb_register_frontend(struct dvb_adapter *dvb,
diff -r 05965994551c linux/drivers/media/dvb/frontends/s5h1409.c
--- a/linux/drivers/media/dvb/frontends/s5h1409.c	Fri Nov 02 18:40:13 2007 -0200
+++ b/linux/drivers/media/dvb/frontends/s5h1409.c	Wed Jan 16 21:23:40 2008 -0500
@@ -394,6 +394,7 @@ static int s5h1409_enable_modulation(str
 		break;
 	case QAM_64:
 	case QAM_256:
+	case QAM_AUTO:
 		dprintk("%s() QAM_AUTO (64/256)\n", __FUNCTION__);
 		s5h1409_writereg(state, 0xf4, 1);
 		s5h1409_writereg(state, 0x85, 0x110);
diff -r 05965994551c linux/include/linux/dvb/frontend.h
--- a/linux/include/linux/dvb/frontend.h	Fri Nov 02 18:40:13 2007 -0200
+++ b/linux/include/linux/dvb/frontend.h	Wed Jan 16 21:23:40 2008 -0500
@@ -160,7 +160,9 @@ typedef enum fe_modulation {
 	QAM_256,
 	QAM_AUTO,
 	VSB_8,
-	VSB_16
+	VSB_16,
+	_8PSK,
+	_16APSK,
 } fe_modulation_t;
 
 typedef enum fe_transmit_mode {
@@ -239,6 +241,80 @@ struct dvb_frontend_event {
 	struct dvb_frontend_parameters parameters;
 };
 
+typedef enum tv_cmd_types {
+	TV_SEQ_UNDEFINED,
+	TV_SEQ_START,
+	TV_SEQ_CONTINUE,
+	TV_SEQ_COMPLETE,
+	TV_SEQ_TERMINATE,
+
+	TV_SET_FREQUENCY,
+	TV_SET_MODULATION,
+	TV_SET_BANDWIDTH,
+	TV_SET_INVERSION,
+	TV_SET_DISEQC_MASTER,
+	TV_SET_SYMBOLRATE,
+	TV_SET_INNERFEC,
+	TV_SET_VOLTAGE,
+	TV_SET_TONE,
+	TV_SET_PILOT,
+	TV_SET_ROLLOFF,
+
+	TV_GET_FREQUENCY,
+	TV_GET_MODULATION,
+	TV_GET_BANDWIDTH,
+	TV_GET_INVERSION,
+	TV_GET_DISEQC_SLAVE_REPLY,
+	TV_GET_SYMBOLRATE,
+	TV_GET_INNERFEC,
+	TV_GET_VOLTAGE,
+	TV_GET_TONE,
+	TV_GET_PILOT,
+	TV_GET_ROLLOFF,
+
+} tv_cmd_types_t;
+
+typedef enum fe_pilot {
+	PILOT_ON,
+	PILOT_OFF,
+	PILOT_AUTO,
+} fe_pilot_t;
+
+typedef enum fe_rolloff {
+	ROLLOFF_20,
+	ROLLOFF_25,
+	ROLLOFF_35,
+	ROLLOFF_AUTO,
+} fe_rolloff_t;
+
+struct tv_cmds_h {
+	char	*name;		/* A display name for debugging purposes */
+
+	__u32	cmd;		/* A unique ID */
+
+	/* Flags */
+	__u32	set:1;		/* Either a set or get property */
+	__u32	buffer:1;	/* Does this property use the buffer? */
+	__u32	reserved:30;	/* Align */
+};
+
+typedef struct {
+	__u32 cmd;
+	union {
+		__u32 data;
+		struct {
+			__u8 data[32];
+			__u32 len;	
+		} buffer;
+	} u;
+} tv_property_t;
+
+/* No more than 16 properties during any given ioctl */
+typedef tv_property_t tv_properties_t[16];
+
+#define FE_SET_PROPERTY		   _IOW('o', 82, tv_properties_t)
+#define FE_GET_PROPERTY		   _IOR('o', 83, tv_properties_t)
+
 
 /**
  * When set, this flag will disable any zigzagging or other "normal" tuning
