]>
Commit | Line | Data |
---|---|---|
b2441318 | 1 | // SPDX-License-Identifier: GPL-2.0 |
2add87a9 | 2 | /* |
1589a993 UB |
3 | * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III |
4 | * flexcop-hw-filter.c - pid and mac address filtering and control functions | |
5 | * see flexcop.c for copyright information | |
2add87a9 JS |
6 | */ |
7 | #include "flexcop.h" | |
8 | ||
9 | static void flexcop_rcv_data_ctrl(struct flexcop_device *fc, int onoff) | |
10 | { | |
1589a993 UB |
11 | flexcop_set_ibi_value(ctrl_208, Rcv_Data_sig, onoff); |
12 | deb_ts("rcv_data is now: '%s'\n", onoff ? "on" : "off"); | |
2add87a9 JS |
13 | } |
14 | ||
15 | void flexcop_smc_ctrl(struct flexcop_device *fc, int onoff) | |
16 | { | |
1589a993 | 17 | flexcop_set_ibi_value(ctrl_208, SMC_Enable_sig, onoff); |
2add87a9 JS |
18 | } |
19 | ||
15ac8e66 | 20 | static void flexcop_null_filter_ctrl(struct flexcop_device *fc, int onoff) |
2add87a9 | 21 | { |
1589a993 | 22 | flexcop_set_ibi_value(ctrl_208, Null_filter_sig, onoff); |
2add87a9 JS |
23 | } |
24 | ||
25 | void flexcop_set_mac_filter(struct flexcop_device *fc, u8 mac[6]) | |
26 | { | |
1589a993 UB |
27 | flexcop_ibi_value v418, v41c; |
28 | v41c = fc->read_ibi_reg(fc, mac_address_41c); | |
2add87a9 JS |
29 | |
30 | v418.mac_address_418.MAC1 = mac[0]; | |
31 | v418.mac_address_418.MAC2 = mac[1]; | |
32 | v418.mac_address_418.MAC3 = mac[2]; | |
33 | v418.mac_address_418.MAC6 = mac[3]; | |
34 | v41c.mac_address_41c.MAC7 = mac[4]; | |
35 | v41c.mac_address_41c.MAC8 = mac[5]; | |
36 | ||
1589a993 UB |
37 | fc->write_ibi_reg(fc, mac_address_418, v418); |
38 | fc->write_ibi_reg(fc, mac_address_41c, v41c); | |
2add87a9 JS |
39 | } |
40 | ||
41 | void flexcop_mac_filter_ctrl(struct flexcop_device *fc, int onoff) | |
42 | { | |
1589a993 | 43 | flexcop_set_ibi_value(ctrl_208, MAC_filter_Mode_sig, onoff); |
2add87a9 JS |
44 | } |
45 | ||
1589a993 UB |
46 | static void flexcop_pid_group_filter(struct flexcop_device *fc, |
47 | u16 pid, u16 mask) | |
2add87a9 JS |
48 | { |
49 | /* index_reg_310.extra_index_reg need to 0 or 7 to work */ | |
50 | flexcop_ibi_value v30c; | |
51 | v30c.pid_filter_30c_ext_ind_0_7.Group_PID = pid; | |
52 | v30c.pid_filter_30c_ext_ind_0_7.Group_mask = mask; | |
1589a993 | 53 | fc->write_ibi_reg(fc, pid_filter_30c, v30c); |
2add87a9 JS |
54 | } |
55 | ||
56 | static void flexcop_pid_group_filter_ctrl(struct flexcop_device *fc, int onoff) | |
57 | { | |
1589a993 | 58 | flexcop_set_ibi_value(ctrl_208, Mask_filter_sig, onoff); |
2add87a9 JS |
59 | } |
60 | ||
61 | /* this fancy define reduces the code size of the quite similar PID controlling of | |
62 | * the first 6 PIDs | |
63 | */ | |
64 | ||
65 | #define pid_ctrl(vregname,field,enablefield,trans_field,transval) \ | |
66 | flexcop_ibi_value vpid = fc->read_ibi_reg(fc, vregname), \ | |
1589a993 UB |
67 | v208 = fc->read_ibi_reg(fc, ctrl_208); \ |
68 | vpid.vregname.field = onoff ? pid : 0x1fff; \ | |
69 | vpid.vregname.trans_field = transval; \ | |
70 | v208.ctrl_208.enablefield = onoff; \ | |
71 | fc->write_ibi_reg(fc, vregname, vpid); \ | |
72 | fc->write_ibi_reg(fc, ctrl_208, v208); | |
2add87a9 | 73 | |
1589a993 UB |
74 | static void flexcop_pid_Stream1_PID_ctrl(struct flexcop_device *fc, |
75 | u16 pid, int onoff) | |
2add87a9 | 76 | { |
1589a993 UB |
77 | pid_ctrl(pid_filter_300, Stream1_PID, Stream1_filter_sig, |
78 | Stream1_trans, 0); | |
2add87a9 JS |
79 | } |
80 | ||
1589a993 UB |
81 | static void flexcop_pid_Stream2_PID_ctrl(struct flexcop_device *fc, |
82 | u16 pid, int onoff) | |
2add87a9 | 83 | { |
1589a993 UB |
84 | pid_ctrl(pid_filter_300, Stream2_PID, Stream2_filter_sig, |
85 | Stream2_trans, 0); | |
2add87a9 JS |
86 | } |
87 | ||
1589a993 UB |
88 | static void flexcop_pid_PCR_PID_ctrl(struct flexcop_device *fc, |
89 | u16 pid, int onoff) | |
2add87a9 | 90 | { |
1589a993 | 91 | pid_ctrl(pid_filter_304, PCR_PID, PCR_filter_sig, PCR_trans, 0); |
2add87a9 JS |
92 | } |
93 | ||
1589a993 UB |
94 | static void flexcop_pid_PMT_PID_ctrl(struct flexcop_device *fc, |
95 | u16 pid, int onoff) | |
2add87a9 | 96 | { |
1589a993 | 97 | pid_ctrl(pid_filter_304, PMT_PID, PMT_filter_sig, PMT_trans, 0); |
2add87a9 JS |
98 | } |
99 | ||
1589a993 UB |
100 | static void flexcop_pid_EMM_PID_ctrl(struct flexcop_device *fc, |
101 | u16 pid, int onoff) | |
2add87a9 | 102 | { |
1589a993 | 103 | pid_ctrl(pid_filter_308, EMM_PID, EMM_filter_sig, EMM_trans, 0); |
2add87a9 JS |
104 | } |
105 | ||
1589a993 UB |
106 | static void flexcop_pid_ECM_PID_ctrl(struct flexcop_device *fc, |
107 | u16 pid, int onoff) | |
2add87a9 | 108 | { |
1589a993 | 109 | pid_ctrl(pid_filter_308, ECM_PID, ECM_filter_sig, ECM_trans, 0); |
2add87a9 JS |
110 | } |
111 | ||
1589a993 UB |
112 | static void flexcop_pid_control(struct flexcop_device *fc, |
113 | int index, u16 pid, int onoff) | |
2add87a9 | 114 | { |
c4ee3fd4 JS |
115 | if (pid == 0x2000) |
116 | return; | |
117 | ||
1589a993 UB |
118 | deb_ts("setting pid: %5d %04x at index %d '%s'\n", |
119 | pid, pid, index, onoff ? "on" : "off"); | |
2add87a9 | 120 | |
d3525b63 JD |
121 | /* First 6 can be buggy - skip over them if option set */ |
122 | if (fc->skip_6_hw_pid_filter) | |
123 | index += 6; | |
124 | ||
2add87a9 JS |
125 | /* We could use bit magic here to reduce source code size. |
126 | * I decided against it, but to use the real register names */ | |
127 | switch (index) { | |
1589a993 UB |
128 | case 0: |
129 | flexcop_pid_Stream1_PID_ctrl(fc, pid, onoff); | |
130 | break; | |
131 | case 1: | |
132 | flexcop_pid_Stream2_PID_ctrl(fc, pid, onoff); | |
133 | break; | |
134 | case 2: | |
135 | flexcop_pid_PCR_PID_ctrl(fc, pid, onoff); | |
136 | break; | |
137 | case 3: | |
138 | flexcop_pid_PMT_PID_ctrl(fc, pid, onoff); | |
139 | break; | |
140 | case 4: | |
141 | flexcop_pid_EMM_PID_ctrl(fc, pid, onoff); | |
142 | break; | |
143 | case 5: | |
144 | flexcop_pid_ECM_PID_ctrl(fc, pid, onoff); | |
145 | break; | |
146 | default: | |
147 | if (fc->has_32_hw_pid_filter && index < 38) { | |
148 | flexcop_ibi_value vpid, vid; | |
149 | ||
150 | /* set the index */ | |
151 | vid = fc->read_ibi_reg(fc, index_reg_310); | |
152 | vid.index_reg_310.index_reg = index - 6; | |
153 | fc->write_ibi_reg(fc, index_reg_310, vid); | |
154 | ||
155 | vpid = fc->read_ibi_reg(fc, pid_n_reg_314); | |
156 | vpid.pid_n_reg_314.PID = onoff ? pid : 0x1fff; | |
157 | vpid.pid_n_reg_314.PID_enable_bit = onoff; | |
158 | fc->write_ibi_reg(fc, pid_n_reg_314, vpid); | |
159 | } | |
160 | break; | |
2add87a9 JS |
161 | } |
162 | } | |
163 | ||
1589a993 | 164 | static int flexcop_toggle_fullts_streaming(struct flexcop_device *fc, int onoff) |
c4ee3fd4 JS |
165 | { |
166 | if (fc->fullts_streaming_state != onoff) { | |
167 | deb_ts("%s full TS transfer\n",onoff ? "enabling" : "disabling"); | |
168 | flexcop_pid_group_filter(fc, 0, 0x1fe0 * (!onoff)); | |
1589a993 | 169 | flexcop_pid_group_filter_ctrl(fc, onoff); |
c4ee3fd4 JS |
170 | fc->fullts_streaming_state = onoff; |
171 | } | |
172 | return 0; | |
173 | } | |
174 | ||
1589a993 UB |
175 | int flexcop_pid_feed_control(struct flexcop_device *fc, |
176 | struct dvb_demux_feed *dvbdmxfeed, int onoff) | |
2add87a9 | 177 | { |
d3525b63 JD |
178 | int max_pid_filter = 6; |
179 | ||
180 | max_pid_filter -= 6 * fc->skip_6_hw_pid_filter; | |
181 | max_pid_filter += 32 * fc->has_32_hw_pid_filter; | |
2add87a9 | 182 | |
64221be7 | 183 | fc->feedcount += onoff ? 1 : -1; /* the number of PIDs/Feed currently requested */ |
c4ee3fd4 JS |
184 | if (dvbdmxfeed->index >= max_pid_filter) |
185 | fc->extra_feedcount += onoff ? 1 : -1; | |
2add87a9 | 186 | |
c4ee3fd4 JS |
187 | /* toggle complete-TS-streaming when: |
188 | * - pid_filtering is not enabled and it is the first or last feed requested | |
189 | * - pid_filtering is enabled, | |
190 | * - but the number of requested feeds is exceeded | |
191 | * - or the requested pid is 0x2000 */ | |
2add87a9 | 192 | |
c4ee3fd4 | 193 | if (!fc->pid_filtering && fc->feedcount == onoff) |
1589a993 | 194 | flexcop_toggle_fullts_streaming(fc, onoff); |
2add87a9 | 195 | |
c4ee3fd4 | 196 | if (fc->pid_filtering) { |
1589a993 UB |
197 | flexcop_pid_control \ |
198 | (fc, dvbdmxfeed->index, dvbdmxfeed->pid, onoff); | |
c4ee3fd4 JS |
199 | |
200 | if (fc->extra_feedcount > 0) | |
1589a993 | 201 | flexcop_toggle_fullts_streaming(fc, 1); |
c4ee3fd4 | 202 | else if (dvbdmxfeed->pid == 0x2000) |
1589a993 | 203 | flexcop_toggle_fullts_streaming(fc, onoff); |
c4ee3fd4 | 204 | else |
1589a993 | 205 | flexcop_toggle_fullts_streaming(fc, 0); |
2add87a9 JS |
206 | } |
207 | ||
c4ee3fd4 JS |
208 | /* if it was the first or last feed request change the stream-status */ |
209 | if (fc->feedcount == onoff) { | |
1589a993 | 210 | flexcop_rcv_data_ctrl(fc, onoff); |
64221be7 | 211 | if (fc->stream_control) /* device specific stream control */ |
1589a993 | 212 | fc->stream_control(fc, onoff); |
64221be7 PB |
213 | |
214 | /* feeding stopped -> reset the flexcop filter*/ | |
215 | if (onoff == 0) { | |
216 | flexcop_reset_block_300(fc); | |
217 | flexcop_hw_filter_init(fc); | |
218 | } | |
2add87a9 | 219 | } |
2add87a9 JS |
220 | return 0; |
221 | } | |
382c5546 | 222 | EXPORT_SYMBOL(flexcop_pid_feed_control); |
2add87a9 JS |
223 | |
224 | void flexcop_hw_filter_init(struct flexcop_device *fc) | |
225 | { | |
226 | int i; | |
227 | flexcop_ibi_value v; | |
d3525b63 JD |
228 | int max_pid_filter = 6; |
229 | ||
230 | max_pid_filter -= 6 * fc->skip_6_hw_pid_filter; | |
231 | max_pid_filter += 32 * fc->has_32_hw_pid_filter; | |
232 | ||
233 | for (i = 0; i < max_pid_filter; i++) | |
1589a993 | 234 | flexcop_pid_control(fc, i, 0x1fff, 0); |
2add87a9 | 235 | |
7635acd2 | 236 | flexcop_pid_group_filter(fc, 0, 0x1fe0); |
1589a993 | 237 | flexcop_pid_group_filter_ctrl(fc, 0); |
2add87a9 | 238 | |
1589a993 | 239 | v = fc->read_ibi_reg(fc, pid_filter_308); |
2add87a9 JS |
240 | v.pid_filter_308.EMM_filter_4 = 1; |
241 | v.pid_filter_308.EMM_filter_6 = 0; | |
1589a993 | 242 | fc->write_ibi_reg(fc, pid_filter_308, v); |
7635acd2 JS |
243 | |
244 | flexcop_null_filter_ctrl(fc, 1); | |
2add87a9 | 245 | } |