aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.c571
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.h44
-rw-r--r--include/linux/dvb/frontend.h130
3 files changed, 737 insertions, 8 deletions
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index 3526e3ee9487..e68974b2fee9 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -755,6 +755,535 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe,
755 return 0; 755 return 0;
756} 756}
757 757
758struct tv_cmds_h tv_cmds[] = {
759 [TV_SEQ_UNDEFINED] = {
760 .name = "TV_SEQ_UNDEFINED",
761 .cmd = TV_SEQ_UNDEFINED,
762 .set = 1,
763 },
764 [TV_SEQ_START] = {
765 .name = "TV_SEQ_START",
766 .cmd = TV_SEQ_START,
767 .set = 1,
768 },
769 [TV_SEQ_CONTINUE] = {
770 .name = "TV_SEQ_CONTINUE",
771 .cmd = TV_SEQ_CONTINUE,
772 .set = 1,
773 },
774 [TV_SEQ_COMPLETE] = {
775 .name = "TV_SEQ_COMPLETE",
776 .cmd = TV_SEQ_COMPLETE,
777 .set = 1,
778 },
779 [TV_SEQ_TERMINATE] = {
780 .name = "TV_SEQ_TERMINATE",
781 .cmd = TV_SEQ_TERMINATE,
782 .set = 1,
783 },
784
785 /* Set */
786 [TV_SET_FREQUENCY] = {
787 .name = "TV_SET_FREQUENCY",
788 .cmd = TV_SET_FREQUENCY,
789 .set = 1,
790 },
791 [TV_SET_BANDWIDTH] = {
792 .name = "TV_SET_BANDWIDTH",
793 .cmd = TV_SET_BANDWIDTH,
794 .set = 1,
795 },
796 [TV_SET_MODULATION] = {
797 .name = "TV_SET_MODULATION",
798 .cmd = TV_SET_MODULATION,
799 .set = 1,
800 },
801 [TV_SET_INVERSION] = {
802 .name = "TV_SET_INVERSION",
803 .cmd = TV_SET_INVERSION,
804 .set = 1,
805 },
806 [TV_SET_DISEQC_MASTER] = {
807 .name = "TV_SET_DISEQC_MASTER",
808 .cmd = TV_SET_DISEQC_MASTER,
809 .set = 1,
810 .buffer = 1,
811 },
812 [TV_SET_SYMBOLRATE] = {
813 .name = "TV_SET_SYMBOLRATE",
814 .cmd = TV_SET_SYMBOLRATE,
815 .set = 1,
816 },
817 [TV_SET_INNERFEC] = {
818 .name = "TV_SET_INNERFEC",
819 .cmd = TV_SET_INNERFEC,
820 .set = 1,
821 },
822 [TV_SET_VOLTAGE] = {
823 .name = "TV_SET_VOLTAGE",
824 .cmd = TV_SET_VOLTAGE,
825 .set = 1,
826 },
827 [TV_SET_TONE] = {
828 .name = "TV_SET_TONE",
829 .cmd = TV_SET_TONE,
830 .set = 1,
831 },
832 [TV_SET_PILOT] = {
833 .name = "TV_SET_PILOT",
834 .cmd = TV_SET_PILOT,
835 .set = 1,
836 },
837 [TV_SET_ROLLOFF] = {
838 .name = "TV_SET_ROLLOFF",
839 .cmd = TV_SET_ROLLOFF,
840 .set = 1,
841 },
842 [TV_SET_DELIVERY_SYSTEM] = {
843 .name = "TV_SET_DELIVERY_SYSTEM",
844 .cmd = TV_SET_DELIVERY_SYSTEM,
845 .set = 1,
846 },
847 [TV_SET_ISDB_SEGMENT_NUM] = {
848 .name = "TV_SET_ISDB_SEGMENT_NUM",
849 .cmd = TV_SET_ISDB_SEGMENT_NUM,
850 .set = 1,
851 },
852 [TV_SET_ISDB_SEGMENT_WIDTH] = {
853 .name = "TV_SET_ISDB_SEGMENT_WIDTH",
854 .cmd = TV_SET_ISDB_SEGMENT_WIDTH,
855 .set = 1,
856 },
857
858 /* Get */
859 [TV_GET_FREQUENCY] = {
860 .name = "TV_GET_FREQUENCY",
861 .cmd = TV_GET_FREQUENCY,
862 .set = 0,
863 },
864 [TV_GET_BANDWIDTH] = {
865 .name = "TV_GET_BANDWIDTH",
866 .cmd = TV_GET_BANDWIDTH,
867 .set = 0,
868 },
869 [TV_GET_MODULATION] = {
870 .name = "TV_GET_MODULATION",
871 .cmd = TV_GET_MODULATION,
872 .set = 0,
873 },
874 [TV_GET_INVERSION] = {
875 .name = "TV_GET_INVERSION",
876 .cmd = TV_GET_INVERSION,
877 .set = 0,
878 },
879 [TV_GET_DISEQC_SLAVE_REPLY] = {
880 .name = "TV_GET_DISEQC_SLAVE_REPLY",
881 .cmd = TV_GET_DISEQC_SLAVE_REPLY,
882 .set = 0,
883 .buffer = 1,
884 },
885 [TV_GET_SYMBOLRATE] = {
886 .name = "TV_GET_SYMBOLRATE",
887 .cmd = TV_GET_SYMBOLRATE,
888 .set = 0,
889 },
890 [TV_GET_INNERFEC] = {
891 .name = "TV_GET_INNERFEC",
892 .cmd = TV_GET_INNERFEC,
893 .set = 0,
894 },
895 [TV_GET_VOLTAGE] = {
896 .name = "TV_GET_VOLTAGE",
897 .cmd = TV_GET_VOLTAGE,
898 .set = 0,
899 },
900 [TV_GET_TONE] = {
901 .name = "TV_GET_TONE",
902 .cmd = TV_GET_TONE,
903 .set = 0,
904 },
905 [TV_GET_PILOT] = {
906 .name = "TV_GET_PILOT",
907 .cmd = TV_GET_PILOT,
908 .set = 0,
909 },
910 [TV_GET_ROLLOFF] = {
911 .name = "TV_GET_ROLLOFF",
912 .cmd = TV_GET_ROLLOFF,
913 .set = 0,
914 },
915 [TV_GET_DELIVERY_SYSTEM] = {
916 .name = "TV_GET_DELIVERY_SYSTEM",
917 .cmd = TV_GET_DELIVERY_SYSTEM,
918 .set = 0,
919 },
920 [TV_GET_ISDB_SEGMENT_NUM] = {
921 .name = "TV_GET_ISDB_SEGMENT_NUM",
922 .cmd = TV_GET_ISDB_SEGMENT_NUM,
923 .set = 0,
924 },
925 [TV_GET_ISDB_SEGMENT_WIDTH] = {
926 .name = "TV_GET_ISDB_SEGMENT_WIDTH",
927 .cmd = TV_GET_ISDB_SEGMENT_WIDTH,
928 .set = 0,
929 },
930 [TV_GET_ISDB_LAYERA_FEC] = {
931 .name = "TV_GET_ISDB_LAYERA_FEC",
932 .cmd = TV_GET_ISDB_LAYERA_FEC,
933 .set = 0,
934 },
935 [TV_GET_ISDB_LAYERA_MODULATION] = {
936 .name = "TV_GET_ISDB_LAYERA_MODULATION",
937 .cmd = TV_GET_ISDB_LAYERA_MODULATION,
938 .set = 0,
939 },
940 [TV_GET_ISDB_LAYERA_SEGMENT_WIDTH] = {
941 .name = "TV_GET_ISDB_LAYERA_SEGMENT_WIDTH",
942 .cmd = TV_GET_ISDB_LAYERA_SEGMENT_WIDTH,
943 .set = 0,
944 },
945 [TV_GET_ISDB_LAYERB_FEC] = {
946 .name = "TV_GET_ISDB_LAYERB_FEC",
947 .cmd = TV_GET_ISDB_LAYERB_FEC,
948 .set = 0,
949 },
950 [TV_GET_ISDB_LAYERB_MODULATION] = {
951 .name = "TV_GET_ISDB_LAYERB_MODULATION",
952 .cmd = TV_GET_ISDB_LAYERB_MODULATION,
953 .set = 0,
954 },
955 [TV_GET_ISDB_LAYERB_SEGMENT_WIDTH] = {
956 .name = "TV_GET_ISDB_LAYERB_SEGMENT_WIDTH",
957 .cmd = TV_GET_ISDB_LAYERB_SEGMENT_WIDTH,
958 .set = 0,
959 },
960 [TV_GET_ISDB_LAYERC_FEC] = {
961 .name = "TV_GET_ISDB_LAYERC_FEC",
962 .cmd = TV_GET_ISDB_LAYERC_FEC,
963 .set = 0,
964 },
965 [TV_GET_ISDB_LAYERC_MODULATION] = {
966 .name = "TV_GET_ISDB_LAYERC_MODULATION",
967 .cmd = TV_GET_ISDB_LAYERC_MODULATION,
968 .set = 0,
969 },
970 [TV_GET_ISDB_LAYERC_SEGMENT_WIDTH] = {
971 .name = "TV_GET_ISDB_LAYERC_SEGMENT_WIDTH",
972 .cmd = TV_GET_ISDB_LAYERC_SEGMENT_WIDTH,
973 .set = 0,
974 },
975};
976
977void tv_property_dump(tv_property_t *tvp)
978{
979 int i;
980
981 printk("%s() tvp.cmd = 0x%08x (%s)\n"
982 ,__FUNCTION__
983 ,tvp->cmd
984 ,tv_cmds[ tvp->cmd ].name);
985
986 if(tv_cmds[ tvp->cmd ].buffer) {
987
988 printk("%s() tvp.u.buffer.len = 0x%02x\n"
989 ,__FUNCTION__
990 ,tvp->u.buffer.len);
991
992 for(i = 0; i < tvp->u.buffer.len; i++)
993 printk("%s() tvp.u.buffer.data[0x%02x] = 0x%02x\n"
994 ,__FUNCTION__
995 ,i
996 ,tvp->u.buffer.data[i]);
997
998 } else
999 printk("%s() tvp.u.data = 0x%08x\n", __FUNCTION__, tvp->u.data);
1000}
1001
1002int is_legacy_delivery_system(fe_delivery_system_t s)
1003{
1004 if((s == SYS_UNDEFINED) || (s == SYS_DVBC_ANNEX_AC) ||
1005 (s == SYS_DVBC_ANNEX_B) || (s == SYS_DVBT) || (s == SYS_DVBS))
1006 return 1;
1007
1008 return 0;
1009}
1010
1011int tv_property_cache_submit(struct dvb_frontend *fe)
1012{
1013
1014 /* We have to do one of two things:
1015 * To support legacy devices using the new API we take values from
1016 * the tv_cache and generate a legacy truning structure.
1017 *
1018 * Or,
1019 *
1020 * To support advanced tuning devices with the new API we
1021 * notify the new advance driver type that a tuning operation is required
1022 * and let it pull values from the cache as is, we don't need to
1023 * pass structures.
1024 *
1025 * We'll use the modulation type to assess how this is handled. as the API
1026 * progresses we'll probably want to have a flag in dvb_frontend_ops
1027 * to allow the frontend driver to dictate how it likes to be tuned.
1028 *
1029 * Because of how this is attached to the ioctl handler for legacy support,
1030 * it's important to return an appropriate result code with atleast the following
1031 * three meanings:
1032 * < 0 = processing error
1033 * 0 = lecagy ioctl handler to submit a traditional set_frontend() call.
1034 * 1 = lecagy ioctl handler should NOT submit a traditional set_frontend() call.
1035 */
1036
1037 int r;
1038
1039 struct tv_frontend_properties *c = &fe->tv_property_cache;
1040 struct dvb_frontend_private *fepriv = fe->frontend_priv;
1041 struct dvb_frontend_parameters p;
1042
1043 printk("%s()\n", __FUNCTION__);
1044
1045 /* For legacy delivery systems we don't need the delivery_system to be specified */
1046 if(is_legacy_delivery_system(c->delivery_system)) {
1047 switch(c->modulation) {
1048 case QPSK:
1049 printk("%s() Preparing QPSK req\n", __FUNCTION__);
1050 p.frequency = c->frequency;
1051 p.inversion = c->inversion;
1052 p.u.qpsk.symbol_rate = c->symbol_rate;
1053 p.u.qpsk.fec_inner = c->fec_inner;
1054 memcpy(&fepriv->parameters, &p,
1055 sizeof (struct dvb_frontend_parameters));
1056
1057 /* Call the traditional tuning mechanisms. */
1058
1059 r = 0;
1060 break;
1061 case QAM_16:
1062 case QAM_32:
1063 case QAM_64:
1064 case QAM_128:
1065 case QAM_256:
1066 case QAM_AUTO:
1067 printk("%s() Preparing QAM req\n", __FUNCTION__);
1068 p.frequency = c->frequency;
1069 p.inversion = c->inversion;
1070 p.u.qam.symbol_rate = c->symbol_rate;
1071 p.u.vsb.modulation = c->modulation;
1072 printk("%s() frequency = %d\n", __FUNCTION__, p.frequency);
1073 printk("%s() QAM = %d\n", __FUNCTION__, p.u.vsb.modulation);
1074 memcpy(&fepriv->parameters, &p,
1075 sizeof (struct dvb_frontend_parameters));
1076
1077 /* At this point we're fully formed for backwards
1078 * compatability and we need to return this
1079 * via the ioctl handler as SET_FRONTEND (arg).
1080 * We've already patched the new values into the
1081 * frontends tuning structures so the ioctl code just
1082 * continues as if a legacy tune structure was passed
1083 * from userspace.
1084 */
1085
1086 r = 0;
1087 break;
1088 case VSB_8:
1089 case VSB_16:
1090 printk("%s() Preparing VSB req\n", __FUNCTION__);
1091 p.frequency = c->frequency;
1092 p.u.vsb.modulation = c->modulation;
1093 memcpy(&fepriv->parameters, &p,
1094 sizeof (struct dvb_frontend_parameters));
1095
1096 /* Call the traditional tuning mechanisms. */
1097
1098 r = 0;
1099 break;
1100 /* TODO: Add any missing modulation types */
1101 default:
1102 r = -1;
1103 }
1104 } else {
1105 /* For advanced delivery systems / modulation types ...
1106 * we seed the lecacy dvb_frontend_parameters structure
1107 * so that the sanity checking code later in the IOCTL processing
1108 * can validate our basic frequency ranges, symbolrates, modulation
1109 * etc.
1110 */
1111 r = -1;
1112
1113 switch(c->modulation) {
1114 case _8PSK:
1115 case _16APSK:
1116 case NBC_QPSK:
1117 /* Just post a notification to the demod driver and let it pull
1118 * the specific values it wants from its tv_property_cache.
1119 * It can decide how best to use those parameters.
1120 * IOCTL will call set_frontend (by default) due to zigzag
1121 * support etc.
1122 */
1123 if (fe->ops.set_params)
1124 r = fe->ops.set_params(fe);
1125
1126 p.frequency = c->frequency;
1127 p.inversion = c->inversion;
1128 p.u.qpsk.symbol_rate = c->symbol_rate;
1129 p.u.qpsk.fec_inner = c->fec_inner;
1130 memcpy(&fepriv->parameters, &p,
1131 sizeof (struct dvb_frontend_parameters));
1132
1133 r = 0;
1134 break;
1135 default:
1136 r = -1;
1137 }
1138
1139 if(c->delivery_system == SYS_ISDBT) {
1140 /* Fake out a generic DVB-T request so we pass validation in the ioctl */
1141 p.frequency = c->frequency;
1142 p.inversion = INVERSION_AUTO;
1143 p.u.ofdm.constellation = QAM_AUTO;
1144 p.u.ofdm.code_rate_HP = FEC_AUTO;
1145 p.u.ofdm.code_rate_LP = FEC_AUTO;
1146 p.u.ofdm.bandwidth = BANDWIDTH_AUTO;
1147 p.u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO;
1148 p.u.ofdm.guard_interval = GUARD_INTERVAL_AUTO;
1149 p.u.ofdm.hierarchy_information = HIERARCHY_AUTO;
1150 memcpy(&fepriv->parameters, &p,
1151 sizeof (struct dvb_frontend_parameters));
1152
1153 r = 0;
1154 }
1155 }
1156 return r;
1157}
1158
1159int tv_property_process(struct dvb_frontend *fe, tv_property_t *tvp)
1160{
1161 int r = 0;
1162 printk("%s()\n", __FUNCTION__);
1163 tv_property_dump(tvp);
1164
1165 switch(tvp->cmd) {
1166 case TV_SEQ_START:
1167 case TV_SEQ_TERMINATE:
1168 /* Reset a cache of data specific to the frontend here. This does
1169 * not effect hardware.
1170 */
1171 printk("%s() Flushing property cache\n", __FUNCTION__);
1172 memset(&fe->tv_property_cache, 0, sizeof(struct tv_frontend_properties));
1173 fe->tv_property_cache.state = TV_SEQ_START;
1174 fe->tv_property_cache.delivery_system = SYS_UNDEFINED;
1175 break;
1176 case TV_SEQ_COMPLETE:
1177 /* interpret the cache of data, build either a traditional frontend
1178 * tunerequest and submit it to a subset of the ioctl handler,
1179 * or, call a new undefined method on the frontend to deal with
1180 * all new tune requests.
1181 */
1182 fe->tv_property_cache.state = TV_SEQ_COMPLETE;
1183 printk("%s() Finalised property cache\n", __FUNCTION__);
1184 r = tv_property_cache_submit(fe);
1185 break;
1186 case TV_SET_FREQUENCY:
1187 fe->tv_property_cache.frequency = tvp->u.data;
1188 break;
1189 case TV_GET_FREQUENCY:
1190 tvp->u.data = fe->tv_property_cache.frequency;
1191 break;
1192 case TV_SET_MODULATION:
1193 fe->tv_property_cache.modulation = tvp->u.data;
1194 break;
1195 case TV_GET_MODULATION:
1196 tvp->u.data = fe->tv_property_cache.modulation;
1197 break;
1198 case TV_SET_BANDWIDTH:
1199 fe->tv_property_cache.bandwidth = tvp->u.data;
1200 break;
1201 case TV_GET_BANDWIDTH:
1202 tvp->u.data = fe->tv_property_cache.bandwidth;
1203 break;
1204 case TV_SET_INVERSION:
1205 fe->tv_property_cache.inversion = tvp->u.data;
1206 break;
1207 case TV_GET_INVERSION:
1208 tvp->u.data = fe->tv_property_cache.inversion;
1209 break;
1210 case TV_SET_SYMBOLRATE:
1211 fe->tv_property_cache.symbol_rate = tvp->u.data;
1212 break;
1213 case TV_GET_SYMBOLRATE:
1214 tvp->u.data = fe->tv_property_cache.symbol_rate;
1215 break;
1216 case TV_SET_INNERFEC:
1217 fe->tv_property_cache.fec_inner = tvp->u.data;
1218 break;
1219 case TV_GET_INNERFEC:
1220 tvp->u.data = fe->tv_property_cache.fec_inner;
1221 break;
1222 case TV_SET_PILOT:
1223 fe->tv_property_cache.pilot = tvp->u.data;
1224 break;
1225 case TV_GET_PILOT:
1226 tvp->u.data = fe->tv_property_cache.pilot;
1227 break;
1228 case TV_SET_ROLLOFF:
1229 fe->tv_property_cache.rolloff = tvp->u.data;
1230 break;
1231 case TV_GET_ROLLOFF:
1232 tvp->u.data = fe->tv_property_cache.rolloff;
1233 break;
1234 case TV_SET_DELIVERY_SYSTEM:
1235 fe->tv_property_cache.delivery_system = tvp->u.data;
1236 break;
1237 case TV_GET_DELIVERY_SYSTEM:
1238 tvp->u.data = fe->tv_property_cache.delivery_system;
1239 break;
1240
1241 /* ISDB-T Support here */
1242 case TV_SET_ISDB_SEGMENT_NUM:
1243 fe->tv_property_cache.isdb_segment_num = tvp->u.data;
1244 break;
1245 case TV_GET_ISDB_SEGMENT_NUM:
1246 tvp->u.data = fe->tv_property_cache.isdb_segment_num;
1247 break;
1248 case TV_SET_ISDB_SEGMENT_WIDTH:
1249 fe->tv_property_cache.isdb_segment_width = tvp->u.data;
1250 break;
1251 case TV_GET_ISDB_SEGMENT_WIDTH:
1252 tvp->u.data = fe->tv_property_cache.isdb_segment_width;
1253 break;
1254 case TV_GET_ISDB_LAYERA_FEC:
1255 tvp->u.data = fe->tv_property_cache.isdb_layera_fec;
1256 break;
1257 case TV_GET_ISDB_LAYERA_MODULATION:
1258 tvp->u.data = fe->tv_property_cache.isdb_layera_modulation;
1259 break;
1260 case TV_GET_ISDB_LAYERA_SEGMENT_WIDTH:
1261 tvp->u.data = fe->tv_property_cache.isdb_layera_segment_width;
1262 break;
1263 case TV_GET_ISDB_LAYERB_FEC:
1264 tvp->u.data = fe->tv_property_cache.isdb_layerb_fec;
1265 break;
1266 case TV_GET_ISDB_LAYERB_MODULATION:
1267 tvp->u.data = fe->tv_property_cache.isdb_layerb_modulation;
1268 break;
1269 case TV_GET_ISDB_LAYERB_SEGMENT_WIDTH:
1270 tvp->u.data = fe->tv_property_cache.isdb_layerb_segment_width;
1271 break;
1272 case TV_GET_ISDB_LAYERC_FEC:
1273 tvp->u.data = fe->tv_property_cache.isdb_layerc_fec;
1274 break;
1275 case TV_GET_ISDB_LAYERC_MODULATION:
1276 tvp->u.data = fe->tv_property_cache.isdb_layerc_modulation;
1277 break;
1278 case TV_GET_ISDB_LAYERC_SEGMENT_WIDTH:
1279 tvp->u.data = fe->tv_property_cache.isdb_layerc_segment_width;
1280 break;
1281
1282 }
1283
1284 return 0;
1285}
1286
758static int dvb_frontend_ioctl(struct inode *inode, struct file *file, 1287static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
759 unsigned int cmd, void *parg) 1288 unsigned int cmd, void *parg)
760{ 1289{
@@ -762,6 +1291,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
762 struct dvb_frontend *fe = dvbdev->priv; 1291 struct dvb_frontend *fe = dvbdev->priv;
763 struct dvb_frontend_private *fepriv = fe->frontend_priv; 1292 struct dvb_frontend_private *fepriv = fe->frontend_priv;
764 int err = -EOPNOTSUPP; 1293 int err = -EOPNOTSUPP;
1294 tv_property_t* tvp;
765 1295
766 dprintk ("%s\n", __func__); 1296 dprintk ("%s\n", __func__);
767 1297
@@ -776,6 +1306,27 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
776 if (down_interruptible (&fepriv->sem)) 1306 if (down_interruptible (&fepriv->sem))
777 return -ERESTARTSYS; 1307 return -ERESTARTSYS;
778 1308
1309 if(cmd == FE_SET_PROPERTY) {
1310 printk("%s() FE_SET_PROPERTY\n", __FUNCTION__);
1311
1312 /* TODO: basic property validation here */
1313
1314 /* TODO: ioctl userdata out of range check here */
1315 tvp = parg;
1316 while(tvp->cmd != TV_SEQ_UNDEFINED) {
1317 tv_property_process(fe, tvp);
1318 if( (tvp->cmd == TV_SEQ_TERMINATE) || (tvp->cmd == TV_SEQ_COMPLETE) )
1319 break;
1320 tvp++;
1321 }
1322
1323 if(fe->tv_property_cache.state == TV_SEQ_COMPLETE) {
1324 printk("%s() Property cache is full, tuning\n", __FUNCTION__);
1325 cmd = FE_SET_FRONTEND;
1326 }
1327 err = 0;
1328 }
1329
779 switch (cmd) { 1330 switch (cmd) {
780 case FE_GET_INFO: { 1331 case FE_GET_INFO: {
781 struct dvb_frontend_info* info = parg; 1332 struct dvb_frontend_info* info = parg;
@@ -942,13 +1493,20 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
942 case FE_SET_FRONTEND: { 1493 case FE_SET_FRONTEND: {
943 struct dvb_frontend_tune_settings fetunesettings; 1494 struct dvb_frontend_tune_settings fetunesettings;
944 1495
945 if (dvb_frontend_check_parameters(fe, parg) < 0) { 1496 if(fe->tv_property_cache.state == TV_SEQ_COMPLETE) {
946 err = -EINVAL; 1497 if (dvb_frontend_check_parameters(fe, &fepriv->parameters) < 0) {
947 break; 1498 err = -EINVAL;
948 } 1499 break;
1500 }
1501 } else {
1502 if (dvb_frontend_check_parameters(fe, parg) < 0) {
1503 err = -EINVAL;
1504 break;
1505 }
949 1506
950 memcpy (&fepriv->parameters, parg, 1507 memcpy (&fepriv->parameters, parg,
951 sizeof (struct dvb_frontend_parameters)); 1508 sizeof (struct dvb_frontend_parameters));
1509 }
952 1510
953 memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings)); 1511 memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings));
954 memcpy(&fetunesettings.parameters, parg, 1512 memcpy(&fetunesettings.parameters, parg,
@@ -1031,6 +1589,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
1031 return err; 1589 return err;
1032} 1590}
1033 1591
1592
1034static unsigned int dvb_frontend_poll(struct file *file, struct poll_table_struct *wait) 1593static unsigned int dvb_frontend_poll(struct file *file, struct poll_table_struct *wait)
1035{ 1594{
1036 struct dvb_device *dvbdev = file->private_data; 1595 struct dvb_device *dvbdev = file->private_data;
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h
index aa4133f0bd19..61d53ee70f2a 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.h
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.h
@@ -169,6 +169,10 @@ struct dvb_frontend_ops {
169 169
170 struct dvb_tuner_ops tuner_ops; 170 struct dvb_tuner_ops tuner_ops;
171 struct analog_demod_ops analog_ops; 171 struct analog_demod_ops analog_ops;
172
173 int (*set_property)(struct dvb_frontend* fe, tv_property_t* tvp);
174 int (*get_property)(struct dvb_frontend* fe, tv_property_t* tvp);
175 int (*set_params)(struct dvb_frontend* fe);
172}; 176};
173 177
174#define MAX_EVENT 8 178#define MAX_EVENT 8
@@ -182,6 +186,45 @@ struct dvb_fe_events {
182 struct mutex mtx; 186 struct mutex mtx;
183}; 187};
184 188
189struct tv_frontend_properties {
190
191 /* Cache State */
192 u32 state;
193
194 u32 frequency;
195 fe_modulation_t modulation;
196
197 fe_sec_voltage_t voltage;
198 fe_sec_tone_mode_t sectone;
199 fe_spectral_inversion_t inversion;
200 fe_code_rate_t fec_inner;
201 fe_transmit_mode_t transmission_mode;
202 fe_bandwidth_t bandwidth;
203 fe_guard_interval_t guard_interval;
204 fe_hierarchy_t hierarchy;
205 u32 symbol_rate;
206 fe_code_rate_t code_rate_HP;
207 fe_code_rate_t code_rate_LP;
208
209 fe_pilot_t pilot;
210 fe_rolloff_t rolloff;
211
212 fe_delivery_system_t delivery_system;
213
214 /* ISDB-T specifics */
215 u32 isdb_segment_num;
216 u32 isdb_segment_width;
217 fe_code_rate_t isdb_layera_fec;
218 fe_modulation_t isdb_layera_modulation;
219 u32 isdb_layera_segment_width;
220 fe_code_rate_t isdb_layerb_fec;
221 fe_modulation_t isdb_layerb_modulation;
222 u32 isdb_layerb_segment_width;
223 fe_code_rate_t isdb_layerc_fec;
224 fe_modulation_t isdb_layerc_modulation;
225 u32 isdb_layerc_segment_width;
226};
227
185struct dvb_frontend { 228struct dvb_frontend {
186 struct dvb_frontend_ops ops; 229 struct dvb_frontend_ops ops;
187 struct dvb_adapter *dvb; 230 struct dvb_adapter *dvb;
@@ -190,6 +233,7 @@ struct dvb_frontend {
190 void *frontend_priv; 233 void *frontend_priv;
191 void *sec_priv; 234 void *sec_priv;
192 void *analog_demod_priv; 235 void *analog_demod_priv;
236 struct tv_frontend_properties tv_property_cache;
193}; 237};
194 238
195extern int dvb_register_frontend(struct dvb_adapter *dvb, 239extern int dvb_register_frontend(struct dvb_adapter *dvb,
diff --git a/include/linux/dvb/frontend.h b/include/linux/dvb/frontend.h
index c8cbd90ba375..4d3770021736 100644
--- a/include/linux/dvb/frontend.h
+++ b/include/linux/dvb/frontend.h
@@ -62,6 +62,7 @@ typedef enum fe_caps {
62 FE_CAN_HIERARCHY_AUTO = 0x100000, 62 FE_CAN_HIERARCHY_AUTO = 0x100000,
63 FE_CAN_8VSB = 0x200000, 63 FE_CAN_8VSB = 0x200000,
64 FE_CAN_16VSB = 0x400000, 64 FE_CAN_16VSB = 0x400000,
65 FE_HAS_EXTENDED_CAPS = 0x800000, // We need more bitspace for newer APIs, indicate this.
65 FE_NEEDS_BENDING = 0x20000000, // not supported anymore, don't use (frontend requires frequency bending) 66 FE_NEEDS_BENDING = 0x20000000, // not supported anymore, don't use (frontend requires frequency bending)
66 FE_CAN_RECOVER = 0x40000000, // frontend can recover from a cable unplug automatically 67 FE_CAN_RECOVER = 0x40000000, // frontend can recover from a cable unplug automatically
67 FE_CAN_MUTE_TS = 0x80000000 // frontend can stop spurious TS data output 68 FE_CAN_MUTE_TS = 0x80000000 // frontend can stop spurious TS data output
@@ -147,7 +148,9 @@ typedef enum fe_code_rate {
147 FEC_6_7, 148 FEC_6_7,
148 FEC_7_8, 149 FEC_7_8,
149 FEC_8_9, 150 FEC_8_9,
150 FEC_AUTO 151 FEC_AUTO,
152 FEC_3_5,
153 FEC_9_10,
151} fe_code_rate_t; 154} fe_code_rate_t;
152 155
153 156
@@ -160,7 +163,11 @@ typedef enum fe_modulation {
160 QAM_256, 163 QAM_256,
161 QAM_AUTO, 164 QAM_AUTO,
162 VSB_8, 165 VSB_8,
163 VSB_16 166 VSB_16,
167 _8PSK,
168 _16APSK,
169 NBC_QPSK,
170 DQPSK,
164} fe_modulation_t; 171} fe_modulation_t;
165 172
166typedef enum fe_transmit_mode { 173typedef enum fe_transmit_mode {
@@ -239,6 +246,125 @@ struct dvb_frontend_event {
239 struct dvb_frontend_parameters parameters; 246 struct dvb_frontend_parameters parameters;
240}; 247};
241 248
249/* TODO: Turn this into a series of defines, so future maintainers
250 * don't insert random new commands and break backwards
251 * binary compatability.
252 */
253typedef enum tv_cmd_types {
254 TV_SEQ_UNDEFINED,
255 TV_SEQ_START,
256 TV_SEQ_CONTINUE,
257 TV_SEQ_COMPLETE,
258 TV_SEQ_TERMINATE,
259
260 TV_SET_FREQUENCY,
261 TV_SET_MODULATION,
262 TV_SET_BANDWIDTH,
263 TV_SET_INVERSION,
264 TV_SET_DISEQC_MASTER,
265 TV_SET_SYMBOLRATE,
266 TV_SET_INNERFEC,
267 TV_SET_VOLTAGE,
268 TV_SET_TONE,
269 TV_SET_PILOT,
270 TV_SET_ROLLOFF,
271
272 TV_GET_FREQUENCY,
273 TV_GET_MODULATION,
274 TV_GET_BANDWIDTH,
275 TV_GET_INVERSION,
276 TV_GET_DISEQC_SLAVE_REPLY,
277 TV_GET_SYMBOLRATE,
278 TV_GET_INNERFEC,
279 TV_GET_VOLTAGE,
280 TV_GET_TONE,
281 TV_GET_PILOT,
282 TV_GET_ROLLOFF,
283
284 /* Basic enumeration set for querying unlimited capabilities */
285 TV_GET_FE_CAPABILITY_COUNT,
286 TV_GET_FE_CAPABILITY,
287
288 /* New commands are always appended */
289 TV_SET_DELIVERY_SYSTEM,
290 TV_GET_DELIVERY_SYSTEM,
291
292 /* ISDB-T */
293 TV_SET_ISDB_SEGMENT_NUM,
294 TV_GET_ISDB_SEGMENT_NUM,
295 TV_SET_ISDB_SEGMENT_WIDTH,
296 TV_GET_ISDB_SEGMENT_WIDTH,
297 TV_GET_ISDB_LAYERA_FEC,
298 TV_GET_ISDB_LAYERA_MODULATION,
299 TV_GET_ISDB_LAYERA_SEGMENT_WIDTH,
300 TV_GET_ISDB_LAYERB_FEC,
301 TV_GET_ISDB_LAYERB_MODULATION,
302 TV_GET_ISDB_LAYERB_SEGMENT_WIDTH,
303 TV_GET_ISDB_LAYERC_FEC,
304 TV_GET_ISDB_LAYERC_MODULATION,
305 TV_GET_ISDB_LAYERC_SEGMENT_WIDTH,
306
307} tv_cmd_types_t;
308
309typedef enum fe_pilot {
310 PILOT_ON,
311 PILOT_OFF,
312 PILOT_AUTO,
313} fe_pilot_t;
314
315typedef enum fe_rolloff {
316 ROLLOFF_20,
317 ROLLOFF_25,
318 ROLLOFF_35,
319 ROLLOFF_AUTO,
320} fe_rolloff_t;
321
322typedef enum fe_delivery_system {
323 SYS_UNDEFINED,
324 SYS_DVBC_ANNEX_AC,
325 SYS_DVBC_ANNEX_B,
326 SYS_DVBT,
327 SYS_DVBS,
328 SYS_DVBS2,
329 SYS_DVBH,
330 SYS_ISDBT,
331 SYS_ISDBS,
332 SYS_ISDBC,
333 SYS_ATSC,
334 SYS_ATSCMH,
335 SYS_DMBTH,
336 SYS_CMMB,
337 SYS_DAB,
338} fe_delivery_system_t;
339
340struct tv_cmds_h {
341 char *name; /* A display name for debugging purposes */
342
343 __u32 cmd; /* A unique ID */
344
345 /* Flags */
346 __u32 set:1; /* Either a set or get property */
347 __u32 buffer:1; /* Does this property use the buffer? */
348 __u32 reserved:30; /* Align */
349};
350
351typedef struct {
352 __u32 cmd;
353 union {
354 __u32 data;
355 struct {
356 __u8 data[32];
357 __u32 len;
358 } buffer;
359 } u;
360} tv_property_t;
361
362/* No more than 16 properties during any given ioctl */
363typedef tv_property_t tv_properties_t[16];
364
365#define FE_SET_PROPERTY _IOW('o', 82, tv_properties_t)
366#define FE_GET_PROPERTY _IOR('o', 83, tv_properties_t)
367
242 368
243/** 369/**
244 * When set, this flag will disable any zigzagging or other "normal" tuning 370 * When set, this flag will disable any zigzagging or other "normal" tuning