/src/mpv/stream/dvb_tune.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* dvbtune - tune.c |
2 | | |
3 | | Copyright (C) Dave Chapman 2001,2002 |
4 | | Copyright (C) Rozhuk Ivan <rozhuk.im@gmail.com> 2016 - 2017 |
5 | | |
6 | | Modified for use with MPlayer, for details see the changelog at |
7 | | http://svn.mplayerhq.hu/mplayer/trunk/ |
8 | | $Id$ |
9 | | |
10 | | This file is part of mpv. |
11 | | |
12 | | mpv is free software; you can redistribute it and/or modify |
13 | | it under the terms of the GNU General Public License as published by |
14 | | the Free Software Foundation; either version 2 of the License, or |
15 | | (at your option) any later version. |
16 | | |
17 | | mpv is distributed in the hope that it will be useful, |
18 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
19 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
20 | | GNU General Public License for more details. |
21 | | |
22 | | You should have received a copy of the GNU General Public License along |
23 | | with mpv. If not, see <http://www.gnu.org/licenses/>. |
24 | | |
25 | | */ |
26 | | |
27 | | #include <stdio.h> |
28 | | #include <stdlib.h> |
29 | | #include <sys/ioctl.h> |
30 | | #include <poll.h> |
31 | | #include <fcntl.h> |
32 | | #include <errno.h> |
33 | | #include <linux/dvb/dmx.h> |
34 | | #include <linux/dvb/frontend.h> |
35 | | |
36 | | #include "common/common.h" |
37 | | #include "osdep/io.h" |
38 | | #include "osdep/poll_wrapper.h" |
39 | | #include "osdep/timer.h" |
40 | | #include "dvbin.h" |
41 | | #include "dvb_tune.h" |
42 | | #include "common/msg.h" |
43 | | |
44 | | /* Keep in sync with enum fe_delivery_system. */ |
45 | | static const char *dvb_delsys_str[] = { |
46 | | "UNDEFINED", |
47 | | "DVB-C ANNEX A", |
48 | | "DVB-C ANNEX B", |
49 | | "DVB-T", |
50 | | "DSS", |
51 | | "DVB-S", |
52 | | "DVB-S2", |
53 | | "DVB-H", |
54 | | "ISDBT", |
55 | | "ISDBS", |
56 | | "ISDBC", |
57 | | "ATSC", |
58 | | "ATSCMH", |
59 | | "DTMB", |
60 | | "CMMB", |
61 | | "DAB", |
62 | | "DVB-T2", |
63 | | "TURBO", |
64 | | "DVB-C ANNEX C", |
65 | | NULL |
66 | | }; |
67 | | |
68 | | const char *get_dvb_delsys(unsigned int delsys) |
69 | 0 | { |
70 | 0 | if (SYS_DVB__COUNT__ <= delsys) |
71 | 0 | return dvb_delsys_str[0]; |
72 | 0 | return dvb_delsys_str[delsys]; |
73 | 0 | } |
74 | | |
75 | | unsigned int dvb_get_tuner_delsys_mask(int fe_fd, struct mp_log *log) |
76 | 0 | { |
77 | 0 | unsigned int ret_mask = 0, delsys; |
78 | 0 | struct dtv_property prop[1]; |
79 | 0 | struct dtv_properties cmdseq = {.num = 1, .props = prop}; |
80 | |
|
81 | 0 | prop[0].cmd = DTV_ENUM_DELSYS; |
82 | 0 | if (ioctl(fe_fd, FE_GET_PROPERTY, &cmdseq) < 0) { |
83 | 0 | mp_err(log, "DVBv5: FE_GET_PROPERTY(DTV_ENUM_DELSYS) error: %d\n", errno); |
84 | 0 | return ret_mask; |
85 | 0 | } |
86 | 0 | unsigned int delsys_count = prop[0].u.buffer.len; |
87 | 0 | if (delsys_count == 0) { |
88 | 0 | mp_err(log, "DVBv5: Frontend returned no delivery systems!\n"); |
89 | 0 | return ret_mask; |
90 | 0 | } |
91 | 0 | mp_verbose(log, "DVBv5: Number of supported delivery systems: %d\n", delsys_count); |
92 | 0 | for (unsigned int i = 0; i < delsys_count; i++) { |
93 | 0 | delsys = (unsigned int)prop[0].u.buffer.data[i]; |
94 | 0 | DELSYS_SET(ret_mask, delsys); |
95 | 0 | mp_verbose(log, " %s\n", get_dvb_delsys(delsys)); |
96 | 0 | } |
97 | |
|
98 | 0 | return ret_mask; |
99 | 0 | } |
100 | | |
101 | | int dvb_open_devices(dvb_priv_t *priv, unsigned int adapter, |
102 | | unsigned int frontend, unsigned int demux_cnt) |
103 | 0 | { |
104 | 0 | dvb_state_t *state = priv->state; |
105 | |
|
106 | 0 | char frontend_dev[100], dvr_dev[100], demux_dev[100]; |
107 | 0 | snprintf(frontend_dev, sizeof(frontend_dev), "/dev/dvb/adapter%u/frontend%u", adapter, frontend); |
108 | 0 | snprintf(dvr_dev, sizeof(dvr_dev), "/dev/dvb/adapter%u/dvr0", adapter); |
109 | 0 | snprintf(demux_dev, sizeof(demux_dev), "/dev/dvb/adapter%u/demux0", adapter); |
110 | |
|
111 | 0 | MP_VERBOSE(priv, "Opening frontend device %s\n", frontend_dev); |
112 | 0 | state->fe_fd = open(frontend_dev, O_RDWR | O_NONBLOCK | O_CLOEXEC); |
113 | 0 | if (state->fe_fd < 0) { |
114 | 0 | MP_ERR(priv, "Error opening frontend device: %d\n", errno); |
115 | 0 | return 0; |
116 | 0 | } |
117 | | |
118 | 0 | state->demux_fds_cnt = 0; |
119 | 0 | MP_VERBOSE(priv, "Opening %d demuxers\n", demux_cnt); |
120 | 0 | for (unsigned int i = 0; i < demux_cnt; i++) { |
121 | 0 | state->demux_fds[i] = open(demux_dev, O_RDWR | O_NONBLOCK | O_CLOEXEC); |
122 | 0 | if (state->demux_fds[i] < 0) { |
123 | 0 | MP_ERR(priv, "Error opening demux0: %d\n", errno); |
124 | 0 | return 0; |
125 | 0 | } |
126 | 0 | state->demux_fds_cnt++; |
127 | 0 | } |
128 | | |
129 | 0 | state->dvr_fd = open(dvr_dev, O_RDONLY | O_NONBLOCK | O_CLOEXEC); |
130 | 0 | if (state->dvr_fd < 0) { |
131 | 0 | MP_ERR(priv, "Error opening dvr device %s: %d\n", dvr_dev, errno); |
132 | 0 | return 0; |
133 | 0 | } |
134 | | |
135 | 0 | return 1; |
136 | 0 | } |
137 | | |
138 | | int dvb_fix_demuxes(dvb_priv_t *priv, unsigned int cnt) |
139 | 0 | { |
140 | 0 | dvb_state_t *state = priv->state; |
141 | |
|
142 | 0 | char demux_dev[100]; |
143 | 0 | snprintf(demux_dev, sizeof(demux_dev), "/dev/dvb/adapter%d/demux0", |
144 | 0 | state->adapters[state->cur_adapter].devno); |
145 | |
|
146 | 0 | MP_VERBOSE(priv, "Changing demuxer count %d -> %d\n", state->demux_fds_cnt, cnt); |
147 | 0 | if (state->demux_fds_cnt >= cnt) { |
148 | 0 | for (int i = state->demux_fds_cnt - 1; i >= (int)cnt; i--) { |
149 | 0 | close(state->demux_fds[i]); |
150 | 0 | } |
151 | 0 | state->demux_fds_cnt = cnt; |
152 | 0 | } else { |
153 | 0 | for (int i = state->demux_fds_cnt; i < cnt; i++) { |
154 | 0 | state->demux_fds[i] = open(demux_dev, |
155 | 0 | O_RDWR | O_NONBLOCK | O_CLOEXEC); |
156 | 0 | if (state->demux_fds[i] < 0) { |
157 | 0 | MP_ERR(priv, "Error opening demux0: %d\n", errno); |
158 | 0 | return 0; |
159 | 0 | } |
160 | 0 | state->demux_fds_cnt++; |
161 | 0 | } |
162 | 0 | } |
163 | | |
164 | 0 | return 1; |
165 | 0 | } |
166 | | |
167 | | int dvb_set_ts_filt(dvb_priv_t *priv, int fd, uint16_t pid, |
168 | | dmx_pes_type_t pestype) |
169 | 0 | { |
170 | 0 | int i; |
171 | 0 | struct dmx_pes_filter_params pesFilterParams; |
172 | |
|
173 | 0 | pesFilterParams.pid = pid; |
174 | 0 | pesFilterParams.input = DMX_IN_FRONTEND; |
175 | 0 | pesFilterParams.output = DMX_OUT_TS_TAP; |
176 | 0 | pesFilterParams.pes_type = pestype; |
177 | 0 | pesFilterParams.flags = DMX_IMMEDIATE_START; |
178 | |
|
179 | 0 | { |
180 | 0 | int buffersize = 256 * 1024; |
181 | 0 | if (ioctl(fd, DMX_SET_BUFFER_SIZE, buffersize) < 0) |
182 | 0 | MP_ERR(priv, "Error in DMX_SET_BUFFER_SIZE %i: errno=%d\n", |
183 | 0 | pid, errno); |
184 | 0 | } |
185 | |
|
186 | 0 | errno = 0; |
187 | 0 | if ((i = ioctl(fd, DMX_SET_PES_FILTER, &pesFilterParams)) < 0) { |
188 | 0 | MP_ERR(priv, "Error in DMX_SET_PES_FILTER %i: errno=%d\n", |
189 | 0 | pid, errno); |
190 | 0 | return 0; |
191 | 0 | } |
192 | | |
193 | 0 | return 1; |
194 | 0 | } |
195 | | |
196 | | int dvb_get_pmt_pid(dvb_priv_t *priv, int devno, int service_id) |
197 | 0 | { |
198 | | /* We need special filters on the demux, |
199 | | so open one locally, and close also here. */ |
200 | 0 | char demux_dev[100]; |
201 | 0 | snprintf(demux_dev, sizeof(demux_dev), "/dev/dvb/adapter%d/demux0", devno); |
202 | |
|
203 | 0 | struct dmx_sct_filter_params fparams = {0}; |
204 | 0 | fparams.pid = 0; |
205 | 0 | fparams.filter.filter[0] = 0x00; |
206 | 0 | fparams.filter.mask[0] = 0xff; |
207 | 0 | fparams.timeout = 0; |
208 | 0 | fparams.flags = DMX_IMMEDIATE_START | DMX_CHECK_CRC; |
209 | |
|
210 | 0 | int pat_fd; |
211 | 0 | if ((pat_fd = open(demux_dev, O_RDWR)) < 0) { |
212 | 0 | MP_ERR(priv, "Opening PAT demux failed: %d", errno); |
213 | 0 | return -1; |
214 | 0 | } |
215 | | |
216 | 0 | if (ioctl(pat_fd, DMX_SET_FILTER, &fparams) < 0) { |
217 | 0 | MP_ERR(priv, "ioctl DMX_SET_FILTER failed: %d", errno); |
218 | 0 | close(pat_fd); |
219 | 0 | return -1; |
220 | 0 | } |
221 | | |
222 | 0 | int bytes_read; |
223 | 0 | unsigned char buft[4096]; |
224 | 0 | unsigned char *bufptr = buft; |
225 | |
|
226 | 0 | int pmt_pid = -1; |
227 | |
|
228 | 0 | bool pat_read = false; |
229 | 0 | while (!pat_read) { |
230 | 0 | bytes_read = read(pat_fd, bufptr, sizeof(buft)); |
231 | 0 | if (bytes_read < 0 && errno == EOVERFLOW) |
232 | 0 | bytes_read = read(pat_fd, bufptr, sizeof(buft)); |
233 | 0 | if (bytes_read < 0) { |
234 | 0 | MP_ERR(priv, "PAT: read error: %d", errno); |
235 | 0 | close(pat_fd); |
236 | 0 | return -1; |
237 | 0 | } |
238 | | |
239 | 0 | int section_length = ((bufptr[1] & 0x0f) << 8) | bufptr[2]; |
240 | 0 | if (bytes_read != section_length + 3) |
241 | 0 | continue; |
242 | | |
243 | 0 | bufptr += 8; |
244 | 0 | section_length -= 8; |
245 | | |
246 | | /* assumes one section contains the whole pat */ |
247 | 0 | pat_read = true; |
248 | 0 | while (section_length > 0) { |
249 | 0 | int this_service_id = (bufptr[0] << 8) | bufptr[1]; |
250 | 0 | if (this_service_id == service_id) { |
251 | 0 | pmt_pid = ((bufptr[2] & 0x1f) << 8) | bufptr[3]; |
252 | 0 | section_length = 0; |
253 | 0 | } |
254 | 0 | bufptr += 4; |
255 | 0 | section_length -= 4; |
256 | 0 | } |
257 | 0 | } |
258 | 0 | close(pat_fd); |
259 | |
|
260 | 0 | return pmt_pid; |
261 | 0 | } |
262 | | |
263 | | static void print_status(dvb_priv_t *priv, fe_status_t festatus) |
264 | 0 | { |
265 | 0 | MP_VERBOSE(priv, "FE_STATUS:"); |
266 | 0 | if (festatus & FE_HAS_SIGNAL) |
267 | 0 | MP_VERBOSE(priv, " FE_HAS_SIGNAL"); |
268 | 0 | if (festatus & FE_TIMEDOUT) |
269 | 0 | MP_VERBOSE(priv, " FE_TIMEDOUT"); |
270 | 0 | if (festatus & FE_HAS_LOCK) |
271 | 0 | MP_VERBOSE(priv, " FE_HAS_LOCK"); |
272 | 0 | if (festatus & FE_HAS_CARRIER) |
273 | 0 | MP_VERBOSE(priv, " FE_HAS_CARRIER"); |
274 | 0 | if (festatus & FE_HAS_VITERBI) |
275 | 0 | MP_VERBOSE(priv, " FE_HAS_VITERBI"); |
276 | 0 | if (festatus & FE_HAS_SYNC) |
277 | 0 | MP_VERBOSE(priv, " FE_HAS_SYNC"); |
278 | 0 | MP_VERBOSE(priv, "\n"); |
279 | 0 | } |
280 | | |
281 | | static int check_status(dvb_priv_t *priv, int fd_frontend, float tmout) |
282 | 0 | { |
283 | 0 | fe_status_t festatus; |
284 | 0 | bool ok = false; |
285 | 0 | int locks = 0; |
286 | |
|
287 | 0 | struct pollfd pfd[1]; |
288 | 0 | pfd[0].fd = fd_frontend; |
289 | 0 | pfd[0].events = POLLPRI; |
290 | |
|
291 | 0 | MP_VERBOSE(priv, "Getting frontend status\n"); |
292 | 0 | int tm1 = (int)mp_time_sec(); |
293 | 0 | while (!ok) { |
294 | 0 | festatus = 0; |
295 | 0 | if (mp_poll(pfd, 1, MP_TIME_S_TO_NS(tmout)) > 0) { |
296 | 0 | if (pfd[0].revents & POLLPRI) { |
297 | 0 | if (ioctl(fd_frontend, FE_READ_STATUS, &festatus) >= 0) { |
298 | 0 | if (festatus & FE_HAS_LOCK) |
299 | 0 | locks++; |
300 | 0 | } |
301 | 0 | } |
302 | 0 | } |
303 | 0 | usleep(10000); |
304 | 0 | int tm2 = (int)mp_time_sec(); |
305 | 0 | if ((festatus & FE_TIMEDOUT) || (locks >= 2) || (tm2 - tm1 >= tmout)) |
306 | 0 | ok = true; |
307 | 0 | } |
308 | |
|
309 | 0 | if (!(festatus & FE_HAS_LOCK)) { |
310 | 0 | MP_ERR(priv, "Not able to lock to the signal on the given frequency, " |
311 | 0 | "timeout: %g\n", tmout); |
312 | 0 | return -1; |
313 | 0 | } |
314 | | |
315 | 0 | int32_t strength = 0; |
316 | 0 | if (ioctl(fd_frontend, FE_READ_BER, &strength) >= 0) |
317 | 0 | MP_VERBOSE(priv, "Bit error rate: %d\n", strength); |
318 | |
|
319 | 0 | strength = 0; |
320 | 0 | if (ioctl(fd_frontend, FE_READ_SIGNAL_STRENGTH, &strength) >= 0) |
321 | 0 | MP_VERBOSE(priv, "Signal strength: %d\n", strength); |
322 | |
|
323 | 0 | strength = 0; |
324 | 0 | if (ioctl(fd_frontend, FE_READ_SNR, &strength) >= 0) |
325 | 0 | MP_VERBOSE(priv, "SNR: %d\n", strength); |
326 | |
|
327 | 0 | strength = 0; |
328 | 0 | if (ioctl(fd_frontend, FE_READ_UNCORRECTED_BLOCKS, &strength) >= 0) |
329 | 0 | MP_VERBOSE(priv, "UNC: %d\n", strength); |
330 | |
|
331 | 0 | print_status(priv, festatus); |
332 | |
|
333 | 0 | return 0; |
334 | 0 | } |
335 | | |
336 | | struct diseqc_cmd { |
337 | | struct dvb_diseqc_master_cmd cmd; |
338 | | uint32_t wait; |
339 | | }; |
340 | | |
341 | | static int diseqc_send_msg(int fd, fe_sec_voltage_t v, struct diseqc_cmd *cmd, |
342 | | fe_sec_tone_mode_t t, fe_sec_mini_cmd_t b) |
343 | 0 | { |
344 | 0 | if (ioctl(fd, FE_SET_TONE, SEC_TONE_OFF) < 0) |
345 | 0 | return -1; |
346 | 0 | if (ioctl(fd, FE_SET_VOLTAGE, v) < 0) |
347 | 0 | return -1; |
348 | 0 | usleep(15 * 1000); |
349 | 0 | if (ioctl(fd, FE_DISEQC_SEND_MASTER_CMD, &cmd->cmd) < 0) |
350 | 0 | return -1; |
351 | 0 | usleep(cmd->wait * 1000); |
352 | 0 | usleep(15 * 1000); |
353 | 0 | if (ioctl(fd, FE_DISEQC_SEND_BURST, b) < 0) |
354 | 0 | return -1; |
355 | 0 | usleep(15 * 1000); |
356 | 0 | if (ioctl(fd, FE_SET_TONE, t) < 0) |
357 | 0 | return -1; |
358 | 0 | usleep(100000); |
359 | |
|
360 | 0 | return 0; |
361 | 0 | } |
362 | | |
363 | | /* digital satellite equipment control, |
364 | | * specification is available from http://www.eutelsat.com/ |
365 | | */ |
366 | | static int do_diseqc(int secfd, int sat_no, int polv, int hi_lo) |
367 | 0 | { |
368 | 0 | struct diseqc_cmd cmd = { {{0xe0, 0x10, 0x38, 0xf0, 0x00, 0x00}, 4}, 0 }; |
369 | | |
370 | | /* param: high nibble: reset bits, low nibble set bits, |
371 | | * bits are: option, position, polarizaion, band |
372 | | */ |
373 | 0 | cmd.cmd.msg[3] = 0xf0 | (((sat_no * 4) & 0x0f) | (hi_lo ? 1 : 0) | (polv ? 0 : 2)); |
374 | |
|
375 | 0 | return diseqc_send_msg(secfd, polv ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18, |
376 | 0 | &cmd, hi_lo ? SEC_TONE_ON : SEC_TONE_OFF, |
377 | 0 | ((sat_no / 4) % 2) ? SEC_MINI_B : SEC_MINI_A); |
378 | 0 | } |
379 | | |
380 | | static int dvbv5_tune(dvb_priv_t *priv, int fd_frontend, |
381 | | unsigned int delsys, struct dtv_properties* cmdseq) |
382 | 0 | { |
383 | 0 | MP_VERBOSE(priv, "Dumping raw tuning commands and values:\n"); |
384 | 0 | for (int i = 0; i < cmdseq->num; ++i) { |
385 | 0 | MP_VERBOSE(priv, " %02d: 0x%x(%d) => 0x%x(%d)\n", |
386 | 0 | i, cmdseq->props[i].cmd, cmdseq->props[i].cmd, |
387 | 0 | cmdseq->props[i].u.data, cmdseq->props[i].u.data); |
388 | 0 | } |
389 | 0 | if (ioctl(fd_frontend, FE_SET_PROPERTY, cmdseq) < 0) { |
390 | 0 | MP_ERR(priv, "Error tuning channel\n"); |
391 | 0 | return -1; |
392 | 0 | } |
393 | 0 | return 0; |
394 | 0 | } |
395 | | |
396 | | static int tune_it(dvb_priv_t *priv, int fd_frontend, unsigned int delsys, |
397 | | unsigned int freq, unsigned int srate, char pol, |
398 | | int stream_id, |
399 | | fe_spectral_inversion_t specInv, unsigned int diseqc, |
400 | | fe_modulation_t modulation, |
401 | | fe_code_rate_t HP_CodeRate, |
402 | | fe_transmit_mode_t TransmissionMode, |
403 | | fe_guard_interval_t guardInterval, |
404 | | fe_bandwidth_t bandwidth, |
405 | | fe_code_rate_t LP_CodeRate, fe_hierarchy_t hier, |
406 | | float timeout) |
407 | 0 | { |
408 | 0 | dvb_state_t *state = priv->state; |
409 | |
|
410 | 0 | MP_VERBOSE(priv, "tune_it: fd_frontend %d, %s freq %lu, srate %lu, " |
411 | 0 | "pol %c, diseqc %u\n", fd_frontend, |
412 | 0 | get_dvb_delsys(delsys), |
413 | 0 | (long unsigned int)freq, (long unsigned int)srate, |
414 | 0 | (pol > ' ' ? pol : '-'), diseqc); |
415 | |
|
416 | 0 | MP_VERBOSE(priv, "Using %s adapter %d\n", |
417 | 0 | get_dvb_delsys(delsys), |
418 | 0 | state->adapters[state->cur_adapter].devno); |
419 | |
|
420 | 0 | { |
421 | | /* discard stale QPSK events */ |
422 | 0 | struct dvb_frontend_event ev; |
423 | 0 | while (true) { |
424 | 0 | if (ioctl(fd_frontend, FE_GET_EVENT, &ev) < 0) |
425 | 0 | break; |
426 | 0 | } |
427 | 0 | } |
428 | | |
429 | | /* Prepare params, be verbose. */ |
430 | 0 | int hi_lo = 0, bandwidth_hz = 0; |
431 | 0 | switch (delsys) { |
432 | 0 | case SYS_DVBT2: |
433 | 0 | case SYS_DVBT: |
434 | 0 | case SYS_ISDBT: |
435 | 0 | if (freq < 1000000) |
436 | 0 | freq *= 1000UL; |
437 | 0 | switch (bandwidth) { |
438 | 0 | case BANDWIDTH_5_MHZ: |
439 | 0 | bandwidth_hz = 5000000; |
440 | 0 | break; |
441 | 0 | case BANDWIDTH_6_MHZ: |
442 | 0 | bandwidth_hz = 6000000; |
443 | 0 | break; |
444 | 0 | case BANDWIDTH_7_MHZ: |
445 | 0 | bandwidth_hz = 7000000; |
446 | 0 | break; |
447 | 0 | case BANDWIDTH_8_MHZ: |
448 | 0 | bandwidth_hz = 8000000; |
449 | 0 | break; |
450 | 0 | case BANDWIDTH_10_MHZ: |
451 | 0 | bandwidth_hz = 10000000; |
452 | 0 | break; |
453 | 0 | case BANDWIDTH_AUTO: |
454 | 0 | if (freq < 474000000) { |
455 | 0 | bandwidth_hz = 7000000; |
456 | 0 | } else { |
457 | 0 | bandwidth_hz = 8000000; |
458 | 0 | } |
459 | 0 | break; |
460 | 0 | default: |
461 | 0 | bandwidth_hz = 0; |
462 | 0 | break; |
463 | 0 | } |
464 | | |
465 | 0 | MP_VERBOSE(priv, "tuning %s to %d Hz, bandwidth: %d\n", |
466 | 0 | get_dvb_delsys(delsys), freq, bandwidth_hz); |
467 | 0 | break; |
468 | 0 | case SYS_DVBS2: |
469 | 0 | case SYS_DVBS: |
470 | 0 | if (freq > 2200000) { |
471 | | // this must be an absolute frequency |
472 | 0 | if (freq < SLOF) { |
473 | 0 | freq -= LOF1; |
474 | 0 | hi_lo = 0; |
475 | 0 | } else { |
476 | 0 | freq -= LOF2; |
477 | 0 | hi_lo = 1; |
478 | 0 | } |
479 | 0 | } |
480 | 0 | MP_VERBOSE(priv, "tuning %s to Freq: %u, Pol: %c Srate: %d, " |
481 | 0 | "22kHz: %s, LNB: %d\n", get_dvb_delsys(delsys), freq, |
482 | 0 | pol, srate, hi_lo ? "on" : "off", diseqc); |
483 | |
|
484 | 0 | if (do_diseqc(fd_frontend, diseqc, (pol == 'V' ? 1 : 0), hi_lo) == 0) { |
485 | 0 | MP_VERBOSE(priv, "DISEQC setting succeeded\n"); |
486 | 0 | } else { |
487 | 0 | MP_ERR(priv, "DISEQC setting failed\n"); |
488 | 0 | return -1; |
489 | 0 | } |
490 | | |
491 | 0 | break; |
492 | 0 | case SYS_DVBC_ANNEX_A: |
493 | 0 | case SYS_DVBC_ANNEX_C: |
494 | 0 | MP_VERBOSE(priv, "tuning %s to %d, srate=%d\n", |
495 | 0 | get_dvb_delsys(delsys), freq, srate); |
496 | 0 | break; |
497 | 0 | case SYS_ATSC: |
498 | 0 | case SYS_DVBC_ANNEX_B: |
499 | 0 | MP_VERBOSE(priv, "tuning %s to %d, modulation=%d\n", |
500 | 0 | get_dvb_delsys(delsys), freq, modulation); |
501 | 0 | break; |
502 | 0 | default: |
503 | 0 | MP_VERBOSE(priv, "Unknown FE type, aborting.\n"); |
504 | 0 | return 0; |
505 | 0 | } |
506 | | |
507 | | /* S2API is the DVB API new since 2.6.28. |
508 | | * It is needed to tune to new delivery systems, e.g. DVB-S2. |
509 | | * It takes a struct with a list of pairs of command + parameter. |
510 | | */ |
511 | | |
512 | | /* Reset before tune. */ |
513 | 0 | struct dtv_property p_clear[] = { |
514 | 0 | { .cmd = DTV_CLEAR }, |
515 | 0 | }; |
516 | 0 | struct dtv_properties cmdseq_clear = { |
517 | 0 | .num = 1, |
518 | 0 | .props = p_clear |
519 | 0 | }; |
520 | 0 | if (ioctl(fd_frontend, FE_SET_PROPERTY, &cmdseq_clear) < 0) { |
521 | 0 | MP_ERR(priv, "DTV_CLEAR failed\n"); |
522 | 0 | } |
523 | | |
524 | | /* Tune. */ |
525 | 0 | switch (delsys) { |
526 | 0 | case SYS_DVBS: |
527 | 0 | case SYS_DVBS2: |
528 | 0 | { |
529 | 0 | struct dtv_property p[] = { |
530 | 0 | { .cmd = DTV_DELIVERY_SYSTEM, .u.data = delsys }, |
531 | 0 | { .cmd = DTV_FREQUENCY, .u.data = freq }, |
532 | 0 | { .cmd = DTV_MODULATION, .u.data = modulation }, |
533 | 0 | { .cmd = DTV_SYMBOL_RATE, .u.data = srate }, |
534 | 0 | { .cmd = DTV_INNER_FEC, .u.data = HP_CodeRate }, |
535 | 0 | { .cmd = DTV_INVERSION, .u.data = specInv }, |
536 | 0 | { .cmd = DTV_ROLLOFF, .u.data = ROLLOFF_AUTO }, |
537 | 0 | { .cmd = DTV_PILOT, .u.data = PILOT_AUTO }, |
538 | 0 | { .cmd = DTV_TUNE }, |
539 | 0 | }; |
540 | 0 | struct dtv_properties cmdseq = { |
541 | 0 | .num = MP_ARRAY_SIZE(p), |
542 | 0 | .props = p |
543 | 0 | }; |
544 | 0 | if (dvbv5_tune(priv, fd_frontend, delsys, &cmdseq) != 0) { |
545 | 0 | goto error_tune; |
546 | 0 | } |
547 | 0 | } |
548 | 0 | break; |
549 | 0 | case SYS_DVBT: |
550 | 0 | case SYS_DVBT2: |
551 | 0 | case SYS_ISDBT: |
552 | 0 | { |
553 | 0 | struct dtv_property p[] = { |
554 | 0 | { .cmd = DTV_DELIVERY_SYSTEM, .u.data = delsys }, |
555 | 0 | { .cmd = DTV_FREQUENCY, .u.data = freq }, |
556 | 0 | { .cmd = DTV_MODULATION, .u.data = modulation }, |
557 | 0 | { .cmd = DTV_SYMBOL_RATE, .u.data = srate }, |
558 | 0 | { .cmd = DTV_CODE_RATE_HP, .u.data = HP_CodeRate }, |
559 | 0 | { .cmd = DTV_CODE_RATE_LP, .u.data = LP_CodeRate }, |
560 | 0 | { .cmd = DTV_INVERSION, .u.data = specInv }, |
561 | 0 | { .cmd = DTV_BANDWIDTH_HZ, .u.data = bandwidth_hz }, |
562 | 0 | { .cmd = DTV_TRANSMISSION_MODE, .u.data = TransmissionMode }, |
563 | 0 | { .cmd = DTV_GUARD_INTERVAL, .u.data = guardInterval }, |
564 | 0 | { .cmd = DTV_HIERARCHY, .u.data = hier }, |
565 | 0 | { .cmd = DTV_STREAM_ID, .u.data = stream_id }, |
566 | 0 | { .cmd = DTV_TUNE }, |
567 | 0 | }; |
568 | 0 | struct dtv_properties cmdseq = { |
569 | 0 | .num = MP_ARRAY_SIZE(p), |
570 | 0 | .props = p |
571 | 0 | }; |
572 | 0 | if (dvbv5_tune(priv, fd_frontend, delsys, &cmdseq) != 0) { |
573 | 0 | goto error_tune; |
574 | 0 | } |
575 | 0 | } |
576 | 0 | break; |
577 | 0 | case SYS_DVBC_ANNEX_A: |
578 | 0 | case SYS_DVBC_ANNEX_C: |
579 | 0 | { |
580 | 0 | struct dtv_property p[] = { |
581 | 0 | { .cmd = DTV_DELIVERY_SYSTEM, .u.data = delsys }, |
582 | 0 | { .cmd = DTV_FREQUENCY, .u.data = freq }, |
583 | 0 | { .cmd = DTV_MODULATION, .u.data = modulation }, |
584 | 0 | { .cmd = DTV_SYMBOL_RATE, .u.data = srate }, |
585 | 0 | { .cmd = DTV_INNER_FEC, .u.data = HP_CodeRate }, |
586 | 0 | { .cmd = DTV_INVERSION, .u.data = specInv }, |
587 | 0 | { .cmd = DTV_TUNE }, |
588 | 0 | }; |
589 | 0 | struct dtv_properties cmdseq = { |
590 | 0 | .num = MP_ARRAY_SIZE(p), |
591 | 0 | .props = p |
592 | 0 | }; |
593 | 0 | if (dvbv5_tune(priv, fd_frontend, delsys, &cmdseq) != 0) { |
594 | 0 | goto error_tune; |
595 | 0 | } |
596 | 0 | } |
597 | 0 | break; |
598 | 0 | case SYS_ATSC: |
599 | 0 | case SYS_DVBC_ANNEX_B: |
600 | 0 | { |
601 | 0 | struct dtv_property p[] = { |
602 | 0 | { .cmd = DTV_DELIVERY_SYSTEM, .u.data = delsys }, |
603 | 0 | { .cmd = DTV_FREQUENCY, .u.data = freq }, |
604 | 0 | { .cmd = DTV_INVERSION, .u.data = specInv }, |
605 | 0 | { .cmd = DTV_MODULATION, .u.data = modulation }, |
606 | 0 | { .cmd = DTV_TUNE }, |
607 | 0 | }; |
608 | 0 | struct dtv_properties cmdseq = { |
609 | 0 | .num = MP_ARRAY_SIZE(p), |
610 | 0 | .props = p |
611 | 0 | }; |
612 | 0 | if (dvbv5_tune(priv, fd_frontend, delsys, &cmdseq) != 0) { |
613 | 0 | goto error_tune; |
614 | 0 | } |
615 | 0 | } |
616 | 0 | break; |
617 | 0 | } |
618 | | |
619 | 0 | int tune_status = check_status(priv, fd_frontend, timeout); |
620 | 0 | if (tune_status != 0) { |
621 | 0 | MP_ERR(priv, "Error locking to channel\n"); |
622 | 0 | } |
623 | 0 | return tune_status; |
624 | | |
625 | 0 | error_tune: |
626 | 0 | MP_ERR(priv, "Error tuning channel\n"); |
627 | 0 | return -1; |
628 | 0 | } |
629 | | |
630 | | int dvb_tune(dvb_priv_t *priv, unsigned int delsys, |
631 | | int freq, char pol, int srate, int diseqc, |
632 | | int stream_id, fe_spectral_inversion_t specInv, |
633 | | fe_modulation_t modulation, fe_guard_interval_t guardInterval, |
634 | | fe_transmit_mode_t TransmissionMode, fe_bandwidth_t bandWidth, |
635 | | fe_code_rate_t HP_CodeRate, |
636 | | fe_code_rate_t LP_CodeRate, fe_hierarchy_t hier, |
637 | | float timeout) |
638 | 0 | { |
639 | 0 | MP_INFO(priv, "Tuning to %s frequency %lu Hz\n", |
640 | 0 | get_dvb_delsys(delsys), (long unsigned int) freq); |
641 | |
|
642 | 0 | dvb_state_t *state = priv->state; |
643 | |
|
644 | 0 | int ris = tune_it(priv, state->fe_fd, delsys, freq, srate, pol, |
645 | 0 | stream_id, specInv, diseqc, modulation, |
646 | 0 | HP_CodeRate, TransmissionMode, guardInterval, |
647 | 0 | bandWidth, LP_CodeRate, hier, timeout); |
648 | |
|
649 | 0 | if (ris != 0) |
650 | 0 | MP_INFO(priv, "Tuning failed\n"); |
651 | |
|
652 | 0 | return ris == 0; |
653 | 0 | } |