1 /*****************************************************************************
2 * dvb.c: linux-dvb input for DVBlast
3 *****************************************************************************
4 * Copyright (C) 2008-2010 VideoLAN
6 * Authors: Christophe Massiot <massiot@via.ecp.fr>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
24 #ifdef HAVE_DVB_SUPPORT
32 #include <sys/types.h>
36 #include <sys/ioctl.h>
37 #include <sys/socket.h>
39 #include <netinet/in.h>
40 #include <arpa/inet.h>
44 /* DVB Card Drivers */
45 #include <linux/dvb/version.h>
46 #include <linux/dvb/dmx.h>
47 #include <linux/dvb/frontend.h>
48 #include <linux/dvb/ca.h>
50 #if DVBAPI_VERSION < 508
51 #define DTV_STREAM_ID 42
52 #define FE_CAN_MULTISTREAM 0x4000000
55 #define MAX_DELIVERY_SYSTEMS 20
61 #include <bitstream/common.h>
63 /*****************************************************************************
65 *****************************************************************************/
66 #define DVR_READ_TIMEOUT 30000000 /* 30 s */
67 #define CA_POLL_PERIOD 100000 /* 100 ms */
68 #define MAX_READ_ONCE 50
69 #define DVR_BUFFER_SIZE 40*188*1024 /* bytes */
71 int i_dvr_buffer_size
= DVR_BUFFER_SIZE
;
73 static int i_frontend
, i_dvr
;
74 static fe_status_t i_last_status
;
75 static mtime_t i_frontend_timeout
;
76 static mtime_t i_last_packet
= 0;
77 static mtime_t i_ca_next_event
= 0;
78 static block_t
*p_freelist
= NULL
;
80 /*****************************************************************************
82 *****************************************************************************/
83 static block_t
*DVRRead( void );
84 static void FrontendPoll( void );
85 static void FrontendSet( bool b_reset
);
87 /*****************************************************************************
89 *****************************************************************************/
94 msg_Dbg( NULL
, "compiled with DVB API version %d.%d", DVB_API_VERSION
, DVB_API_VERSION_MINOR
);
96 i_wallclock
= mdate();
100 sprintf( psz_tmp
, "/dev/dvb/adapter%d/frontend%d", i_adapter
, i_fenum
);
101 if( (i_frontend
= open(psz_tmp
, O_RDWR
| O_NONBLOCK
)) < 0 )
103 msg_Err( NULL
, "opening device %s failed (%s)", psz_tmp
,
115 sprintf( psz_tmp
, "/dev/dvb/adapter%d/dvr%d", i_adapter
, i_fenum
);
117 if( (i_dvr
= open(psz_tmp
, O_RDONLY
| O_NONBLOCK
)) < 0 )
119 msg_Err( NULL
, "opening device %s failed (%s)", psz_tmp
,
124 if ( ioctl( i_dvr
, DMX_SET_BUFFER_SIZE
, i_dvr_buffer_size
) < 0 )
126 msg_Warn( NULL
, "couldn't set %s buffer size (%s)", psz_tmp
,
131 i_ca_next_event
= mdate() + CA_POLL_PERIOD
;
134 /*****************************************************************************
136 *****************************************************************************/
137 void dvb_Reset( void )
143 /*****************************************************************************
145 *****************************************************************************/
146 block_t
*dvb_Read( mtime_t i_poll_timeout
)
148 struct pollfd ufds
[4];
149 int i_ret
, i_nb_fd
= 1;
150 block_t
*p_blocks
= NULL
;
152 memset( ufds
, 0, sizeof(ufds
) );
154 ufds
[0].events
= POLLIN
;
155 if ( i_frontend
!= -1 )
157 ufds
[1].fd
= i_frontend
;
158 ufds
[1].events
= POLLERR
| POLLPRI
;
161 if ( i_comm_fd
!= -1 )
163 ufds
[i_nb_fd
].fd
= i_comm_fd
;
164 ufds
[i_nb_fd
].events
= POLLIN
;
167 if ( i_ca_handle
&& i_ca_type
== CA_CI_LINK
)
169 ufds
[i_nb_fd
].fd
= i_ca_handle
;
170 ufds
[i_nb_fd
].events
= POLLIN
;
174 i_ret
= poll( ufds
, i_nb_fd
, (i_poll_timeout
+ 999) / 1000 );
176 i_wallclock
= mdate();
181 msg_Err( NULL
, "poll error: %s", strerror(errno
) );
185 if ( ufds
[1].revents
)
188 if ( ufds
[0].revents
)
190 p_blocks
= DVRRead();
191 i_wallclock
= mdate();
194 if ( p_blocks
!= NULL
)
195 i_last_packet
= i_wallclock
;
196 else if ( !i_frontend_timeout
197 && i_wallclock
> i_last_packet
+ DVR_READ_TIMEOUT
)
199 msg_Warn( NULL
, "no DVR output, resetting" );
205 if ( i_ca_handle
&& i_ca_type
== CA_CI_LINK
)
207 if ( ufds
[i_nb_fd
- 1].revents
)
210 i_ca_next_event
= i_wallclock
+ CA_POLL_PERIOD
;
212 else if ( i_wallclock
> i_ca_next_event
)
215 i_ca_next_event
= i_wallclock
+ CA_POLL_PERIOD
;
219 if ( i_frontend_timeout
&& i_wallclock
> i_frontend_timeout
)
221 if ( i_quit_timeout_duration
)
223 msg_Err( NULL
, "no lock" );
224 switch (i_print_type
) {
231 exit(EXIT_STATUS_FRONTEND_TIMEOUT
);
233 msg_Warn( NULL
, "no lock, tuning again" );
238 if ( i_comm_fd
!= -1 && ufds
[2].revents
)
244 /*****************************************************************************
246 *****************************************************************************/
247 static block_t
*DVRRead( void )
250 block_t
*p_ts
= p_freelist
, **pp_current
= &p_ts
;
251 struct iovec p_iov
[MAX_READ_ONCE
];
253 for ( i
= 0; i
< MAX_READ_ONCE
; i
++ )
255 if ( (*pp_current
) == NULL
) *pp_current
= block_New();
256 p_iov
[i
].iov_base
= (*pp_current
)->p_ts
;
257 p_iov
[i
].iov_len
= TS_SIZE
;
258 pp_current
= &(*pp_current
)->p_next
;
261 if ( (i_len
= readv(i_dvr
, p_iov
, MAX_READ_ONCE
)) < 0 )
263 msg_Err( NULL
, "couldn't read from DVR device (%s)",
270 while ( i_len
&& *pp_current
)
272 pp_current
= &(*pp_current
)->p_next
;
276 p_freelist
= *pp_current
;
287 /*****************************************************************************
288 * dvb_SetFilter : controls the demux to add a filter
289 *****************************************************************************/
290 int dvb_SetFilter( uint16_t i_pid
)
292 struct dmx_pes_filter_params s_filter_params
;
296 sprintf( psz_tmp
, "/dev/dvb/adapter%d/demux%d", i_adapter
, i_fenum
);
297 if( (i_fd
= open(psz_tmp
, O_RDWR
)) < 0 )
299 msg_Err( NULL
, "DMXSetFilter: opening device failed (%s)",
304 s_filter_params
.pid
= i_pid
;
305 s_filter_params
.input
= DMX_IN_FRONTEND
;
306 s_filter_params
.output
= DMX_OUT_TS_TAP
;
307 s_filter_params
.flags
= DMX_IMMEDIATE_START
;
308 s_filter_params
.pes_type
= DMX_PES_OTHER
;
310 if ( ioctl( i_fd
, DMX_SET_PES_FILTER
, &s_filter_params
) < 0 )
312 msg_Err( NULL
, "failed setting filter on %d (%s)", i_pid
,
318 msg_Dbg( NULL
, "setting filter on PID %d", i_pid
);
323 /*****************************************************************************
324 * dvb_UnsetFilter : removes a filter
325 *****************************************************************************/
326 void dvb_UnsetFilter( int i_fd
, uint16_t i_pid
)
328 if ( ioctl( i_fd
, DMX_STOP
) < 0 )
329 msg_Err( NULL
, "DMX_STOP failed (%s)", strerror(errno
) );
331 msg_Dbg( NULL
, "unsetting filter on PID %d", i_pid
);
341 /*****************************************************************************
342 * FrontendPoll : Poll for frontend events
343 *****************************************************************************/
344 static void FrontendPoll( void )
346 struct dvb_frontend_event event
;
347 fe_status_t i_status
, i_diff
;
351 int i_ret
= ioctl( i_frontend
, FE_GET_EVENT
, &event
);
355 if( errno
== EWOULDBLOCK
)
356 return; /* no more events */
358 msg_Err( NULL
, "reading frontend event failed (%d) %s",
359 i_ret
, strerror(errno
) );
363 i_status
= event
.status
;
364 i_diff
= i_status
^ i_last_status
;
365 i_last_status
= i_status
;
370 if ( i_diff & (x) ) \
372 if ( i_status & (x) )
374 IF_UP( FE_HAS_SIGNAL
)
375 msg_Dbg( NULL
, "frontend has acquired signal" );
377 msg_Dbg( NULL
, "frontend has lost signal" );
379 IF_UP( FE_HAS_CARRIER
)
380 msg_Dbg( NULL
, "frontend has acquired carrier" );
382 msg_Dbg( NULL
, "frontend has lost carrier" );
384 IF_UP( FE_HAS_VITERBI
)
385 msg_Dbg( NULL
, "frontend has acquired stable FEC" );
387 msg_Dbg( NULL
, "frontend has lost FEC" );
390 msg_Dbg( NULL
, "frontend has acquired sync" );
392 msg_Dbg( NULL
, "frontend has lost sync" );
397 msg_Info( NULL
, "frontend has acquired lock" );
398 switch (i_print_type
) {
400 printf("<STATUS type=\"lock\" status=\"1\" />\n");
403 printf("frontend has acquired lock\n" );
405 i_frontend_timeout
= 0;
406 i_last_packet
= i_wallclock
;
408 if ( i_quit_timeout_duration
&& !i_quit_timeout
)
409 i_quit_timeout
= i_wallclock
+ i_quit_timeout_duration
;
411 /* Read some statistics */
412 if( ioctl( i_frontend
, FE_READ_BER
, &i_value
) >= 0 )
413 msg_Dbg( NULL
, "- Bit error rate: %d", i_value
);
414 if( ioctl( i_frontend
, FE_READ_SIGNAL_STRENGTH
, &i_value
) >= 0 )
415 msg_Dbg( NULL
, "- Signal strength: %d", i_value
);
416 if( ioctl( i_frontend
, FE_READ_SNR
, &i_value
) >= 0 )
417 msg_Dbg( NULL
, "- SNR: %d", i_value
);
421 msg_Dbg( NULL
, "frontend has lost lock" );
422 switch (i_print_type
) {
424 printf("<STATUS type=\"lock\" status=\"0\"/>\n");
427 printf("frontend has lost lock\n" );
429 i_frontend_timeout
= i_wallclock
+ i_frontend_timeout_duration
;
434 /* The frontend was reinited. */
435 msg_Warn( NULL
, "reiniting frontend");
444 static int FrontendDoDiseqc(void)
446 fe_sec_voltage_t fe_voltage
;
447 fe_sec_tone_mode_t fe_tone
;
452 case 0: fe_voltage
= SEC_VOLTAGE_OFF
; break;
454 case 13: fe_voltage
= SEC_VOLTAGE_13
; break;
455 case 18: fe_voltage
= SEC_VOLTAGE_18
; break;
458 fe_tone
= b_tone
? SEC_TONE_ON
: SEC_TONE_OFF
;
460 /* Automatic mode. */
461 if ( i_frequency
>= 950000 && i_frequency
<= 2150000 )
463 msg_Dbg( NULL
, "frequency %d is in IF-band", i_frequency
);
464 bis_frequency
= i_frequency
;
466 else if ( i_frequency
>= 2500000 && i_frequency
<= 2700000 )
468 msg_Dbg( NULL
, "frequency %d is in S-band", i_frequency
);
469 bis_frequency
= 3650000 - i_frequency
;
471 else if ( i_frequency
>= 3400000 && i_frequency
<= 4200000 )
473 msg_Dbg( NULL
, "frequency %d is in C-band (lower)", i_frequency
);
474 bis_frequency
= 5150000 - i_frequency
;
476 else if ( i_frequency
>= 4500000 && i_frequency
<= 4800000 )
478 msg_Dbg( NULL
, "frequency %d is in C-band (higher)", i_frequency
);
479 bis_frequency
= 5950000 - i_frequency
;
481 else if ( i_frequency
>= 10700000 && i_frequency
< 11700000 )
483 msg_Dbg( NULL
, "frequency %d is in Ku-band (lower)",
485 bis_frequency
= i_frequency
- 9750000;
487 else if ( i_frequency
>= 11700000 && i_frequency
<= 13250000 )
489 msg_Dbg( NULL
, "frequency %d is in Ku-band (higher)",
491 bis_frequency
= i_frequency
- 10600000;
492 fe_tone
= SEC_TONE_ON
;
496 msg_Err( NULL
, "frequency %d is out of any known band",
501 /* Switch off continuous tone. */
502 if ( ioctl( i_frontend
, FE_SET_TONE
, SEC_TONE_OFF
) < 0 )
504 msg_Err( NULL
, "FE_SET_TONE failed (%s)", strerror(errno
) );
508 /* Configure LNB voltage. */
509 if ( ioctl( i_frontend
, FE_SET_VOLTAGE
, fe_voltage
) < 0 )
511 msg_Err( NULL
, "FE_SET_VOLTAGE failed (%s)", strerror(errno
) );
515 /* Wait for at least 15 ms. Currently 100 ms because of broken drivers. */
519 if ( i_satnum
> 0 && i_satnum
< 5 )
521 /* digital satellite equipment control,
522 * specification is available from http://www.eutelsat.com/
526 struct dvb_diseqc_master_cmd uncmd
=
527 { {0xe0, 0x10, 0x39, 0xf0, 0x00, 0x00}, 4};
530 struct dvb_diseqc_master_cmd cmd
=
531 { {0xe0, 0x10, 0x38, 0xf0, 0x00, 0x00}, 4};
533 cmd
.msg
[3] = 0xf0 /* reset bits */
534 | ((i_satnum
- 1) << 2)
535 | (fe_voltage
== SEC_VOLTAGE_13
? 0 : 2)
536 | (fe_tone
== SEC_TONE_ON
? 1 : 0);
538 if ( i_uncommitted
> 0 && i_uncommitted
< 5 )
540 uncmd
.msg
[3] = 0xf0 /* reset bits */
541 | ((i_uncommitted
- 1) << 2)
542 | (fe_voltage
== SEC_VOLTAGE_13
? 0 : 2)
543 | (fe_tone
== SEC_TONE_ON
? 1 : 0);
544 if( ioctl( i_frontend
, FE_DISEQC_SEND_MASTER_CMD
, &uncmd
) < 0 )
546 msg_Err( NULL
, "ioctl FE_SEND_MASTER_CMD failed (%s)",
550 /* Repeat uncommitted command */
551 uncmd
.msg
[0] = 0xe1; /* framing: master, no reply, repeated TX */
552 if( ioctl( i_frontend
, FE_DISEQC_SEND_MASTER_CMD
, &uncmd
) < 0 )
554 msg_Err( NULL
, "ioctl FE_SEND_MASTER_CMD failed (%s)",
558 /* Pause 125 ms between uncommitted & committed diseqc commands. */
562 if( ioctl( i_frontend
, FE_DISEQC_SEND_MASTER_CMD
, &cmd
) < 0 )
564 msg_Err( NULL
, "ioctl FE_SEND_MASTER_CMD failed (%s)",
568 msleep(100000); /* Should be 15 ms. */
570 /* Do it again just to be sure. */
571 cmd
.msg
[0] = 0xe1; /* framing: master, no reply, repeated TX */
572 if( ioctl( i_frontend
, FE_DISEQC_SEND_MASTER_CMD
, &cmd
) < 0 )
574 msg_Err( NULL
, "ioctl FE_SEND_MASTER_CMD failed (%s)",
578 msleep(100000); /* Again, should be 15 ms */
580 else if ( i_satnum
== 0xA || i_satnum
== 0xB )
582 /* A or B simple diseqc ("diseqc-compatible") */
583 if( ioctl( i_frontend
, FE_DISEQC_SEND_BURST
,
584 i_satnum
== 0xB ? SEC_MINI_B
: SEC_MINI_A
) < 0 )
586 msg_Err( NULL
, "ioctl FE_SEND_BURST failed (%s)", strerror(errno
) );
589 msleep(100000); /* ... */
592 if ( ioctl( i_frontend
, FE_SET_TONE
, fe_tone
) < 0 )
594 msg_Err( NULL
, "FE_SET_TONE failed (%s)", strerror(errno
) );
598 msleep(100000); /* ... */
600 msg_Dbg( NULL
, "configuring LNB to v=%d p=%d satnum=%x uncommitted=%x",
601 i_voltage
, b_tone
, i_satnum
, i_uncommitted
);
602 return bis_frequency
;
605 #if DVB_API_VERSION >= 5
607 #if DVBAPI_VERSION < 505
608 #warning Your linux-dvb headers are old, you should consider upgrading your kernel and/or compiling against different kernel headers
611 /*****************************************************************************
612 * Helper functions for S2API
613 *****************************************************************************/
614 static fe_spectral_inversion_t
GetInversion(void)
616 switch ( i_inversion
)
618 case 0: return INVERSION_OFF
;
619 case 1: return INVERSION_ON
;
621 msg_Warn( NULL
, "invalid inversion %d", i_inversion
);
622 case -1: return INVERSION_AUTO
;
626 static fe_code_rate_t
GetFEC(fe_caps_t fe_caps
, int i_fec_value
)
628 #define GET_FEC_INNER(fec, val) \
629 if ( (fe_caps & FE_CAN_##fec) && (i_fec_value == val) ) \
632 GET_FEC_INNER(FEC_AUTO
, 999);
633 GET_FEC_INNER(FEC_AUTO
, -1);
634 if (i_fec_value
== 0)
636 GET_FEC_INNER(FEC_1_2
, 12);
637 GET_FEC_INNER(FEC_2_3
, 23);
638 GET_FEC_INNER(FEC_3_4
, 34);
639 if (i_fec_value
== 35)
641 GET_FEC_INNER(FEC_4_5
, 45);
642 GET_FEC_INNER(FEC_5_6
, 56);
643 GET_FEC_INNER(FEC_6_7
, 67);
644 GET_FEC_INNER(FEC_7_8
, 78);
645 GET_FEC_INNER(FEC_8_9
, 89);
646 if (i_fec_value
== 910)
650 msg_Warn(NULL
, "invalid FEC %d", i_fec_value
);
654 #define GetFECInner(caps) GetFEC(caps, i_fec)
655 #define GetFECLP(caps) GetFEC(caps, i_fec_lp)
657 static fe_modulation_t
GetModulation(void)
659 #define GET_MODULATION( mod ) \
660 if ( !strcasecmp( psz_modulation, #mod ) ) \
663 GET_MODULATION(QPSK
);
664 GET_MODULATION(QAM_16
);
665 GET_MODULATION(QAM_32
);
666 GET_MODULATION(QAM_64
);
667 GET_MODULATION(QAM_128
);
668 GET_MODULATION(QAM_256
);
669 GET_MODULATION(QAM_AUTO
);
670 GET_MODULATION(VSB_8
);
671 GET_MODULATION(VSB_16
);
672 GET_MODULATION(PSK_8
);
673 GET_MODULATION(APSK_16
);
674 GET_MODULATION(APSK_32
);
675 GET_MODULATION(DQPSK
);
677 #undef GET_MODULATION
678 msg_Err( NULL
, "invalid modulation %s", psz_modulation
);
682 static fe_pilot_t
GetPilot(void)
686 case 0: return PILOT_OFF
;
687 case 1: return PILOT_ON
;
689 msg_Warn( NULL
, "invalid pilot %d", i_pilot
);
690 case -1: return PILOT_AUTO
;
694 static fe_rolloff_t
GetRollOff(void)
699 case 0: return ROLLOFF_AUTO
;
700 case 20: return ROLLOFF_20
;
701 case 25: return ROLLOFF_25
;
703 msg_Warn( NULL
, "invalid rolloff %d", i_rolloff
);
704 case 35: return ROLLOFF_35
;
708 static fe_guard_interval_t
GetGuard(void)
712 case 32: return GUARD_INTERVAL_1_32
;
713 case 16: return GUARD_INTERVAL_1_16
;
714 case 8: return GUARD_INTERVAL_1_8
;
715 case 4: return GUARD_INTERVAL_1_4
;
717 msg_Warn( NULL
, "invalid guard interval %d", i_guard
);
719 case 0: return GUARD_INTERVAL_AUTO
;
723 static fe_transmit_mode_t
GetTransmission(void)
725 switch ( i_transmission
)
727 case 2: return TRANSMISSION_MODE_2K
;
728 case 8: return TRANSMISSION_MODE_8K
;
729 #ifdef TRANSMISSION_MODE_4K
730 case 4: return TRANSMISSION_MODE_4K
;
733 msg_Warn( NULL
, "invalid tranmission mode %d", i_transmission
);
735 case 0: return TRANSMISSION_MODE_AUTO
;
739 static fe_hierarchy_t
GetHierarchy(void)
741 switch ( i_hierarchy
)
743 case 0: return HIERARCHY_NONE
;
744 case 1: return HIERARCHY_1
;
745 case 2: return HIERARCHY_2
;
746 case 4: return HIERARCHY_4
;
748 msg_Warn( NULL
, "invalid intramission mode %d", i_transmission
);
749 case -1: return HIERARCHY_AUTO
;
753 /*****************************************************************************
754 * FrontendInfo : Print frontend info
755 *****************************************************************************/
756 static void FrontendInfo( struct dvb_frontend_info
*info
, uint32_t version
,
757 fe_delivery_system_t
*p_systems
, int i_systems
)
759 msg_Dbg( NULL
, "using DVB API version %d.%d", version
/ 256, version
% 256 );
760 msg_Dbg( NULL
, "Frontend \"%s\" supports:", info
->name
);
761 msg_Dbg( NULL
, " frequency min: %d, max: %d, stepsize: %d, tolerance: %d",
762 info
->frequency_min
, info
->frequency_max
,
763 info
->frequency_stepsize
, info
->frequency_tolerance
);
764 msg_Dbg( NULL
, " symbolrate min: %d, max: %d, tolerance: %d",
765 info
->symbol_rate_min
, info
->symbol_rate_max
, info
->symbol_rate_tolerance
);
766 msg_Dbg( NULL
, " capabilities:" );
768 #define FRONTEND_INFO(caps,val,msg) \
770 msg_Dbg( NULL, " %s", msg );
772 FRONTEND_INFO( info
->caps
, FE_IS_STUPID
, "FE_IS_STUPID" )
773 FRONTEND_INFO( info
->caps
, FE_CAN_INVERSION_AUTO
, "INVERSION_AUTO" )
774 FRONTEND_INFO( info
->caps
, FE_CAN_FEC_1_2
, "FEC_1_2" )
775 FRONTEND_INFO( info
->caps
, FE_CAN_FEC_2_3
, "FEC_2_3" )
776 FRONTEND_INFO( info
->caps
, FE_CAN_FEC_3_4
, "FEC_3_4" )
777 FRONTEND_INFO( info
->caps
, FE_CAN_FEC_4_5
, "FEC_4_5" )
778 FRONTEND_INFO( info
->caps
, FE_CAN_FEC_5_6
, "FEC_5_6" )
779 FRONTEND_INFO( info
->caps
, FE_CAN_FEC_6_7
, "FEC_6_7" )
780 FRONTEND_INFO( info
->caps
, FE_CAN_FEC_7_8
, "FEC_7_8" )
781 FRONTEND_INFO( info
->caps
, FE_CAN_FEC_8_9
, "FEC_8_9" )
782 FRONTEND_INFO( info
->caps
, FE_CAN_FEC_AUTO
,"FEC_AUTO")
783 FRONTEND_INFO( info
->caps
, FE_CAN_QPSK
, "QPSK" )
784 FRONTEND_INFO( info
->caps
, FE_CAN_QAM_16
, "QAM_16" )
785 FRONTEND_INFO( info
->caps
, FE_CAN_QAM_32
, "QAM_32" )
786 FRONTEND_INFO( info
->caps
, FE_CAN_QAM_64
, "QAM_64" )
787 FRONTEND_INFO( info
->caps
, FE_CAN_QAM_128
,"QAM_128")
788 FRONTEND_INFO( info
->caps
, FE_CAN_QAM_256
,"QAM_256")
789 FRONTEND_INFO( info
->caps
, FE_CAN_QAM_AUTO
,"QAM_AUTO" )
790 FRONTEND_INFO( info
->caps
, FE_CAN_TRANSMISSION_MODE_AUTO
, "TRANSMISSION_MODE_AUTO" )
791 FRONTEND_INFO( info
->caps
, FE_CAN_BANDWIDTH_AUTO
, "BANDWIDTH_AUTO" )
792 FRONTEND_INFO( info
->caps
, FE_CAN_GUARD_INTERVAL_AUTO
, "GUARD_INTERVAL_AUTO" )
793 FRONTEND_INFO( info
->caps
, FE_CAN_HIERARCHY_AUTO
, "HIERARCHY_AUTO" )
794 FRONTEND_INFO( info
->caps
, FE_CAN_8VSB
, "8VSB" )
795 FRONTEND_INFO( info
->caps
, FE_CAN_16VSB
,"16VSB" )
796 FRONTEND_INFO( info
->caps
, FE_HAS_EXTENDED_CAPS
, "EXTENDED_CAPS" )
797 #if DVBAPI_VERSION >= 501
798 FRONTEND_INFO( info
->caps
, FE_CAN_2G_MODULATION
, "2G_MODULATION" )
800 FRONTEND_INFO( info
->caps
, FE_CAN_MULTISTREAM
, "MULTISTREAM" )
801 FRONTEND_INFO( info
->caps
, FE_NEEDS_BENDING
, "NEEDS_BENDING" )
802 FRONTEND_INFO( info
->caps
, FE_CAN_RECOVER
, "FE_CAN_RECOVER" )
803 FRONTEND_INFO( info
->caps
, FE_CAN_MUTE_TS
, "FE_CAN_MUTE_TS" )
806 msg_Dbg( NULL
, " delivery systems:" );
808 for ( i
= 0; i
< i_systems
; i
++ )
810 switch ( p_systems
[i
] )
812 #define DELSYS_INFO(delsys, msg) \
813 case delsys: msg_Dbg( NULL, " %s", msg); break;
814 DELSYS_INFO( SYS_ATSC
, "ATSC" )
815 DELSYS_INFO( SYS_ATSCMH
, "ATSCMH" )
816 DELSYS_INFO( SYS_CMMB
, "CMBB" )
817 DELSYS_INFO( SYS_DAB
, "DAB" )
818 DELSYS_INFO( SYS_DSS
, "DSS" )
819 DELSYS_INFO( SYS_DVBC_ANNEX_B
, "DVBC_ANNEX_B" )
820 DELSYS_INFO( SYS_DVBH
, "DVBH" )
821 DELSYS_INFO( SYS_DVBS
, "DVBS" )
822 DELSYS_INFO( SYS_DVBS2
, "DVBS2" )
823 DELSYS_INFO( SYS_DVBT
, "DVBT" )
824 DELSYS_INFO( SYS_ISDBC
, "ISDBC" )
825 DELSYS_INFO( SYS_ISDBS
, "ISDBS" )
826 DELSYS_INFO( SYS_ISDBT
, "ISDBT" )
827 DELSYS_INFO( SYS_UNDEFINED
, "UNDEFINED" )
828 #if DVBAPI_VERSION >= 505
829 DELSYS_INFO( SYS_DVBC_ANNEX_A
, "DVBC_ANNEX_A" )
830 DELSYS_INFO( SYS_DVBC_ANNEX_C
, "DVBC_ANNEX_C" )
831 DELSYS_INFO( SYS_DVBT2
, "DVBT2" )
832 DELSYS_INFO( SYS_TURBO
, "TURBO" )
834 DELSYS_INFO( SYS_DVBC_ANNEX_AC
, "DVBC_ANNEX_AC" )
836 #if DVBAPI_VERSION >= 507
837 DELSYS_INFO( SYS_DTMB
, "DTMB" )
839 DELSYS_INFO( SYS_DMBTH
, "DMBTH" )
845 /*****************************************************************************
847 *****************************************************************************/
849 #if DVBAPI_VERSION >= 505
850 static struct dtv_property info_cmdargs
[] = {
851 { .cmd
= DTV_API_VERSION
, .u
.data
= 0 },
853 static struct dtv_properties info_cmdseq
= {
854 .num
= sizeof(info_cmdargs
)/sizeof(struct dtv_property
),
855 .props
= info_cmdargs
858 static struct dtv_property enum_cmdargs
[] = {
859 { .cmd
= DTV_ENUM_DELSYS
, .u
.data
= 0 },
861 static struct dtv_properties enum_cmdseq
= {
862 .num
= sizeof(enum_cmdargs
)/sizeof(struct dtv_property
),
863 .props
= enum_cmdargs
867 static struct dtv_property dvbs_cmdargs
[] = {
868 { .cmd
= DTV_DELIVERY_SYSTEM
, .u
.data
= SYS_DVBS
},
869 { .cmd
= DTV_FREQUENCY
, .u
.data
= 0 },
870 { .cmd
= DTV_MODULATION
, .u
.data
= QPSK
},
871 { .cmd
= DTV_INVERSION
, .u
.data
= INVERSION_AUTO
},
872 { .cmd
= DTV_SYMBOL_RATE
, .u
.data
= 27500000 },
873 { .cmd
= DTV_INNER_FEC
, .u
.data
= FEC_AUTO
},
876 static struct dtv_properties dvbs_cmdseq
= {
877 .num
= sizeof(dvbs_cmdargs
)/sizeof(struct dtv_property
),
878 .props
= dvbs_cmdargs
881 static struct dtv_property dvbs2_cmdargs
[] = {
882 { .cmd
= DTV_DELIVERY_SYSTEM
, .u
.data
= SYS_DVBS2
},
883 { .cmd
= DTV_FREQUENCY
, .u
.data
= 0 },
884 { .cmd
= DTV_MODULATION
, .u
.data
= PSK_8
},
885 { .cmd
= DTV_INVERSION
, .u
.data
= INVERSION_AUTO
},
886 { .cmd
= DTV_SYMBOL_RATE
, .u
.data
= 27500000 },
887 { .cmd
= DTV_INNER_FEC
, .u
.data
= FEC_AUTO
},
888 { .cmd
= DTV_PILOT
, .u
.data
= PILOT_AUTO
},
889 { .cmd
= DTV_ROLLOFF
, .u
.data
= ROLLOFF_AUTO
},
890 { .cmd
= DTV_STREAM_ID
, .u
.data
= 0 },
893 static struct dtv_properties dvbs2_cmdseq
= {
894 .num
= sizeof(dvbs2_cmdargs
)/sizeof(struct dtv_property
),
895 .props
= dvbs2_cmdargs
898 static struct dtv_property dvbc_cmdargs
[] = {
899 #if DVBAPI_VERSION >= 505
900 { .cmd
= DTV_DELIVERY_SYSTEM
, .u
.data
= SYS_DVBC_ANNEX_A
},
902 { .cmd
= DTV_DELIVERY_SYSTEM
, .u
.data
= SYS_DVBC_ANNEX_AC
},
904 { .cmd
= DTV_FREQUENCY
, .u
.data
= 0 },
905 { .cmd
= DTV_MODULATION
, .u
.data
= QAM_AUTO
},
906 { .cmd
= DTV_INVERSION
, .u
.data
= INVERSION_AUTO
},
907 { .cmd
= DTV_SYMBOL_RATE
, .u
.data
= 27500000 },
910 static struct dtv_properties dvbc_cmdseq
= {
911 .num
= sizeof(dvbc_cmdargs
)/sizeof(struct dtv_property
),
912 .props
= dvbc_cmdargs
915 static struct dtv_property dvbt_cmdargs
[] = {
916 { .cmd
= DTV_DELIVERY_SYSTEM
, .u
.data
= SYS_DVBT
},
917 { .cmd
= DTV_FREQUENCY
, .u
.data
= 0 },
918 { .cmd
= DTV_MODULATION
, .u
.data
= QAM_AUTO
},
919 { .cmd
= DTV_INVERSION
, .u
.data
= INVERSION_AUTO
},
920 { .cmd
= DTV_BANDWIDTH_HZ
, .u
.data
= 8000000 },
921 { .cmd
= DTV_CODE_RATE_HP
, .u
.data
= FEC_AUTO
},
922 { .cmd
= DTV_CODE_RATE_LP
, .u
.data
= FEC_AUTO
},
923 { .cmd
= DTV_GUARD_INTERVAL
, .u
.data
= GUARD_INTERVAL_AUTO
},
924 { .cmd
= DTV_TRANSMISSION_MODE
,.u
.data
= TRANSMISSION_MODE_AUTO
},
925 { .cmd
= DTV_HIERARCHY
, .u
.data
= HIERARCHY_AUTO
},
928 static struct dtv_properties dvbt_cmdseq
= {
929 .num
= sizeof(dvbt_cmdargs
)/sizeof(struct dtv_property
),
930 .props
= dvbt_cmdargs
933 /* ATSC + DVB-C annex B */
934 static struct dtv_property atsc_cmdargs
[] = {
935 { .cmd
= DTV_DELIVERY_SYSTEM
, .u
.data
= SYS_ATSC
},
936 { .cmd
= DTV_FREQUENCY
, .u
.data
= 0 },
937 { .cmd
= DTV_MODULATION
, .u
.data
= QAM_AUTO
},
938 { .cmd
= DTV_INVERSION
, .u
.data
= INVERSION_AUTO
},
941 static struct dtv_properties atsc_cmdseq
= {
942 .num
= sizeof(atsc_cmdargs
)/sizeof(struct dtv_property
),
943 .props
= atsc_cmdargs
950 #define SYMBOL_RATE 4
956 #define TRANSMISSION 8
961 struct dtv_property pclear
[] = {
962 { .cmd
= DTV_CLEAR
},
965 struct dtv_properties cmdclear
= {
970 static fe_delivery_system_t
971 FrontendGuessSystem( fe_delivery_system_t
*p_systems
, int i_systems
)
973 if ( psz_delsys
!= NULL
)
975 if ( !strcasecmp( psz_delsys
, "DVBS" ) )
977 if ( !strcasecmp( psz_delsys
, "DVBS2" ) )
979 if ( !strcasecmp( psz_delsys
, "DVBC_ANNEX_A" ) )
980 #if DVBAPI_VERSION >= 505
981 return SYS_DVBC_ANNEX_A
;
983 return SYS_DVBC_ANNEX_AC
;
985 if ( !strcasecmp( psz_delsys
, "DVBC_ANNEX_B" ) )
986 return SYS_DVBC_ANNEX_B
;
987 if ( !strcasecmp( psz_delsys
, "DVBT" ) )
989 if ( !strcasecmp( psz_delsys
, "ATSC" ) )
991 msg_Err( NULL
, "unknown delivery system %s", psz_delsys
);
995 if ( i_systems
== 1 )
999 for ( i
= 0; i
< i_systems
; i
++ )
1001 switch ( p_systems
[i
] )
1004 if ( i_frequency
< 50000000 )
1007 #if DVBAPI_VERSION >= 505
1008 case SYS_DVBC_ANNEX_A
:
1009 if ( i_frequency
> 50000000 || i_srate
!= 27500000 ||
1010 psz_modulation
!= NULL
)
1011 return SYS_DVBC_ANNEX_A
;
1014 case SYS_DVBC_ANNEX_AC
:
1015 if ( i_frequency
> 50000000 || i_srate
!= 27500000 ||
1016 psz_modulation
!= NULL
)
1017 return SYS_DVBC_ANNEX_AC
;
1021 if ( i_frequency
> 50000000 )
1029 msg_Warn( NULL
, "couldn't guess delivery system, use --delsys" );
1030 return p_systems
[0];
1033 static void FrontendSet( bool b_init
)
1035 struct dvb_frontend_info info
;
1036 struct dtv_properties
*p
;
1037 fe_delivery_system_t p_systems
[MAX_DELIVERY_SYSTEMS
] = { 0 };
1040 if ( ioctl( i_frontend
, FE_GET_INFO
, &info
) < 0 )
1042 msg_Err( NULL
, "FE_GET_INFO failed (%s)", strerror(errno
) );
1046 uint32_t version
= 0x300;
1047 #if DVBAPI_VERSION >= 505
1048 if ( ioctl( i_frontend
, FE_GET_PROPERTY
, &info_cmdseq
) < 0 )
1052 switch ( info
.type
)
1055 p_systems
[i_systems
++] = SYS_DVBT
;
1056 #if DVBAPI_VERSION >= 505
1057 if ( info
.caps
& FE_CAN_2G_MODULATION
)
1058 p_systems
[i_systems
++] = SYS_DVBT2
;
1062 #if DVBAPI_VERSION >= 505
1063 p_systems
[i_systems
++] = SYS_DVBC_ANNEX_A
;
1065 p_systems
[i_systems
++] = SYS_DVBC_ANNEX_AC
;
1069 p_systems
[i_systems
++] = SYS_DVBS
;
1070 if ( info
.caps
& FE_CAN_2G_MODULATION
)
1071 p_systems
[i_systems
++] = SYS_DVBS2
;
1074 if ( info
.caps
& (FE_CAN_8VSB
| FE_CAN_16VSB
) )
1075 p_systems
[i_systems
++] = SYS_ATSC
;
1076 if ( info
.caps
& (FE_CAN_QAM_64
| FE_CAN_QAM_256
| FE_CAN_QAM_AUTO
) )
1077 p_systems
[i_systems
++] = SYS_DVBC_ANNEX_B
;
1080 msg_Err( NULL
, "unknown frontend type %d", info
.type
);
1083 #if DVBAPI_VERSION >= 505
1087 version
= info_cmdargs
[0].u
.data
;
1088 if ( ioctl( i_frontend
, FE_GET_PROPERTY
, &enum_cmdseq
) < 0 )
1090 msg_Err( NULL
, "unable to query frontend" );
1093 i_systems
= enum_cmdargs
[0].u
.buffer
.len
;
1094 if ( i_systems
< 1 )
1096 msg_Err( NULL
, "no available delivery system" );
1101 for ( i
= 0; i
< i_systems
; i
++ )
1102 p_systems
[i
] = enum_cmdargs
[0].u
.buffer
.data
[i
];
1107 FrontendInfo( &info
, version
, p_systems
, i_systems
);
1109 /* Clear frontend commands */
1110 if ( ioctl( i_frontend
, FE_SET_PROPERTY
, &cmdclear
) < 0 )
1112 msg_Err( NULL
, "Unable to clear frontend" );
1116 fe_delivery_system_t system
= FrontendGuessSystem( p_systems
, i_systems
);
1121 p
->props
[DELSYS
].u
.data
= system
;
1122 p
->props
[FREQUENCY
].u
.data
= i_frequency
;
1123 p
->props
[INVERSION
].u
.data
= GetInversion();
1124 if ( psz_modulation
!= NULL
)
1125 p
->props
[MODULATION
].u
.data
= GetModulation();
1126 p
->props
[BANDWIDTH
].u
.data
= i_bandwidth
* 1000000;
1127 p
->props
[FEC_INNER
].u
.data
= GetFECInner(info
.caps
);
1128 p
->props
[FEC_LP
].u
.data
= GetFECLP(info
.caps
);
1129 p
->props
[GUARD
].u
.data
= GetGuard();
1130 p
->props
[TRANSMISSION
].u
.data
= GetTransmission();
1131 p
->props
[HIERARCHY
].u
.data
= GetHierarchy();
1133 msg_Dbg( NULL
, "tuning DVB-T frontend to f=%d bandwidth=%d inversion=%d fec_hp=%d fec_lp=%d hierarchy=%d modulation=%s guard=%d transmission=%d",
1134 i_frequency
, i_bandwidth
, i_inversion
, i_fec
, i_fec_lp
,
1136 psz_modulation
== NULL
? "qam_auto" : psz_modulation
,
1137 i_guard
, i_transmission
);
1140 #if DVBAPI_VERSION >= 505
1141 case SYS_DVBC_ANNEX_A
:
1143 case SYS_DVBC_ANNEX_AC
:
1146 p
->props
[FREQUENCY
].u
.data
= i_frequency
;
1147 p
->props
[INVERSION
].u
.data
= GetInversion();
1148 if ( psz_modulation
!= NULL
)
1149 p
->props
[MODULATION
].u
.data
= GetModulation();
1150 p
->props
[SYMBOL_RATE
].u
.data
= i_srate
;
1152 msg_Dbg( NULL
, "tuning DVB-C frontend to f=%d srate=%d inversion=%d modulation=%s",
1153 i_frequency
, i_srate
, i_inversion
,
1154 psz_modulation
== NULL
? "qam_auto" : psz_modulation
);
1157 case SYS_DVBC_ANNEX_B
:
1159 p
->props
[DELSYS
].u
.data
= system
;
1160 p
->props
[FREQUENCY
].u
.data
= i_frequency
;
1161 p
->props
[INVERSION
].u
.data
= GetInversion();
1162 if ( psz_modulation
!= NULL
)
1163 p
->props
[MODULATION
].u
.data
= GetModulation();
1165 msg_Dbg( NULL
, "tuning ATSC cable frontend to f=%d inversion=%d modulation=%s",
1166 i_frequency
, i_inversion
,
1167 psz_modulation
== NULL
? "qam_auto" : psz_modulation
);
1172 if ( psz_modulation
!= NULL
)
1175 p
->props
[MODULATION
].u
.data
= GetModulation();
1176 p
->props
[PILOT
].u
.data
= GetPilot();
1177 p
->props
[ROLLOFF
].u
.data
= GetRollOff();
1178 p
->props
[MIS
].u
.data
= i_mis
;
1183 p
->props
[INVERSION
].u
.data
= GetInversion();
1184 p
->props
[SYMBOL_RATE
].u
.data
= i_srate
;
1185 p
->props
[FEC_INNER
].u
.data
= GetFECInner(info
.caps
);
1186 p
->props
[FREQUENCY
].u
.data
= FrontendDoDiseqc();
1188 msg_Dbg( NULL
, "tuning DVB-S frontend to f=%d srate=%d inversion=%d fec=%d rolloff=%d modulation=%s pilot=%d mis=%d",
1189 i_frequency
, i_srate
, i_inversion
, i_fec
, i_rolloff
,
1190 psz_modulation
== NULL
? "legacy" : psz_modulation
, i_pilot
,
1196 p
->props
[FREQUENCY
].u
.data
= i_frequency
;
1197 p
->props
[INVERSION
].u
.data
= GetInversion();
1198 if ( psz_modulation
!= NULL
)
1199 p
->props
[MODULATION
].u
.data
= GetModulation();
1201 msg_Dbg( NULL
, "tuning ATSC frontend to f=%d inversion=%d modulation=%s",
1202 i_frequency
, i_inversion
,
1203 psz_modulation
== NULL
? "qam_auto" : psz_modulation
);
1207 msg_Err( NULL
, "unknown frontend type %d", info
.type
);
1211 /* Empty the event queue */
1214 struct dvb_frontend_event event
;
1215 if ( ioctl( i_frontend
, FE_GET_EVENT
, &event
) < 0
1216 && errno
== EWOULDBLOCK
)
1220 /* Now send it all to the frontend device */
1221 if ( ioctl( i_frontend
, FE_SET_PROPERTY
, p
) < 0 )
1223 msg_Err( NULL
, "setting frontend failed (%s)", strerror(errno
) );
1228 i_frontend_timeout
= i_wallclock
+ i_frontend_timeout_duration
;
1233 #warning "You are trying to compile DVBlast with an outdated linux-dvb interface."
1234 #warning "DVBlast will be very limited and some options will have no effect."
1236 static void FrontendSet( bool b_init
)
1238 struct dvb_frontend_info info
;
1239 struct dvb_frontend_parameters fep
;
1241 if ( ioctl( i_frontend
, FE_GET_INFO
, &info
) < 0 )
1243 msg_Err( NULL
, "FE_GET_INFO failed (%s)", strerror(errno
) );
1247 switch ( info
.type
)
1250 fep
.frequency
= i_frequency
;
1251 fep
.inversion
= INVERSION_AUTO
;
1253 switch ( i_bandwidth
)
1255 case 6: fep
.u
.ofdm
.bandwidth
= BANDWIDTH_6_MHZ
; break;
1256 case 7: fep
.u
.ofdm
.bandwidth
= BANDWIDTH_7_MHZ
; break;
1258 case 8: fep
.u
.ofdm
.bandwidth
= BANDWIDTH_8_MHZ
; break;
1261 fep
.u
.ofdm
.code_rate_HP
= FEC_AUTO
;
1262 fep
.u
.ofdm
.code_rate_LP
= FEC_AUTO
;
1263 fep
.u
.ofdm
.constellation
= QAM_AUTO
;
1264 fep
.u
.ofdm
.transmission_mode
= TRANSMISSION_MODE_AUTO
;
1265 fep
.u
.ofdm
.guard_interval
= GUARD_INTERVAL_AUTO
;
1266 fep
.u
.ofdm
.hierarchy_information
= HIERARCHY_AUTO
;
1268 msg_Dbg( NULL
, "tuning OFDM frontend to f=%d, bandwidth=%d",
1269 i_frequency
, i_bandwidth
);
1273 fep
.frequency
= i_frequency
;
1274 fep
.inversion
= INVERSION_AUTO
;
1275 fep
.u
.qam
.symbol_rate
= i_srate
;
1276 fep
.u
.qam
.fec_inner
= FEC_AUTO
;
1277 fep
.u
.qam
.modulation
= QAM_AUTO
;
1279 msg_Dbg( NULL
, "tuning QAM frontend to f=%d, srate=%d",
1280 i_frequency
, i_srate
);
1284 fep
.inversion
= INVERSION_AUTO
;
1285 fep
.u
.qpsk
.symbol_rate
= i_srate
;
1286 fep
.u
.qpsk
.fec_inner
= FEC_AUTO
;
1287 fep
.frequency
= FrontendDoDiseqc();
1289 msg_Dbg( NULL
, "tuning QPSK frontend to f=%d, srate=%d",
1290 i_frequency
, i_srate
);
1293 #if DVBAPI_VERSION >= 301
1295 fep
.frequency
= i_frequency
;
1297 fep
.u
.vsb
.modulation
= QAM_AUTO
;
1299 msg_Dbg( NULL
, "tuning ATSC frontend to f=%d", i_frequency
);
1304 msg_Err( NULL
, "unknown frontend type %d", info
.type
);
1308 /* Empty the event queue */
1311 struct dvb_frontend_event event
;
1312 if ( ioctl( i_frontend
, FE_GET_EVENT
, &event
) < 0
1313 && errno
== EWOULDBLOCK
)
1317 /* Now send it all to the frontend device */
1318 if ( ioctl( i_frontend
, FE_SET_FRONTEND
, &fep
) < 0 )
1320 msg_Err( NULL
, "setting frontend failed (%s)", strerror(errno
) );
1325 i_frontend_timeout
= i_wallclock
+ i_frontend_timeout_duration
;
1330 /*****************************************************************************
1331 * dvb_FrontendStatus
1332 *****************************************************************************/
1333 uint8_t dvb_FrontendStatus( uint8_t *p_answer
, ssize_t
*pi_size
)
1335 struct ret_frontend_status
*p_ret
= (struct ret_frontend_status
*)p_answer
;
1337 if ( ioctl( i_frontend
, FE_GET_INFO
, &p_ret
->info
) < 0 )
1339 msg_Err( NULL
, "ioctl FE_GET_INFO failed (%s)", strerror(errno
) );
1343 if ( ioctl( i_frontend
, FE_READ_STATUS
, &p_ret
->i_status
) < 0 )
1345 msg_Err( NULL
, "ioctl FE_READ_STATUS failed (%s)", strerror(errno
) );
1349 if ( p_ret
->i_status
& FE_HAS_LOCK
)
1351 if ( ioctl( i_frontend
, FE_READ_BER
, &p_ret
->i_ber
) < 0 )
1352 msg_Err( NULL
, "ioctl FE_READ_BER failed (%s)", strerror(errno
) );
1354 if ( ioctl( i_frontend
, FE_READ_SIGNAL_STRENGTH
, &p_ret
->i_strength
)
1356 msg_Err( NULL
, "ioctl FE_READ_SIGNAL_STRENGTH failed (%s)",
1359 if ( ioctl( i_frontend
, FE_READ_SNR
, &p_ret
->i_snr
) < 0 )
1360 msg_Err( NULL
, "ioctl FE_READ_SNR failed (%s)", strerror(errno
) );
1363 *pi_size
= sizeof(struct ret_frontend_status
);
1364 return RET_FRONTEND_STATUS
;