diff options
-rw-r--r-- | drivers/media/dvb/dvb-core/dvb_frontend.c | 571 | ||||
-rw-r--r-- | drivers/media/dvb/dvb-core/dvb_frontend.h | 44 | ||||
-rw-r--r-- | include/linux/dvb/frontend.h | 130 |
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 | ||
758 | struct 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 | |||
977 | void 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 | |||
1002 | int 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 | |||
1011 | int 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 | |||
1159 | int 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 | |||
758 | static int dvb_frontend_ioctl(struct inode *inode, struct file *file, | 1287 | static 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 | |||
1034 | static unsigned int dvb_frontend_poll(struct file *file, struct poll_table_struct *wait) | 1593 | static 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 | ||
189 | struct 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 | |||
185 | struct dvb_frontend { | 228 | struct 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 | ||
195 | extern int dvb_register_frontend(struct dvb_adapter *dvb, | 239 | extern 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 | ||
166 | typedef enum fe_transmit_mode { | 173 | typedef 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 | */ | ||
253 | typedef 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 | |||
309 | typedef enum fe_pilot { | ||
310 | PILOT_ON, | ||
311 | PILOT_OFF, | ||
312 | PILOT_AUTO, | ||
313 | } fe_pilot_t; | ||
314 | |||
315 | typedef enum fe_rolloff { | ||
316 | ROLLOFF_20, | ||
317 | ROLLOFF_25, | ||
318 | ROLLOFF_35, | ||
319 | ROLLOFF_AUTO, | ||
320 | } fe_rolloff_t; | ||
321 | |||
322 | typedef 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 | |||
340 | struct 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 | |||
351 | typedef 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 */ | ||
363 | typedef 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 |