diff mbox

DVB Satellite Channel Routing support for DVB-S

Message ID BDD0B014-3AD5-4693-82D9-026F47A7F8A4@gmx.net (mailing list archive)
State Not Applicable
Headers show

Commit Message

Thomas Schlöter Jan. 10, 2011, 4:19 a.m. UTC
None
diff mbox

Patch

================= Kernel patch against 2.6.37

diff -uprN a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c	2011-01-05 01:50:19.000000000 +0100
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c	2011-01-10 03:56:58.000000000 +0100
@@ -9,6 +9,8 @@ 
  *
  * Copyright (C) 2004 Andrew de Quincey (tuning thread cleanup)
  *
+ * Copyright (C) 2011 Thomas Schloeter (satellite channel routing)
+ *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2
@@ -50,6 +52,8 @@  static int dvb_override_tune_delay;
 static int dvb_powerdown_on_sleep = 1;
 static int dvb_mfe_wait_time = 5;
 
+int scr_send_tune_cmd(struct dvb_frontend*);
+
 module_param_named(frontend_debug, dvb_frontend_debug, int, 0644);
 MODULE_PARM_DESC(frontend_debug, "Turn on/off frontend core debugging (default:off).");
 module_param(dvb_shutdown_timeout, int, 0644);
@@ -121,6 +125,9 @@  struct dvb_frontend_private {
 	int tone;
 	int voltage;
 
+	/* satellite channel routing */
+	struct dvb_scr_params dvbscr;
+
 	/* swzigzag values */
 	unsigned int state;
 	unsigned int bending;
@@ -1023,10 +1030,19 @@  static void dtv_property_cache_sync(stru
 				    struct dvb_frontend_parameters *p)
 {
 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct dvb_frontend_private *fepriv = fe->frontend_priv;
 
 	c->frequency = p->frequency;
 	c->inversion = p->inversion;
 
+	c->dvbscr.scr_enable = fepriv->dvbscr.scr_enable;
+	c->dvbscr.scr_id = fepriv->dvbscr.scr_id;
+	c->dvbscr.scr_frequency = fepriv->dvbscr.scr_frequency;
+	c->dvbscr.scr_position = fepriv->dvbscr.scr_position;
+	c->dvbscr.scr_frequency_orig = fepriv->dvbscr.scr_frequency_orig;
+	c->dvbscr.scr_polarisation = fepriv->dvbscr.scr_polarisation;
+	c->dvbscr.scr_band = fepriv->dvbscr.scr_band;
+
 	switch (fe->ops.info.type) {
 	case FE_QPSK:
 		c->modulation = QPSK;   /* implied for DVB-S in legacy API */
@@ -1081,6 +1097,14 @@  static void dtv_property_legacy_params_s
 	p->frequency = c->frequency;
 	p->inversion = c->inversion;
 
+	fepriv->dvbscr.scr_enable = c->dvbscr.scr_enable;
+	fepriv->dvbscr.scr_id = c->dvbscr.scr_id;
+	fepriv->dvbscr.scr_frequency = c->dvbscr.scr_frequency;
+	fepriv->dvbscr.scr_position = c->dvbscr.scr_position;
+	fepriv->dvbscr.scr_frequency_orig = c->dvbscr.scr_frequency_orig;
+	fepriv->dvbscr.scr_polarisation = c->dvbscr.scr_polarisation;
+	fepriv->dvbscr.scr_band = c->dvbscr.scr_band;
+
 	switch (fe->ops.info.type) {
 	case FE_QPSK:
 		dprintk("%s() Preparing QPSK req\n", __func__);
@@ -1136,6 +1160,14 @@  static void dtv_property_adv_params_sync
 	p->frequency = c->frequency;
 	p->inversion = c->inversion;
 
+	fepriv->dvbscr.scr_enable = c->dvbscr.scr_enable;
+	fepriv->dvbscr.scr_id = c->dvbscr.scr_id;
+	fepriv->dvbscr.scr_frequency = c->dvbscr.scr_frequency;
+	fepriv->dvbscr.scr_position = c->dvbscr.scr_position;
+	fepriv->dvbscr.scr_frequency_orig = c->dvbscr.scr_frequency_orig;
+	fepriv->dvbscr.scr_polarisation = c->dvbscr.scr_polarisation;
+	fepriv->dvbscr.scr_band = c->dvbscr.scr_band;
+
 	switch(c->modulation) {
 	case PSK_8:
 	case APSK_16:
@@ -1215,7 +1247,10 @@  static int dtv_property_process_get(stru
 
 	switch(tvp->cmd) {
 	case DTV_FREQUENCY:
-		tvp->u.data = fe->dtv_property_cache.frequency;
+		if (fe->dtv_property_cache.dvbscr.scr_enable == SCR_ON)
+			tvp->u.data = fe->dtv_property_cache.dvbscr.scr_frequency_orig;
+		else
+			tvp->u.data = fe->dtv_property_cache.frequency;
 		break;
 	case DTV_MODULATION:
 		tvp->u.data = fe->dtv_property_cache.modulation;
@@ -1242,10 +1277,18 @@  static int dtv_property_process_get(stru
 		tvp->u.data = fe->dtv_property_cache.delivery_system;
 		break;
 	case DTV_VOLTAGE:
-		tvp->u.data = fe->dtv_property_cache.voltage;
+		if (fe->dtv_property_cache.dvbscr.scr_enable == SCR_ON)
+			tvp->u.data = (fe->dtv_property_cache.dvbscr.scr_polarisation == SCR_POL_H) ?
+					SEC_VOLTAGE_18 : SEC_VOLTAGE_13;
+		else
+			tvp->u.data = fe->dtv_property_cache.voltage;
 		break;
 	case DTV_TONE:
-		tvp->u.data = fe->dtv_property_cache.sectone;
+		if (fe->dtv_property_cache.dvbscr.scr_enable == SCR_ON)
+			tvp->u.data = (fe->dtv_property_cache.dvbscr.scr_band == SCR_BAND_HI) ?
+					SEC_TONE_ON : SEC_TONE_OFF;
+		else
+			tvp->u.data = fe->dtv_property_cache.sectone;
 		break;
 	case DTV_API_VERSION:
 		tvp->u.data = (DVB_API_VERSION << 8) | DVB_API_VERSION_MINOR;
@@ -1342,8 +1385,12 @@  static int dtv_property_process_set(stru
 	dtv_property_dump(tvp);
 
 	/* Allow the frontend to validate incoming properties */
-	if (fe->ops.set_property)
-		r = fe->ops.set_property(fe, tvp);
+	if ((fe->dtv_property_cache.dvbscr.scr_enable != SCR_ON) ||
+	    (tvp->cmd != DTV_FREQUENCY) ||
+	    (tvp->cmd != DTV_VOLTAGE) ||
+	    (tvp->cmd != DTV_TONE))
+		if (fe->ops.set_property)
+			r = fe->ops.set_property(fe, tvp);
 
 	if (r < 0)
 		return r;
@@ -1369,7 +1416,10 @@  static int dtv_property_process_set(stru
 			&fepriv->parameters);
 		break;
 	case DTV_FREQUENCY:
-		fe->dtv_property_cache.frequency = tvp->u.data;
+		if (fe->dtv_property_cache.dvbscr.scr_enable == SCR_ON)
+			fe->dtv_property_cache.dvbscr.scr_frequency_orig = tvp->u.data;
+		else
+			fe->dtv_property_cache.frequency = tvp->u.data;
 		break;
 	case DTV_MODULATION:
 		fe->dtv_property_cache.modulation = tvp->u.data;
@@ -1396,14 +1446,24 @@  static int dtv_property_process_set(stru
 		fe->dtv_property_cache.delivery_system = tvp->u.data;
 		break;
 	case DTV_VOLTAGE:
-		fe->dtv_property_cache.voltage = tvp->u.data;
-		r = dvb_frontend_ioctl_legacy(file, FE_SET_VOLTAGE,
-			(void *)fe->dtv_property_cache.voltage);
+		if (fe->dtv_property_cache.dvbscr.scr_enable == SCR_ON)
+			fe->dtv_property_cache.dvbscr.scr_polarisation =
+				(tvp->u.data == SEC_VOLTAGE_18) ? SCR_POL_H : SCR_POL_V;
+		else {
+			fe->dtv_property_cache.voltage = tvp->u.data;
+			r = dvb_frontend_ioctl_legacy(file, FE_SET_VOLTAGE,
+				(void *)fe->dtv_property_cache.voltage);
+		}
 		break;
 	case DTV_TONE:
-		fe->dtv_property_cache.sectone = tvp->u.data;
-		r = dvb_frontend_ioctl_legacy(file, FE_SET_TONE,
-			(void *)fe->dtv_property_cache.sectone);
+		if (fe->dtv_property_cache.dvbscr.scr_enable == SCR_ON)
+			fe->dtv_property_cache.dvbscr.scr_band =
+				(tvp->u.data == SEC_TONE_ON) ? SCR_BAND_HI : SCR_BAND_LO;
+		else {
+			fe->dtv_property_cache.sectone = tvp->u.data;
+			r = dvb_frontend_ioctl_legacy(file, FE_SET_TONE,
+				(void *)fe->dtv_property_cache.sectone);
+		}
 		break;
 	case DTV_CODE_RATE_HP:
 		fe->dtv_property_cache.code_rate_HP = tvp->u.data;
@@ -1610,6 +1670,7 @@  static int dvb_frontend_ioctl_legacy(str
 	struct dvb_frontend *fe = dvbdev->priv;
 	struct dvb_frontend_private *fepriv = fe->frontend_priv;
 	int cb_err, err = -EOPNOTSUPP;
+	u32 fe_freq_min, fe_freq_max;
 
 	if (fe->dvb->fe_ioctl_override) {
 		cb_err = fe->dvb->fe_ioctl_override(fe, cmd, parg,
@@ -1681,6 +1742,11 @@  static int dvb_frontend_ioctl_legacy(str
 		break;
 
 	case FE_DISEQC_SEND_MASTER_CMD:
+		if (fepriv->dvbscr.scr_enable == SCR_ON) {
+			dprintk("DVB: %s: Operation not available when SCR enabled\n", __FUNCTION__);
+			err = -EINVAL;
+			break;
+		}
 		if (fe->ops.diseqc_send_master_cmd) {
 			err = fe->ops.diseqc_send_master_cmd(fe, (struct dvb_diseqc_master_cmd*) parg);
 			fepriv->state = FESTATE_DISEQC;
@@ -1689,6 +1755,11 @@  static int dvb_frontend_ioctl_legacy(str
 		break;
 
 	case FE_DISEQC_SEND_BURST:
+		if (fepriv->dvbscr.scr_enable == SCR_ON) {
+			dprintk("DVB: %s: Operation not available when SCR enabled\n", __FUNCTION__);
+			err = -EINVAL;
+			break;
+		}
 		if (fe->ops.diseqc_send_burst) {
 			err = fe->ops.diseqc_send_burst(fe, (fe_sec_mini_cmd_t) parg);
 			fepriv->state = FESTATE_DISEQC;
@@ -1696,10 +1767,67 @@  static int dvb_frontend_ioctl_legacy(str
 		}
 		break;
 
+	case FE_SET_SCR:
+		if (fe->ops.info.type != FE_QPSK) {
+			dprintk("DVB: %s: SCR is supported on QPSK frontends only!\n", __FUNCTION__);
+			err = -EINVAL;
+			break;
+		}
+		fepriv->dvbscr.scr_enable = ((struct dvb_scr_params *) parg)->scr_enable;
+		fepriv->dvbscr.scr_id = ((struct dvb_scr_params *) parg)->scr_id;
+		fepriv->dvbscr.scr_position = ((struct dvb_scr_params *) parg)->scr_position;
+		fepriv->dvbscr.scr_frequency = ((struct dvb_scr_params *) parg)->scr_frequency;
+		err = 0;
+		if ((fepriv->dvbscr.scr_enable != SCR_ON) && (fepriv->dvbscr.scr_enable != SCR_OFF)) {
+			fepriv->dvbscr.scr_enable = SCR_OFF;
+			err = -EINVAL;
+			dprintk("DVB: %s: Invalid value for SCR_ON in ioctl\n", __FUNCTION__);
+		}
+		dvb_frontend_get_frequency_limits(fe, &fe_freq_min, &fe_freq_max);
+		if ((fepriv->dvbscr.scr_frequency < fe_freq_min / 1000) || (fepriv->dvbscr.scr_frequency > fe_freq_max / 1000)) {
+			fepriv->dvbscr.scr_enable = SCR_OFF;
+			fepriv->dvbscr.scr_frequency = 1400;
+			err = -EINVAL;
+			dprintk("DVB: %s: Invalid value for SCR_FREQ in ioctl\n", __FUNCTION__);
+		}
+		if ((fepriv->dvbscr.scr_position != SCR_POS_A) && (fepriv->dvbscr.scr_position != SCR_POS_B)) {
+			fepriv->dvbscr.scr_enable = SCR_OFF;
+			fepriv->dvbscr.scr_position = SCR_POS_A;
+			err = -EINVAL;
+			dprintk("DVB: %s: Invalid value for SCR_POSITION in ioctl\n", __FUNCTION__);
+		}
+		if (fepriv->dvbscr.scr_id > 7) {
+			fepriv->dvbscr.scr_enable = SCR_OFF;
+			fepriv->dvbscr.scr_id = 0;
+			err = -EINVAL;
+			dprintk("DVB: %s: Invalid value for SCR_ID in ioctl\n", __FUNCTION__);
+		}
+		if (fe->ops.set_voltage)
+			fe->ops.set_voltage(fe, SEC_VOLTAGE_13);
+		else {
+			dprintk("DVB: %s: Set Voltage not supported. SCR not possible.\n", __FUNCTION__);
+			fepriv->dvbscr.scr_enable = SCR_OFF;
+		}
+		if (fe->ops.set_tone)
+			fe->ops.set_tone(fe, SEC_TONE_OFF);
+		else {
+			dprintk("DVB: %s: Set Tone not supported. SCR not possible.\n", __FUNCTION__);
+			fepriv->dvbscr.scr_enable = SCR_OFF;
+		}
+		dtv_property_cache_sync(fe, &fepriv->parameters);
+		break;
+
 	case FE_SET_TONE:
 		if (fe->ops.set_tone) {
-			err = fe->ops.set_tone(fe, (fe_sec_tone_mode_t) parg);
-			fepriv->tone = (fe_sec_tone_mode_t) parg;
+			if (fepriv->dvbscr.scr_enable == SCR_ON) {
+				err = fe->ops.set_tone(fe, SEC_TONE_OFF);
+				fepriv->dvbscr.scr_band =
+					((fe_sec_tone_mode_t) parg == SEC_TONE_ON) ? SCR_BAND_HI : SCR_BAND_LO;
+			}
+			else {
+				err = fe->ops.set_tone(fe, (fe_sec_tone_mode_t) parg);
+				fepriv->tone = (fe_sec_tone_mode_t) parg;
+			}
 			fepriv->state = FESTATE_DISEQC;
 			fepriv->status = 0;
 		}
@@ -1707,14 +1835,26 @@  static int dvb_frontend_ioctl_legacy(str
 
 	case FE_SET_VOLTAGE:
 		if (fe->ops.set_voltage) {
-			err = fe->ops.set_voltage(fe, (fe_sec_voltage_t) parg);
-			fepriv->voltage = (fe_sec_voltage_t) parg;
+			if (fepriv->dvbscr.scr_enable == SCR_ON) {
+				err = fe->ops.set_voltage(fe, SEC_VOLTAGE_13);
+				fepriv->dvbscr.scr_polarisation =
+					((fe_sec_voltage_t) parg == SEC_VOLTAGE_18) ? SCR_POL_H : SCR_POL_V;
+			}
+			else {
+				err = fe->ops.set_voltage(fe, (fe_sec_voltage_t) parg);
+				fepriv->voltage = (fe_sec_voltage_t) parg;
+			}
 			fepriv->state = FESTATE_DISEQC;
 			fepriv->status = 0;
 		}
 		break;
 
 	case FE_DISHNETWORK_SEND_LEGACY_CMD:
+		if (fepriv->dvbscr.scr_enable == SCR_ON) {
+			dprintk("DVB: %s: Operation not available when SCR enabled\n", __FUNCTION__);
+			err = -EINVAL;
+			break;
+		}
 		if (fe->ops.dishnetwork_send_legacy_command) {
 			err = fe->ops.dishnetwork_send_legacy_command(fe, (unsigned long) parg);
 			fepriv->state = FESTATE_DISEQC;
@@ -1805,6 +1945,13 @@  static int dvb_frontend_ioctl_legacy(str
 			dtv_property_cache_sync(fe, &fepriv->parameters);
 		}
 
+		/* intercept tuning info and replace with SCR parameters */
+		if (fepriv->dvbscr.scr_enable == SCR_ON) {
+			fepriv->dvbscr.scr_frequency_orig = fepriv->parameters.frequency;
+			fepriv->parameters.frequency = (uint32_t) fepriv->dvbscr.scr_frequency * 1000;
+			scr_send_tune_cmd(fe);
+		}
+
 		memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings));
 		memcpy(&fetunesettings.parameters, parg,
 		       sizeof (struct dvb_frontend_parameters));
@@ -1877,6 +2024,10 @@  static int dvb_frontend_ioctl_legacy(str
 		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);
+			if (fepriv->dvbscr.scr_enable == SCR_ON) {
+				((struct dvb_frontend_parameters*) parg)->frequency =
+					fepriv->dvbscr.scr_frequency_orig;
+			}
 		}
 		break;
 
@@ -2068,6 +2219,16 @@  int dvb_register_frontend(struct dvb_ada
 	fe->dvb = dvb;
 	fepriv->inversion = INVERSION_OFF;
 
+	/* initialize SCR parameters */
+	fepriv->dvbscr.scr_enable = SCR_OFF;
+	fepriv->dvbscr.scr_id = 0;
+	fepriv->dvbscr.scr_frequency = 1400;
+	fepriv->dvbscr.scr_position = SCR_POS_A;
+	fe->dtv_property_cache.dvbscr.scr_enable = SCR_OFF;
+	fe->dtv_property_cache.dvbscr.scr_id = 0;
+	fe->dtv_property_cache.dvbscr.scr_frequency = 1400;
+	fe->dtv_property_cache.dvbscr.scr_position = SCR_POS_A;
+
 	printk ("DVB: registering adapter %i frontend %i (%s)...\n",
 		fe->dvb->num,
 		fe->id,
@@ -2141,3 +2302,64 @@  void dvb_frontend_detach(struct dvb_fron
 }
 #endif
 EXPORT_SYMBOL(dvb_frontend_detach);
+
+int scr_send_tune_cmd(struct dvb_frontend * fe) {
+	struct dvb_frontend_private *fepriv = fe->frontend_priv;
+	int err = 0;
+	struct timeval waketime;
+	struct dvb_diseqc_master_cmd tunecmd;
+	uint8_t channel_byte_1, channel_byte_2;
+	uint16_t frequency_calc;
+    
+	dprintk ("DVB: Tuning to %u, %s, %s using SCR. ID=%u, POS=%s, FREQ=%u\n",
+		fepriv->dvbscr.scr_frequency_orig,
+		((fepriv->dvbscr.scr_polarisation == SCR_POL_H) ? "H" : 
+		((fepriv->dvbscr.scr_polarisation == SCR_POL_V) ? "V" : "?")),
+		((fepriv->dvbscr.scr_band == SCR_BAND_HI) ? "HiBand" : "LoBand"),
+		fepriv->dvbscr.scr_id,
+		((fepriv->dvbscr.scr_position == SCR_POS_A) ? "A" : "B"),
+		fepriv->dvbscr.scr_frequency);             
+    
+	if (fepriv->dvbscr.scr_id > 7) {
+		dprintk ("DVB: %s - wrong SCR ID\n", __FUNCTION__);
+		fepriv->dvbscr.scr_id = 0;
+	}
+    
+	channel_byte_1 = (uint8_t) (fepriv->dvbscr.scr_id << 5);
+
+	if (fepriv->dvbscr.scr_position != SCR_POS_A)
+		channel_byte_1 |= (1 << 4);
+   
+	if (fepriv->dvbscr.scr_polarisation == SCR_POL_H)
+		channel_byte_1 |= (1 << 3);
+    
+	if (fepriv->dvbscr.scr_band == SCR_BAND_HI)
+		channel_byte_1 |= (1 << 2);
+            
+	if (fepriv->dvbscr.scr_frequency_orig == 0) {
+		dprintk ("DVB: %s - invalid SCR tuning\n", __FUNCTION__);
+	}
+    
+	frequency_calc = (uint16_t) ((((fepriv->dvbscr.scr_frequency_orig / 1000) + fepriv->dvbscr.scr_frequency) / 4) - 350);
+	channel_byte_1 |= (((uint8_t) (frequency_calc >> 8)) & 0x03);
+	channel_byte_2 = (uint8_t) (frequency_calc & 0x00FF);
+
+	// Send DiSEqC code E0 10 5A channel_byte_1 channel_byte_2
+	tunecmd.msg_len = 5;
+	tunecmd.msg[0] = 0xE0;
+	tunecmd.msg[1] = 0x10;
+	tunecmd.msg[2] = 0x5A;
+	tunecmd.msg[3] = channel_byte_1;
+	tunecmd.msg[4] = channel_byte_2;
+  
+	do_gettimeofday(&waketime);
+	if ((err = fe->ops.set_voltage(fe, SEC_VOLTAGE_18)) != 0) return err;
+	dvb_frontend_sleep_until(&waketime, 6000);
+	if ((err = fe->ops.diseqc_send_master_cmd(fe, &tunecmd)) != 0) return err;
+	do_gettimeofday(&waketime);
+	dvb_frontend_sleep_until(&waketime, 4000);
+	if ((err = fe->ops.set_voltage(fe, SEC_VOLTAGE_13)) != 0) return err;
+
+	return 0;
+}
+
diff -uprN a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h
--- a/drivers/media/dvb/dvb-core/dvb_frontend.h	2011-01-05 01:50:19.000000000 +0100
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.h	2011-01-10 03:12:12.000000000 +0100
@@ -343,6 +343,9 @@  struct dtv_frontend_properties {
 
 	fe_delivery_system_t	delivery_system;
 
+	/* satellite channel routing */
+	struct dvb_scr_params	dvbscr;
+
 	/* ISDB-T specifics */
 	u8			isdbt_partial_reception;
 	u8			isdbt_sb_mode;
diff -uprN a/include/linux/dvb/frontend.h b/include/linux/dvb/frontend.h
--- a/include/linux/dvb/frontend.h	2011-01-05 01:50:19.000000000 +0100
+++ b/include/linux/dvb/frontend.h	2011-01-10 03:35:47.000000000 +0100
@@ -203,6 +203,36 @@  typedef enum fe_hierarchy {
 	HIERARCHY_AUTO
 } fe_hierarchy_t;
 
+/* satellite channel routing */
+typedef enum scr_status {
+	SCR_OFF,
+	SCR_ON
+} scr_status_t;
+
+typedef enum scr_positions {
+	SCR_POS_A,
+	SCR_POS_B
+} scr_position_t;
+
+typedef enum scr_polarisations {
+	SCR_POL_V,
+	SCR_POL_H
+} scr_polarisation_t;
+
+typedef enum scr_bands {
+	SCR_BAND_LO,
+	SCR_BAND_HI
+} scr_band_t;
+
+struct dvb_scr_params {
+	scr_status_t		scr_enable;		/* enable or disable SCR */
+	__u8			scr_id;			/* internal SCR id */
+	scr_position_t		scr_position;		/* SCR satellite position (A or B) */
+	__u32			scr_frequency;		/* SCR frequency we tune to */
+	__u32			scr_frequency_orig;	/* DVB frequency sent to router */
+	scr_polarisation_t	scr_polarisation;	/* DVB polarisation (replaces SEC voltage) */
+	scr_band_t		scr_band;		/* DVB band (replaces SEC tone) */
+};
 
 struct dvb_qpsk_parameters {
 	__u32		symbol_rate;  /* symbol rate in Symbols per second */
@@ -411,4 +441,7 @@  struct dtv_properties {
 
 #define FE_DISHNETWORK_SEND_LEGACY_CMD _IO('o', 80) /* unsigned int */
 
+/* satellite channel routing */
+#define FE_SET_SCR                 _IOW('o', 120, struct dvb_scr_params)
+
 #endif /*_DVBFRONTEND_H_*/