aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Toth <stoth@linuxtv.org>2008-09-04 00:12:25 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2008-10-12 07:37:03 -0400
commit6b73eeafbc856c0cef7166242f0e55403407f355 (patch)
treed385a9c8c8eb0682c2690ca0b2352bea96349f52
parent05c1cab55c282199b85138dc1900b5d9bd6fb32a (diff)
V4L/DVB (8985): S2API: Added dvb frontend changes to support a newer tuning API
This is an experimental patch to add a new tuning mechanism for dvb frontends. Rather than passing fixed structures across the user/kernel boundary, which need to be revised for each new modulation type (or feature the kernel developers want to add), this implements a simpler message based approach, allowing fe commands to be broken down into a series of small fixed size transactions, presented in an array. The goal is to avoid changing the user/kernel ABI in the future, by simply creating new frontend commands (and sequencies of commands) that help us add support for brand new demodulator, delivery system or statistics related commmands. known issues: checkpatch voilations feedback from various developers yet to be implemented, relating to namespace conventions, variable length array passing conventions, and generally some optimization. This patch should support all existing tuning mechanisms through the new API, as well as adding 8PSK, DVB-S2 NBC-QPSK and ISDB-T API support. For testing and exercise purposes, see the latest tune.c tool available from http://www.steventoth.net/linux/s2 Signed-off-by: Steven Toth <stoth@linuxtv.org> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-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