Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
0004  * flexcop-hw-filter.c - pid and mac address filtering and control functions
0005  * see flexcop.c for copyright information
0006  */
0007 #include "flexcop.h"
0008 
0009 static void flexcop_rcv_data_ctrl(struct flexcop_device *fc, int onoff)
0010 {
0011     flexcop_set_ibi_value(ctrl_208, Rcv_Data_sig, onoff);
0012     deb_ts("rcv_data is now: '%s'\n", onoff ? "on" : "off");
0013 }
0014 
0015 void flexcop_smc_ctrl(struct flexcop_device *fc, int onoff)
0016 {
0017     flexcop_set_ibi_value(ctrl_208, SMC_Enable_sig, onoff);
0018 }
0019 
0020 static void flexcop_null_filter_ctrl(struct flexcop_device *fc, int onoff)
0021 {
0022     flexcop_set_ibi_value(ctrl_208, Null_filter_sig, onoff);
0023 }
0024 
0025 void flexcop_set_mac_filter(struct flexcop_device *fc, u8 mac[6])
0026 {
0027     flexcop_ibi_value v418, v41c;
0028     v41c = fc->read_ibi_reg(fc, mac_address_41c);
0029 
0030     v418.mac_address_418.MAC1 = mac[0];
0031     v418.mac_address_418.MAC2 = mac[1];
0032     v418.mac_address_418.MAC3 = mac[2];
0033     v418.mac_address_418.MAC6 = mac[3];
0034     v41c.mac_address_41c.MAC7 = mac[4];
0035     v41c.mac_address_41c.MAC8 = mac[5];
0036 
0037     fc->write_ibi_reg(fc, mac_address_418, v418);
0038     fc->write_ibi_reg(fc, mac_address_41c, v41c);
0039 }
0040 
0041 void flexcop_mac_filter_ctrl(struct flexcop_device *fc, int onoff)
0042 {
0043     flexcop_set_ibi_value(ctrl_208, MAC_filter_Mode_sig, onoff);
0044 }
0045 
0046 static void flexcop_pid_group_filter(struct flexcop_device *fc,
0047         u16 pid, u16 mask)
0048 {
0049     /* index_reg_310.extra_index_reg need to 0 or 7 to work */
0050     flexcop_ibi_value v30c;
0051     v30c.pid_filter_30c_ext_ind_0_7.Group_PID = pid;
0052     v30c.pid_filter_30c_ext_ind_0_7.Group_mask = mask;
0053     fc->write_ibi_reg(fc, pid_filter_30c, v30c);
0054 }
0055 
0056 static void flexcop_pid_group_filter_ctrl(struct flexcop_device *fc, int onoff)
0057 {
0058     flexcop_set_ibi_value(ctrl_208, Mask_filter_sig, onoff);
0059 }
0060 
0061 /* this fancy define reduces the code size of the quite similar PID controlling of
0062  * the first 6 PIDs
0063  */
0064 
0065 #define pid_ctrl(vregname,field,enablefield,trans_field,transval) \
0066     flexcop_ibi_value vpid = fc->read_ibi_reg(fc, vregname), \
0067 v208 = fc->read_ibi_reg(fc, ctrl_208); \
0068 vpid.vregname.field = onoff ? pid : 0x1fff; \
0069 vpid.vregname.trans_field = transval; \
0070 v208.ctrl_208.enablefield = onoff; \
0071 fc->write_ibi_reg(fc, vregname, vpid); \
0072 fc->write_ibi_reg(fc, ctrl_208, v208)
0073 
0074 static void flexcop_pid_Stream1_PID_ctrl(struct flexcop_device *fc,
0075         u16 pid, int onoff)
0076 {
0077     pid_ctrl(pid_filter_300, Stream1_PID, Stream1_filter_sig,
0078             Stream1_trans, 0);
0079 }
0080 
0081 static void flexcop_pid_Stream2_PID_ctrl(struct flexcop_device *fc,
0082         u16 pid, int onoff)
0083 {
0084     pid_ctrl(pid_filter_300, Stream2_PID, Stream2_filter_sig,
0085             Stream2_trans, 0);
0086 }
0087 
0088 static void flexcop_pid_PCR_PID_ctrl(struct flexcop_device *fc,
0089         u16 pid, int onoff)
0090 {
0091     pid_ctrl(pid_filter_304, PCR_PID, PCR_filter_sig, PCR_trans, 0);
0092 }
0093 
0094 static void flexcop_pid_PMT_PID_ctrl(struct flexcop_device *fc,
0095         u16 pid, int onoff)
0096 {
0097     pid_ctrl(pid_filter_304, PMT_PID, PMT_filter_sig, PMT_trans, 0);
0098 }
0099 
0100 static void flexcop_pid_EMM_PID_ctrl(struct flexcop_device *fc,
0101         u16 pid, int onoff)
0102 {
0103     pid_ctrl(pid_filter_308, EMM_PID, EMM_filter_sig, EMM_trans, 0);
0104 }
0105 
0106 static void flexcop_pid_ECM_PID_ctrl(struct flexcop_device *fc,
0107         u16 pid, int onoff)
0108 {
0109     pid_ctrl(pid_filter_308, ECM_PID, ECM_filter_sig, ECM_trans, 0);
0110 }
0111 
0112 static void flexcop_pid_control(struct flexcop_device *fc,
0113         int index, u16 pid, int onoff)
0114 {
0115     if (pid == 0x2000)
0116         return;
0117 
0118     deb_ts("setting pid: %5d %04x at index %d '%s'\n",
0119             pid, pid, index, onoff ? "on" : "off");
0120 
0121     /* First 6 can be buggy - skip over them if option set */
0122     if (fc->skip_6_hw_pid_filter)
0123         index += 6;
0124 
0125     /* We could use bit magic here to reduce source code size.
0126      * I decided against it, but to use the real register names */
0127     switch (index) {
0128     case 0:
0129         flexcop_pid_Stream1_PID_ctrl(fc, pid, onoff);
0130         break;
0131     case 1:
0132         flexcop_pid_Stream2_PID_ctrl(fc, pid, onoff);
0133         break;
0134     case 2:
0135         flexcop_pid_PCR_PID_ctrl(fc, pid, onoff);
0136         break;
0137     case 3:
0138         flexcop_pid_PMT_PID_ctrl(fc, pid, onoff);
0139         break;
0140     case 4:
0141         flexcop_pid_EMM_PID_ctrl(fc, pid, onoff);
0142         break;
0143     case 5:
0144         flexcop_pid_ECM_PID_ctrl(fc, pid, onoff);
0145         break;
0146     default:
0147         if (fc->has_32_hw_pid_filter && index < 38) {
0148             flexcop_ibi_value vpid, vid;
0149 
0150             /* set the index */
0151             vid = fc->read_ibi_reg(fc, index_reg_310);
0152             vid.index_reg_310.index_reg = index - 6;
0153             fc->write_ibi_reg(fc, index_reg_310, vid);
0154 
0155             vpid = fc->read_ibi_reg(fc, pid_n_reg_314);
0156             vpid.pid_n_reg_314.PID = onoff ? pid : 0x1fff;
0157             vpid.pid_n_reg_314.PID_enable_bit = onoff;
0158             fc->write_ibi_reg(fc, pid_n_reg_314, vpid);
0159         }
0160         break;
0161     }
0162 }
0163 
0164 static int flexcop_toggle_fullts_streaming(struct flexcop_device *fc, int onoff)
0165 {
0166     if (fc->fullts_streaming_state != onoff) {
0167         deb_ts("%s full TS transfer\n",onoff ? "enabling" : "disabling");
0168         flexcop_pid_group_filter(fc, 0, 0x1fe0 * (!onoff));
0169         flexcop_pid_group_filter_ctrl(fc, onoff);
0170         fc->fullts_streaming_state = onoff;
0171     }
0172     return 0;
0173 }
0174 
0175 int flexcop_pid_feed_control(struct flexcop_device *fc,
0176         struct dvb_demux_feed *dvbdmxfeed, int onoff)
0177 {
0178     int max_pid_filter = 6;
0179 
0180     max_pid_filter -= 6 * fc->skip_6_hw_pid_filter;
0181     max_pid_filter += 32 * fc->has_32_hw_pid_filter;
0182 
0183     fc->feedcount += onoff ? 1 : -1; /* the number of PIDs/Feed currently requested */
0184     if (dvbdmxfeed->index >= max_pid_filter)
0185         fc->extra_feedcount += onoff ? 1 : -1;
0186 
0187     /* toggle complete-TS-streaming when:
0188      * - pid_filtering is not enabled and it is the first or last feed requested
0189      * - pid_filtering is enabled,
0190      *   - but the number of requested feeds is exceeded
0191      *   - or the requested pid is 0x2000 */
0192 
0193     if (!fc->pid_filtering && fc->feedcount == onoff)
0194         flexcop_toggle_fullts_streaming(fc, onoff);
0195 
0196     if (fc->pid_filtering) {
0197         flexcop_pid_control \
0198             (fc, dvbdmxfeed->index, dvbdmxfeed->pid, onoff);
0199 
0200         if (fc->extra_feedcount > 0)
0201             flexcop_toggle_fullts_streaming(fc, 1);
0202         else if (dvbdmxfeed->pid == 0x2000)
0203             flexcop_toggle_fullts_streaming(fc, onoff);
0204         else
0205             flexcop_toggle_fullts_streaming(fc, 0);
0206     }
0207 
0208     /* if it was the first or last feed request change the stream-status */
0209     if (fc->feedcount == onoff) {
0210         flexcop_rcv_data_ctrl(fc, onoff);
0211         if (fc->stream_control) /* device specific stream control */
0212             fc->stream_control(fc, onoff);
0213 
0214         /* feeding stopped -> reset the flexcop filter*/
0215         if (onoff == 0) {
0216             flexcop_reset_block_300(fc);
0217             flexcop_hw_filter_init(fc);
0218         }
0219     }
0220     return 0;
0221 }
0222 EXPORT_SYMBOL(flexcop_pid_feed_control);
0223 
0224 void flexcop_hw_filter_init(struct flexcop_device *fc)
0225 {
0226     int i;
0227     flexcop_ibi_value v;
0228     int max_pid_filter = 6;
0229 
0230     max_pid_filter -= 6 * fc->skip_6_hw_pid_filter;
0231     max_pid_filter += 32 * fc->has_32_hw_pid_filter;
0232 
0233     for (i = 0; i < max_pid_filter; i++)
0234         flexcop_pid_control(fc, i, 0x1fff, 0);
0235 
0236     flexcop_pid_group_filter(fc, 0, 0x1fe0);
0237     flexcop_pid_group_filter_ctrl(fc, 0);
0238 
0239     v = fc->read_ibi_reg(fc, pid_filter_308);
0240     v.pid_filter_308.EMM_filter_4 = 1;
0241     v.pid_filter_308.EMM_filter_6 = 0;
0242     fc->write_ibi_reg(fc, pid_filter_308, v);
0243 
0244     flexcop_null_filter_ctrl(fc, 1);
0245 }