1 /*****************************************************************************
2 * linux_dvb.c : functions to control a DVB card under Linux with v4l2
3 *****************************************************************************
4 * Copyright (C) 1998-2010 the VideoLAN team
6 * Authors: Damien Lucas <nitrox@via.ecp.fr>
7 * Johan Bilien <jobi@via.ecp.fr>
8 * Jean-Paul Saman <jpsaman _at_ videolan _dot_ org>
9 * Christopher Ross <chris@tebibyte.org>
10 * Christophe Massiot <massiot@via.ecp.fr>
11 * David Kaplan <david@of1.org>
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
26 *****************************************************************************/
32 #include <vlc_common.h>
33 #include <vlc_access.h>
34 #include <sys/ioctl.h>
37 #include <sys/types.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 /* Include dvbpsi headers */
51 #ifdef HAVE_DVBPSI_DR_H
52 # include <dvbpsi/dvbpsi.h>
53 # include <dvbpsi/descriptor.h>
54 # include <dvbpsi/pat.h>
55 # include <dvbpsi/pmt.h>
56 # include <dvbpsi/dr.h>
57 # include <dvbpsi/psi.h>
58 # include <dvbpsi/demux.h>
59 # include <dvbpsi/sdt.h>
62 # include "descriptor.h"
63 # include "tables/pat.h"
64 # include "tables/pmt.h"
65 # include "descriptors/dr.h"
68 # include "tables/sdt.h"
72 # include <vlc_httpd.h>
82 fe_status_t i_last_status;
83 struct dvb_frontend_info info;
86 #define FRONTEND_LOCK_TIMEOUT 10000000 /* 10 s */
88 /* Local prototypes */
89 static int FrontendInfo( access_t * );
90 static int FrontendSetQPSK( access_t * );
91 static int FrontendSetQAM( access_t * );
92 static int FrontendSetOFDM( access_t * );
93 static int FrontendSetATSC( access_t * );
95 /*****************************************************************************
96 * FrontendOpen : Determine frontend device information and capabilities
97 *****************************************************************************/
98 int FrontendOpen( access_t *p_access )
100 access_sys_t *p_sys = p_access->p_sys;
101 frontend_t * p_frontend;
102 unsigned int i_adapter, i_device;
106 i_adapter = var_GetInteger( p_access, "dvb-adapter" );
107 i_device = var_GetInteger( p_access, "dvb-device" );
108 b_probe = var_GetBool( p_access, "dvb-probe" );
110 if( snprintf( frontend, sizeof(frontend), FRONTEND, i_adapter, i_device ) >= (int)sizeof(frontend) )
112 msg_Err( p_access, "snprintf() truncated string for FRONTEND" );
113 frontend[sizeof(frontend) - 1] = '\0';
116 p_sys->p_frontend = p_frontend = malloc( sizeof(frontend_t) );
120 msg_Dbg( p_access, "Opening device %s", frontend );
121 if( (p_sys->i_frontend_handle = vlc_open(frontend, O_RDWR | O_NONBLOCK)) < 0 )
123 msg_Err( p_access, "FrontEndOpen: opening device failed (%m)" );
130 const char * psz_expected = NULL;
131 const char * psz_real;
133 if( FrontendInfo( p_access ) < 0 )
135 close( p_sys->i_frontend_handle );
140 switch( p_frontend->info.type )
155 psz_real = "unknown";
159 if( (!strncmp( p_access->psz_access, "qpsk", 4 ) ||
160 !strncmp( p_access->psz_access, "dvb-s", 5 ) ||
161 !strncmp( p_access->psz_access, "satellite", 9 ) ) &&
162 (p_frontend->info.type != FE_QPSK) )
164 psz_expected = "DVB-S";
166 if( (!strncmp( p_access->psz_access, "cable", 5 ) ||
167 !strncmp( p_access->psz_access, "dvb-c", 5 ) ) &&
168 (p_frontend->info.type != FE_QAM) )
170 psz_expected = "DVB-C";
172 if( (!strncmp( p_access->psz_access, "terrestrial", 11 ) ||
173 !strncmp( p_access->psz_access, "dvb-t", 5 ) ) &&
174 (p_frontend->info.type != FE_OFDM) )
176 psz_expected = "DVB-T";
179 if( (!strncmp( p_access->psz_access, "usdigital", 9 ) ||
180 !strncmp( p_access->psz_access, "atsc", 4 ) ) &&
181 (p_frontend->info.type != FE_ATSC) )
183 psz_expected = "ATSC";
186 if( psz_expected != NULL )
188 msg_Err( p_access, "the user asked for %s, and the tuner is %s",
189 psz_expected, psz_real );
190 close( p_sys->i_frontend_handle );
195 else /* no frontend probing is done so use default border values. */
197 msg_Dbg( p_access, "using default values for frontend info" );
199 msg_Dbg( p_access, "method of access is %s", p_access->psz_access );
200 p_frontend->info.type = FE_QPSK;
201 if( !strncmp( p_access->psz_access, "qpsk", 4 ) ||
202 !strncmp( p_access->psz_access, "dvb-s", 5 ) )
203 p_frontend->info.type = FE_QPSK;
204 else if( !strncmp( p_access->psz_access, "cable", 5 ) ||
205 !strncmp( p_access->psz_access, "dvb-c", 5 ) )
206 p_frontend->info.type = FE_QAM;
207 else if( !strncmp( p_access->psz_access, "terrestrial", 11 ) ||
208 !strncmp( p_access->psz_access, "dvb-t", 5 ) )
209 p_frontend->info.type = FE_OFDM;
210 else if( !strncmp( p_access->psz_access, "usdigital", 9 ) ||
211 !strncmp( p_access->psz_access, "atsc", 4 ) )
212 p_frontend->info.type = FE_ATSC;
218 /*****************************************************************************
219 * FrontendClose : Close the frontend
220 *****************************************************************************/
221 void FrontendClose( access_t *p_access )
223 access_sys_t *p_sys = p_access->p_sys;
225 if( p_sys->p_frontend )
227 close( p_sys->i_frontend_handle );
228 free( p_sys->p_frontend );
230 p_sys->p_frontend = NULL;
234 /*****************************************************************************
235 * FrontendSet : Tune !
236 *****************************************************************************/
237 int FrontendSet( access_t *p_access )
239 access_sys_t *p_sys = p_access->p_sys;
241 switch( p_sys->p_frontend->info.type )
245 if( FrontendSetQPSK( p_access ) < 0 )
247 msg_Err( p_access, "DVB-S: tuning failed" );
254 if( FrontendSetQAM( p_access ) < 0 )
256 msg_Err( p_access, "DVB-C: tuning failed" );
263 if( FrontendSetOFDM( p_access ) < 0 )
265 msg_Err( p_access, "DVB-T: tuning failed" );
272 if( FrontendSetATSC( p_access ) < 0 )
274 msg_Err( p_access, "ATSC: tuning failed" );
280 msg_Err( p_access, "Could not determine frontend type on %s",
281 p_sys->p_frontend->info.name );
284 p_sys->p_frontend->i_last_status = 0;
285 p_sys->i_frontend_timeout = mdate() + FRONTEND_LOCK_TIMEOUT;
289 /*****************************************************************************
290 * FrontendPoll : Poll for frontend events
291 *****************************************************************************/
292 void FrontendPoll( access_t *p_access )
294 access_sys_t *p_sys = p_access->p_sys;
295 frontend_t * p_frontend = p_sys->p_frontend;
296 struct dvb_frontend_event event;
297 fe_status_t i_status, i_diff;
301 int i_ret = ioctl( p_sys->i_frontend_handle, FE_GET_EVENT, &event );
305 if( errno == EWOULDBLOCK )
306 return; /* no more events */
308 msg_Err( p_access, "reading frontend event failed (%d): %m",
313 i_status = event.status;
314 i_diff = i_status ^ p_frontend->i_last_status;
315 p_frontend->i_last_status = i_status;
320 if ( i_diff & (x) ) \
322 if ( i_status & (x) )
324 IF_UP( FE_HAS_SIGNAL )
325 msg_Dbg( p_access, "frontend has acquired signal" );
327 msg_Dbg( p_access, "frontend has lost signal" );
329 IF_UP( FE_HAS_CARRIER )
330 msg_Dbg( p_access, "frontend has acquired carrier" );
332 msg_Dbg( p_access, "frontend has lost carrier" );
334 IF_UP( FE_HAS_VITERBI )
335 msg_Dbg( p_access, "frontend has acquired stable FEC" );
337 msg_Dbg( p_access, "frontend has lost FEC" );
340 msg_Dbg( p_access, "frontend has acquired sync" );
342 msg_Dbg( p_access, "frontend has lost sync" );
346 frontend_statistic_t stat;
348 msg_Dbg( p_access, "frontend has acquired lock" );
349 p_sys->i_frontend_timeout = 0;
351 /* Read some statistics */
352 if( !FrontendGetStatistic( p_access, &stat ) )
354 if( stat.i_ber >= 0 )
355 msg_Dbg( p_access, "- Bit error rate: %d", stat.i_ber );
356 if( stat.i_signal_strenth >= 0 )
357 msg_Dbg( p_access, "- Signal strength: %d", stat.i_signal_strenth );
358 if( stat.i_snr >= 0 )
359 msg_Dbg( p_access, "- SNR: %d", stat.i_snr );
364 msg_Dbg( p_access, "frontend has lost lock" );
365 p_sys->i_frontend_timeout = mdate() + FRONTEND_LOCK_TIMEOUT;
370 /* The frontend was reinited. */
371 msg_Warn( p_access, "reiniting frontend");
372 FrontendSet( p_access );
379 int FrontendGetStatistic( access_t *p_access, frontend_statistic_t *p_stat )
381 access_sys_t *p_sys = p_access->p_sys;
382 frontend_t * p_frontend = p_sys->p_frontend;
384 if( (p_frontend->i_last_status & FE_HAS_LOCK) == 0 )
387 memset( p_stat, 0, sizeof(*p_stat) );
388 if( ioctl( p_sys->i_frontend_handle, FE_READ_BER, &p_stat->i_ber ) < 0 )
390 if( ioctl( p_sys->i_frontend_handle, FE_READ_SIGNAL_STRENGTH, &p_stat->i_signal_strenth ) < 0 )
391 p_stat->i_signal_strenth = -1;
392 if( ioctl( p_sys->i_frontend_handle, FE_READ_SNR, &p_stat->i_snr ) < 0 )
398 void FrontendGetStatus( access_t *p_access, frontend_status_t *p_status )
400 access_sys_t *p_sys = p_access->p_sys;
401 frontend_t * p_frontend = p_sys->p_frontend;
403 p_status->b_has_signal = (p_frontend->i_last_status & FE_HAS_SIGNAL) != 0;
404 p_status->b_has_carrier = (p_frontend->i_last_status & FE_HAS_CARRIER) != 0;
405 p_status->b_has_lock = (p_frontend->i_last_status & FE_HAS_LOCK) != 0;
408 static int ScanParametersDvbS( access_t *p_access, scan_parameter_t *p_scan )
410 const frontend_t *p_frontend = p_access->p_sys->p_frontend;
412 memset( p_scan, 0, sizeof(*p_scan) );
413 p_scan->type = SCAN_DVB_S;
415 p_scan->frequency.i_min = p_frontend->info.frequency_min;
416 p_scan->frequency.i_max = p_frontend->info.frequency_max;
421 static int ScanParametersDvbC( access_t *p_access, scan_parameter_t *p_scan )
423 const frontend_t *p_frontend = p_access->p_sys->p_frontend;
426 memset( p_scan, 0, sizeof(*p_scan) );
427 p_scan->type = SCAN_DVB_C;
428 p_scan->b_exhaustive = false;
431 p_scan->frequency.i_min = p_frontend->info.frequency_min;
432 p_scan->frequency.i_max = p_frontend->info.frequency_max;
433 p_scan->frequency.i_step = p_frontend->info.frequency_stepsize
434 ? p_frontend->info.frequency_stepsize : 166667;
435 p_scan->frequency.i_count = (p_scan->frequency.i_max-p_scan->frequency.i_min)/p_scan->frequency.i_step;
438 p_scan->bandwidth.i_min = 6;
439 p_scan->bandwidth.i_max = 8;
440 p_scan->bandwidth.i_step = 1;
441 p_scan->bandwidth.i_count = 3;
445 static int ScanParametersDvbT( access_t *p_access, scan_parameter_t *p_scan )
447 const frontend_t *p_frontend = p_access->p_sys->p_frontend;
450 memset( p_scan, 0, sizeof(*p_scan) );
451 p_scan->type = SCAN_DVB_T;
452 p_scan->b_exhaustive = false;
455 p_scan->frequency.i_min = p_frontend->info.frequency_min;
456 p_scan->frequency.i_max = p_frontend->info.frequency_max;
457 p_scan->frequency.i_step = p_frontend->info.frequency_stepsize
458 ? p_frontend->info.frequency_stepsize : 166667;
459 p_scan->frequency.i_count = (p_scan->frequency.i_max-p_scan->frequency.i_min)/p_scan->frequency.i_step;
462 p_scan->bandwidth.i_min = 6;
463 p_scan->bandwidth.i_max = 8;
464 p_scan->bandwidth.i_step = 1;
465 p_scan->bandwidth.i_count = 3;
469 int FrontendGetScanParameter( access_t *p_access, scan_parameter_t *p_scan )
471 access_sys_t *p_sys = p_access->p_sys;
472 const frontend_t *p_frontend = p_sys->p_frontend;
474 if( p_frontend->info.type == FE_OFDM ) /* DVB-T */
475 return ScanParametersDvbT( p_access, p_scan );
476 else if( p_frontend->info.type == FE_QAM ) /* DVB-C */
477 return ScanParametersDvbC( p_access, p_scan );
478 else if( p_frontend->info.type == FE_QPSK )
479 return ScanParametersDvbS( p_access, p_scan ); /* DVB-S */
481 msg_Err( p_access, "Frontend type not supported for scanning" );
486 /*****************************************************************************
487 * FrontendStatus : Read frontend status
488 *****************************************************************************/
489 void FrontendStatus( access_t *p_access )
491 access_sys_t *p_sys = p_access->p_sys;
492 frontend_t *p_frontend = p_sys->p_frontend;
493 char *p = p_sys->psz_frontend_info = malloc( 10000 );
494 fe_status_t i_status;
497 /* Determine type of frontend */
498 if( (i_ret = ioctl( p_sys->i_frontend_handle, FE_GET_INFO,
499 &p_frontend->info )) < 0 )
502 strerror_r( errno, buf, sizeof( buf ) );
503 p += sprintf( p, "ioctl FE_GET_INFO failed (%d) %s\n", i_ret, buf );
507 /* Print out frontend capabilities. */
508 p += sprintf( p, "<table border=1><tr><th>name</th><td>%s</td></tr>\n",
509 p_frontend->info.name );
510 switch( p_frontend->info.type )
513 p += sprintf( p, "<tr><th>type</th><td>QPSK (DVB-S)</td></tr>\n" );
516 p += sprintf( p, "<tr><th>type</th><td>QAM (DVB-C)</td></tr>\n" );
519 p += sprintf( p, "<tr><th>type</th><td>OFDM (DVB-T)</td></tr>\n" );
521 #if 0 /* DVB_API_VERSION == 3 */
523 p += sprintf( p, "<tr><th>type</th><td>MEMORY</td></tr>\n" );
526 p += sprintf( p, "<tr><th>type</th><td>NETWORK</td></tr>\n" );
530 p += sprintf( p, "<tr><th>type</th><td>UNKNOWN (%d)</td></tr>\n",
531 p_frontend->info.type );
534 #define CHECK_INFO( x ) \
536 "<tr><th>" STRINGIFY(x) "</th><td>%u</td></tr>\n", \
537 p_frontend->info.x );
539 CHECK_INFO( frequency_min );
540 CHECK_INFO( frequency_max );
541 CHECK_INFO( frequency_stepsize );
542 CHECK_INFO( frequency_tolerance );
543 CHECK_INFO( symbol_rate_min );
544 CHECK_INFO( symbol_rate_max );
545 CHECK_INFO( symbol_rate_tolerance );
546 CHECK_INFO( notifier_delay );
549 p += sprintf( p, "</table><p>Frontend capability list:\n<table border=1>" );
551 #define CHECK_CAPS( x ) \
552 if ( p_frontend->info.caps & (FE_##x) ) \
553 p += sprintf( p, "<tr><td>" STRINGIFY(x) "</td></tr>\n" );
555 CHECK_CAPS( IS_STUPID );
556 CHECK_CAPS( CAN_INVERSION_AUTO );
557 CHECK_CAPS( CAN_FEC_1_2 );
558 CHECK_CAPS( CAN_FEC_2_3 );
559 CHECK_CAPS( CAN_FEC_3_4 );
560 CHECK_CAPS( CAN_FEC_4_5 );
561 CHECK_CAPS( CAN_FEC_5_6 );
562 CHECK_CAPS( CAN_FEC_6_7 );
563 CHECK_CAPS( CAN_FEC_7_8 );
564 CHECK_CAPS( CAN_FEC_8_9 );
565 CHECK_CAPS( CAN_FEC_AUTO );
566 CHECK_CAPS( CAN_QPSK );
567 CHECK_CAPS( CAN_QAM_16 );
568 CHECK_CAPS( CAN_QAM_32 );
569 CHECK_CAPS( CAN_QAM_64 );
570 CHECK_CAPS( CAN_QAM_128 );
571 CHECK_CAPS( CAN_QAM_256 );
572 CHECK_CAPS( CAN_QAM_AUTO );
573 CHECK_CAPS( CAN_TRANSMISSION_MODE_AUTO );
574 CHECK_CAPS( CAN_BANDWIDTH_AUTO );
575 CHECK_CAPS( CAN_GUARD_INTERVAL_AUTO );
576 CHECK_CAPS( CAN_HIERARCHY_AUTO );
577 CHECK_CAPS( CAN_MUTE_TS );
578 CHECK_CAPS( CAN_RECOVER );
579 #if 0 /* Disabled because of older distributions */
580 CHECK_CAPS( CAN_CLEAN_SETUP );
584 p += sprintf( p, "</table><p>Current frontend status:\n<table border=1>" );
586 if( (i_ret = ioctl( p_sys->i_frontend_handle, FE_READ_STATUS, &i_status ))
590 strerror_r( errno, buf, sizeof( buf ) );
591 p += sprintf( p, "</table>ioctl FE_READ_STATUS failed (%d) %s\n",
596 #define CHECK_STATUS( x ) \
597 if ( i_status & (FE_##x) ) \
598 p += sprintf( p, "<tr><td>" STRINGIFY(x) "</td></tr>\n" );
600 CHECK_STATUS( HAS_SIGNAL );
601 CHECK_STATUS( HAS_CARRIER );
602 CHECK_STATUS( HAS_VITERBI );
603 CHECK_STATUS( HAS_SYNC );
604 CHECK_STATUS( HAS_LOCK );
605 CHECK_STATUS( REINIT );
607 p += sprintf( p, "<tr><td>Tuning failed</td></tr>\n" );
610 if ( i_status & FE_HAS_LOCK )
613 p += sprintf( p, "</table><p>Signal status:\n<table border=1>" );
614 if( ioctl( p_sys->i_frontend_handle, FE_READ_BER, &i_value ) >= 0 )
615 p += sprintf( p, "<tr><th>Bit error rate</th><td>%d</td></tr>\n",
617 if( ioctl( p_sys->i_frontend_handle, FE_READ_SIGNAL_STRENGTH,
619 p += sprintf( p, "<tr><th>Signal strength</th><td>%d</td></tr>\n",
621 if( ioctl( p_sys->i_frontend_handle, FE_READ_SNR, &i_value ) >= 0 )
622 p += sprintf( p, "<tr><th>SNR</th><td>%d</td></tr>\n",
625 p += sprintf( p, "</table>" );
628 vlc_mutex_lock( &p_sys->httpd_mutex );
629 p_sys->b_request_frontend_info = false;
630 vlc_cond_signal( &p_sys->httpd_cond );
631 vlc_mutex_unlock( &p_sys->httpd_mutex );
635 /*****************************************************************************
636 * FrontendInfo : Return information about given frontend
637 *****************************************************************************/
638 static int FrontendInfo( access_t *p_access )
640 access_sys_t *p_sys = p_access->p_sys;
641 frontend_t *p_frontend = p_sys->p_frontend;
644 /* Determine type of frontend */
645 if( (i_ret = ioctl( p_sys->i_frontend_handle, FE_GET_INFO,
646 &p_frontend->info )) < 0 )
648 msg_Err( p_access, "ioctl FE_GET_INFO failed (%d): %m", i_ret );
652 /* Print out frontend capabilities. */
653 msg_Dbg(p_access, "Frontend Info:" );
654 msg_Dbg(p_access, " name = %s", p_frontend->info.name );
655 switch( p_frontend->info.type )
658 msg_Dbg( p_access, " type = QPSK (DVB-S)" );
661 msg_Dbg( p_access, " type = QAM (DVB-C)" );
664 msg_Dbg( p_access, " type = OFDM (DVB-T)" );
667 msg_Dbg( p_access, " type = ATSC (USA)" );
669 #if 0 /* DVB_API_VERSION == 3 */
671 msg_Dbg(p_access, " type = MEMORY" );
674 msg_Dbg(p_access, " type = NETWORK" );
678 msg_Err( p_access, " unknown frontend type (%d)",
679 p_frontend->info.type );
682 msg_Dbg(p_access, " frequency_min = %u (kHz)",
683 p_frontend->info.frequency_min);
684 msg_Dbg(p_access, " frequency_max = %u (kHz)",
685 p_frontend->info.frequency_max);
686 msg_Dbg(p_access, " frequency_stepsize = %u",
687 p_frontend->info.frequency_stepsize);
688 msg_Dbg(p_access, " frequency_tolerance = %u",
689 p_frontend->info.frequency_tolerance);
690 msg_Dbg(p_access, " symbol_rate_min = %u (kHz)",
691 p_frontend->info.symbol_rate_min);
692 msg_Dbg(p_access, " symbol_rate_max = %u (kHz)",
693 p_frontend->info.symbol_rate_max);
694 msg_Dbg(p_access, " symbol_rate_tolerance (ppm) = %u",
695 p_frontend->info.symbol_rate_tolerance);
696 msg_Dbg(p_access, " notifier_delay (ms) = %u",
697 p_frontend->info.notifier_delay );
699 msg_Dbg(p_access, "Frontend Info capability list:");
700 if( p_frontend->info.caps & FE_IS_STUPID)
701 msg_Dbg(p_access, " no capabilities - frontend is stupid!");
702 if( p_frontend->info.caps & FE_CAN_INVERSION_AUTO)
703 msg_Dbg(p_access, " inversion auto");
704 if( p_frontend->info.caps & FE_CAN_FEC_1_2)
705 msg_Dbg(p_access, " forward error correction 1/2");
706 if( p_frontend->info.caps & FE_CAN_FEC_2_3)
707 msg_Dbg(p_access, " forward error correction 2/3");
708 if( p_frontend->info.caps & FE_CAN_FEC_3_4)
709 msg_Dbg(p_access, " forward error correction 3/4");
710 if( p_frontend->info.caps & FE_CAN_FEC_4_5)
711 msg_Dbg(p_access, " forward error correction 4/5");
712 if( p_frontend->info.caps & FE_CAN_FEC_5_6)
713 msg_Dbg(p_access, " forward error correction 5/6");
714 if( p_frontend->info.caps & FE_CAN_FEC_6_7)
715 msg_Dbg(p_access, " forward error correction 6/7");
716 if( p_frontend->info.caps & FE_CAN_FEC_7_8)
717 msg_Dbg(p_access, " forward error correction 7/8");
718 if( p_frontend->info.caps & FE_CAN_FEC_8_9)
719 msg_Dbg(p_access, " forward error correction 8/9");
720 if( p_frontend->info.caps & FE_CAN_FEC_AUTO)
721 msg_Dbg(p_access, " forward error correction auto");
722 if( p_frontend->info.caps & FE_CAN_QPSK)
723 msg_Dbg(p_access, " card can do QPSK");
724 if( p_frontend->info.caps & FE_CAN_QAM_16)
725 msg_Dbg(p_access, " card can do QAM 16");
726 if( p_frontend->info.caps & FE_CAN_QAM_32)
727 msg_Dbg(p_access, " card can do QAM 32");
728 if( p_frontend->info.caps & FE_CAN_QAM_64)
729 msg_Dbg(p_access, " card can do QAM 64");
730 if( p_frontend->info.caps & FE_CAN_QAM_128)
731 msg_Dbg(p_access, " card can do QAM 128");
732 if( p_frontend->info.caps & FE_CAN_QAM_256)
733 msg_Dbg(p_access, " card can do QAM 256");
734 if( p_frontend->info.caps & FE_CAN_QAM_AUTO)
735 msg_Dbg(p_access, " card can do QAM auto");
736 if( p_frontend->info.caps & FE_CAN_TRANSMISSION_MODE_AUTO)
737 msg_Dbg(p_access, " transmission mode auto");
738 if( p_frontend->info.caps & FE_CAN_BANDWIDTH_AUTO)
739 msg_Dbg(p_access, " bandwidth mode auto");
740 if( p_frontend->info.caps & FE_CAN_GUARD_INTERVAL_AUTO)
741 msg_Dbg(p_access, " guard interval mode auto");
742 if( p_frontend->info.caps & FE_CAN_HIERARCHY_AUTO)
743 msg_Dbg(p_access, " hierarchy mode auto");
744 if( p_frontend->info.caps & FE_CAN_MUTE_TS)
745 msg_Dbg(p_access, " card can mute TS");
746 if( p_frontend->info.caps & FE_CAN_RECOVER)
747 msg_Dbg(p_access, " card can recover from a cable unplug");
748 if( p_frontend->info.caps & FE_CAN_8VSB)
749 msg_Dbg(p_access, " card can do 8vsb");
750 if( p_frontend->info.caps & FE_CAN_16VSB)
751 msg_Dbg(p_access, " card can do 16vsb");
752 msg_Dbg(p_access, "End of capability list");
757 /*****************************************************************************
758 * Decoding the DVB parameters (common)
759 *****************************************************************************/
760 static fe_spectral_inversion_t DecodeInversion( access_t *p_access )
763 fe_spectral_inversion_t fe_inversion = 0;
765 i_val = var_GetInteger( p_access, "dvb-inversion" );
766 msg_Dbg( p_access, "using inversion=%d", i_val );
770 case 0: fe_inversion = INVERSION_OFF; break;
771 case 1: fe_inversion = INVERSION_ON; break;
772 case 2: fe_inversion = INVERSION_AUTO; break;
774 msg_Dbg( p_access, "dvb has inversion not set, using auto");
775 fe_inversion = INVERSION_AUTO;
781 static fe_code_rate_t DecodeFEC( access_t *p_access, int i_val )
783 fe_code_rate_t fe_fec = FEC_NONE;
785 msg_Dbg( p_access, "using fec=%d", i_val );
789 case 0: fe_fec = FEC_NONE; break;
790 case 1: fe_fec = FEC_1_2; break;
791 case 2: fe_fec = FEC_2_3; break;
792 case 3: fe_fec = FEC_3_4; break;
793 case 4: fe_fec = FEC_4_5; break;
794 case 5: fe_fec = FEC_5_6; break;
795 case 6: fe_fec = FEC_6_7; break;
796 case 7: fe_fec = FEC_7_8; break;
797 case 8: fe_fec = FEC_8_9; break;
798 case 9: fe_fec = FEC_AUTO; break;
802 msg_Err( p_access, "argument has invalid FEC (%d)", i_val);
808 static fe_modulation_t DecodeModulationQAM( access_t *p_access )
810 switch( var_GetInteger( p_access, "dvb-modulation" ) )
812 case 0: return QAM_AUTO;
813 case 16: return QAM_16;
814 case 32: return QAM_32;
815 case 64: return QAM_64;
816 case 128: return QAM_128;
817 case 256: return QAM_256;
819 msg_Dbg( p_access, "QAM modulation not set, using auto");
823 static fe_modulation_t DecodeModulationOFDM( access_t *p_access )
825 switch( var_GetInteger( p_access, "dvb-modulation" ) )
827 case -1: return QPSK;
828 case 0: return QAM_AUTO;
829 case 16: return QAM_16;
830 case 32: return QAM_32;
831 case 64: return QAM_64;
832 case 128: return QAM_128;
833 case 256: return QAM_256;
835 msg_Dbg( p_access, "OFDM modulation not set, using QAM auto");
840 static fe_modulation_t DecodeModulationATSC( access_t *p_access )
842 switch( var_GetInteger( p_access, "dvb-modulation" ) )
844 case 0: return QAM_AUTO;
845 case 8: return VSB_8;
846 case 16: return VSB_16;
847 case 32: return QAM_32;
848 case 64: return QAM_64;
849 case 128: return QAM_128;
850 case 256: return QAM_256;
852 msg_Dbg( p_access, "ATSC modulation not set, using VSB 8");
857 /*****************************************************************************
858 * FrontendSetQPSK : controls the FE device
859 *****************************************************************************/
860 static fe_sec_voltage_t DecodeVoltage( access_t *p_access )
863 fe_sec_voltage_t fe_voltage;
865 i_val = var_GetInteger( p_access, "dvb-voltage" );
866 msg_Dbg( p_access, "using voltage=%d", i_val );
870 case 0: fe_voltage = SEC_VOLTAGE_OFF; break;
871 case 13: fe_voltage = SEC_VOLTAGE_13; break;
872 case 18: fe_voltage = SEC_VOLTAGE_18; break;
874 fe_voltage = SEC_VOLTAGE_OFF;
875 msg_Err( p_access, "argument has invalid voltage (%d)", i_val );
881 static fe_sec_tone_mode_t DecodeTone( access_t *p_access )
884 fe_sec_tone_mode_t fe_tone;
886 i_val = var_GetInteger( p_access, "dvb-tone" );
887 msg_Dbg( p_access, "using tone=%d", i_val );
891 case 0: fe_tone = SEC_TONE_OFF; break;
892 case 1: fe_tone = SEC_TONE_ON; break;
894 fe_tone = SEC_TONE_OFF;
895 msg_Err( p_access, "argument has invalid tone mode (%d)", i_val );
903 struct dvb_diseqc_master_cmd cmd;
907 static int DoDiseqc( access_t *p_access )
909 access_sys_t *p_sys = p_access->p_sys;
912 int i_frequency, i_lnb_slof;
913 fe_sec_voltage_t fe_voltage;
914 fe_sec_tone_mode_t fe_tone;
917 i_frequency = var_GetInteger( p_access, "dvb-frequency" );
918 i_lnb_slof = var_GetInteger( p_access, "dvb-lnb-slof" );
920 i_val = var_GetInteger( p_access, "dvb-tone" );
921 if( i_val == -1 /* auto */ )
923 if( i_frequency >= i_lnb_slof )
927 var_SetInteger( p_access, "dvb-tone", i_val );
930 fe_voltage = DecodeVoltage( p_access );
931 fe_tone = DecodeTone( p_access );
933 /* Switch off continuous tone. */
934 if( (i_err = ioctl( p_sys->i_frontend_handle, FE_SET_TONE, SEC_TONE_OFF )) < 0 )
936 msg_Err( p_access, "ioctl FE_SET_TONE failed, tone=%s (%d) %m",
937 fe_tone == SEC_TONE_ON ? "on" : "off", i_err );
941 /* Configure LNB voltage. */
942 if( (i_err = ioctl( p_sys->i_frontend_handle, FE_SET_VOLTAGE, fe_voltage )) < 0 )
944 msg_Err( p_access, "ioctl FE_SET_VOLTAGE failed, voltage=%d (%d) %m",
949 b_val = var_GetBool( p_access, "dvb-high-voltage" );
950 if( (i_err = ioctl( p_sys->i_frontend_handle, FE_ENABLE_HIGH_LNB_VOLTAGE,
951 b_val )) < 0 && b_val )
954 "ioctl FE_ENABLE_HIGH_LNB_VOLTAGE failed, val=%d (%d) %m",
958 /* Wait for at least 15 ms. */
961 i_val = var_GetInteger( p_access, "dvb-satno" );
962 if( i_val > 0 && i_val < 5 )
964 /* digital satellite equipment control,
965 * specification is available from http://www.eutelsat.com/
968 /* 1.x compatible equipment */
969 struct diseqc_cmd_t cmd = { {{0xe0, 0x10, 0x38, 0xf0, 0x00, 0x00}, 4}, 0 };
971 /* param: high nibble: reset bits, low nibble set bits,
972 * bits are: option, position, polarization, band
974 cmd.cmd.msg[3] = 0xf0 /* reset bits */
975 | (((i_val - 1) * 4) & 0xc)
976 | (fe_voltage == SEC_VOLTAGE_13 ? 0 : 2)
977 | (fe_tone == SEC_TONE_ON ? 1 : 0);
979 if( (i_err = ioctl( p_sys->i_frontend_handle, FE_DISEQC_SEND_MASTER_CMD,
982 msg_Err( p_access, "ioctl FE_SEND_MASTER_CMD failed (%d) %m",
987 msleep(15000 + cmd.wait * 1000);
989 /* A or B simple diseqc ("diseqc-compatible") */
990 if( (i_err = ioctl( p_sys->i_frontend_handle, FE_DISEQC_SEND_BURST,
991 ((i_val - 1) % 2) ? SEC_MINI_B : SEC_MINI_A )) < 0 )
993 msg_Err( p_access, "ioctl FE_SEND_BURST failed (%d) %m",
1001 if( (i_err = ioctl( p_sys->i_frontend_handle, FE_SET_TONE, fe_tone )) < 0 )
1003 msg_Err( p_access, "ioctl FE_SET_TONE failed, tone=%s (%d) %m",
1004 fe_tone == SEC_TONE_ON ? "on" : "off", i_err );
1012 static int FrontendSetQPSK( access_t *p_access )
1014 access_sys_t *p_sys = p_access->p_sys;
1015 struct dvb_frontend_parameters fep;
1018 int i_frequency, i_lnb_slof = 0, i_lnb_lof1, i_lnb_lof2 = 0;
1020 /* Prepare the fep structure */
1021 i_frequency = var_GetInteger( p_access, "dvb-frequency" );
1023 i_val = var_GetInteger( p_access, "dvb-lnb-lof1" );
1026 /* Automatic mode. */
1027 if ( i_frequency >= 950000 && i_frequency <= 2150000 )
1029 msg_Dbg( p_access, "frequency %d is in IF-band", i_frequency );
1032 else if ( i_frequency >= 2500000 && i_frequency <= 2700000 )
1034 msg_Dbg( p_access, "frequency %d is in S-band", i_frequency );
1035 i_lnb_lof1 = 3650000;
1037 else if ( i_frequency >= 3400000 && i_frequency <= 4200000 )
1039 msg_Dbg( p_access, "frequency %d is in C-band (lower)",
1041 i_lnb_lof1 = 5150000;
1043 else if ( i_frequency >= 4500000 && i_frequency <= 4800000 )
1045 msg_Dbg( p_access, "frequency %d is in C-band (higher)",
1047 i_lnb_lof1 = 5950000;
1049 else if ( i_frequency >= 10700000 && i_frequency <= 13250000 )
1051 msg_Dbg( p_access, "frequency %d is in Ku-band",
1053 i_lnb_lof1 = 9750000;
1054 i_lnb_lof2 = 10600000;
1055 i_lnb_slof = 11700000;
1059 msg_Err( p_access, "frequency %d is out of any known band",
1061 msg_Err( p_access, "specify dvb-lnb-lof1 manually for the local "
1062 "oscillator frequency" );
1063 return VLC_EGENERIC;
1065 var_SetInteger( p_access, "dvb-lnb-lof1", i_lnb_lof1 );
1066 var_SetInteger( p_access, "dvb-lnb-lof2", i_lnb_lof2 );
1067 var_SetInteger( p_access, "dvb-lnb-slof", i_lnb_slof );
1072 i_lnb_lof2 = var_GetInteger( p_access, "dvb-lnb-lof2" );
1073 i_lnb_slof = var_GetInteger( p_access, "dvb-lnb-slof" );
1076 if( i_lnb_slof && i_frequency >= i_lnb_slof )
1078 i_frequency -= i_lnb_lof2;
1082 i_frequency -= i_lnb_lof1;
1084 fep.frequency = i_frequency >= 0 ? i_frequency : -i_frequency;
1086 fep.inversion = DecodeInversion( p_access );
1088 fep.u.qpsk.symbol_rate = var_GetInteger( p_access, "dvb-srate" );
1090 fep.u.qpsk.fec_inner = DecodeFEC( p_access, var_GetInteger( p_access, "dvb-fec" ) );
1092 if( DoDiseqc( p_access ) < 0 )
1094 return VLC_EGENERIC;
1097 /* Empty the event queue */
1100 struct dvb_frontend_event event;
1101 if ( ioctl( p_sys->i_frontend_handle, FE_GET_EVENT, &event ) < 0
1102 && errno == EWOULDBLOCK )
1106 /* Now send it all to the frontend device */
1107 if( (i_ret = ioctl( p_sys->i_frontend_handle, FE_SET_FRONTEND, &fep )) < 0 )
1109 msg_Err( p_access, "DVB-S: setting frontend failed (%d) %m", i_ret );
1110 return VLC_EGENERIC;
1116 /*****************************************************************************
1117 * FrontendSetQAM : controls the FE device
1118 *****************************************************************************/
1119 static int FrontendSetQAM( access_t *p_access )
1121 access_sys_t *p_sys = p_access->p_sys;
1122 frontend_t *p_frontend = p_sys->p_frontend;
1123 struct dvb_frontend_parameters fep;
1127 /* Prepare the fep structure */
1129 fep.frequency = var_GetInteger( p_access, "dvb-frequency" );
1131 fep.inversion = DecodeInversion( p_access );
1133 /* Default symbol-rate is for dvb-s, and doesn't fit
1134 * for dvb-c, so if it's over the limit of frontend, default to
1135 * somewhat common value
1137 i_val = var_GetInteger( p_access, "dvb-srate" );
1138 if( i_val < p_frontend->info.symbol_rate_max &&
1139 i_val > p_frontend->info.symbol_rate_min )
1140 fep.u.qam.symbol_rate = i_val;
1142 fep.u.qam.symbol_rate = 6875000;
1144 fep.u.qam.fec_inner = DecodeFEC( p_access, var_GetInteger( p_access,
1147 fep.u.qam.modulation = DecodeModulationQAM( p_access );
1149 /* Empty the event queue */
1152 struct dvb_frontend_event event;
1153 if ( ioctl( p_sys->i_frontend_handle, FE_GET_EVENT, &event ) < 0
1154 && errno == EWOULDBLOCK )
1158 /* Now send it all to the frontend device */
1159 if( (i_ret = ioctl( p_sys->i_frontend_handle, FE_SET_FRONTEND, &fep )) < 0 )
1161 msg_Err( p_access, "DVB-C: setting frontend failed (%d): %m", i_ret );
1162 return VLC_EGENERIC;
1168 /*****************************************************************************
1169 * FrontendSetOFDM : controls the FE device
1170 *****************************************************************************/
1171 static fe_bandwidth_t DecodeBandwidth( access_t *p_access )
1173 fe_bandwidth_t fe_bandwidth = 0;
1174 int i_bandwith = var_GetInteger( p_access, "dvb-bandwidth" );
1176 msg_Dbg( p_access, "using bandwidth=%d", i_bandwith );
1178 switch( i_bandwith )
1180 case 0: fe_bandwidth = BANDWIDTH_AUTO; break;
1181 case 6: fe_bandwidth = BANDWIDTH_6_MHZ; break;
1182 case 7: fe_bandwidth = BANDWIDTH_7_MHZ; break;
1183 case 8: fe_bandwidth = BANDWIDTH_8_MHZ; break;
1185 msg_Dbg( p_access, "terrestrial dvb has bandwidth not set, using auto" );
1186 fe_bandwidth = BANDWIDTH_AUTO;
1189 return fe_bandwidth;
1192 static fe_transmit_mode_t DecodeTransmission( access_t *p_access )
1194 fe_transmit_mode_t fe_transmission = 0;
1195 int i_transmission = var_GetInteger( p_access, "dvb-transmission" );
1197 msg_Dbg( p_access, "using transmission=%d", i_transmission );
1199 switch( i_transmission )
1201 case 0: fe_transmission = TRANSMISSION_MODE_AUTO; break;
1202 case 2: fe_transmission = TRANSMISSION_MODE_2K; break;
1203 case 8: fe_transmission = TRANSMISSION_MODE_8K; break;
1205 msg_Dbg( p_access, "terrestrial dvb has transmission mode not set, using auto");
1206 fe_transmission = TRANSMISSION_MODE_AUTO;
1209 return fe_transmission;
1212 static fe_guard_interval_t DecodeGuardInterval( access_t *p_access )
1214 fe_guard_interval_t fe_guard = 0;
1215 int i_guard = var_GetInteger( p_access, "dvb-guard" );
1217 msg_Dbg( p_access, "using guard=%d", i_guard );
1221 case 0: fe_guard = GUARD_INTERVAL_AUTO; break;
1222 case 4: fe_guard = GUARD_INTERVAL_1_4; break;
1223 case 8: fe_guard = GUARD_INTERVAL_1_8; break;
1224 case 16: fe_guard = GUARD_INTERVAL_1_16; break;
1225 case 32: fe_guard = GUARD_INTERVAL_1_32; break;
1227 msg_Dbg( p_access, "terrestrial dvb has guard interval not set, using auto");
1228 fe_guard = GUARD_INTERVAL_AUTO;
1234 static fe_hierarchy_t DecodeHierarchy( access_t *p_access )
1236 fe_hierarchy_t fe_hierarchy = 0;
1237 int i_hierarchy = var_GetInteger( p_access, "dvb-hierarchy" );
1239 msg_Dbg( p_access, "using hierarchy=%d", i_hierarchy );
1241 switch( i_hierarchy )
1243 case -1: fe_hierarchy = HIERARCHY_NONE; break;
1244 case 0: fe_hierarchy = HIERARCHY_AUTO; break;
1245 case 1: fe_hierarchy = HIERARCHY_1; break;
1246 case 2: fe_hierarchy = HIERARCHY_2; break;
1247 case 4: fe_hierarchy = HIERARCHY_4; break;
1249 msg_Dbg( p_access, "terrestrial dvb has hierarchy not set, using auto");
1250 fe_hierarchy = HIERARCHY_AUTO;
1253 return fe_hierarchy;
1256 static int FrontendSetOFDM( access_t * p_access )
1258 access_sys_t *p_sys = p_access->p_sys;
1259 struct dvb_frontend_parameters fep;
1262 /* Prepare the fep structure */
1264 fep.frequency = var_GetInteger( p_access, "dvb-frequency" );
1266 fep.inversion = DecodeInversion( p_access );
1268 fep.u.ofdm.bandwidth = DecodeBandwidth( p_access );
1269 fep.u.ofdm.code_rate_HP = DecodeFEC( p_access, var_GetInteger( p_access,
1270 "dvb-code-rate-hp" ) );
1271 fep.u.ofdm.code_rate_LP = DecodeFEC( p_access, var_GetInteger( p_access,
1272 "dvb-code-rate-lp" ) );
1273 fep.u.ofdm.constellation = DecodeModulationOFDM( p_access );
1274 fep.u.ofdm.transmission_mode = DecodeTransmission( p_access );
1275 fep.u.ofdm.guard_interval = DecodeGuardInterval( p_access );
1276 fep.u.ofdm.hierarchy_information = DecodeHierarchy( p_access );
1278 /* Empty the event queue */
1281 struct dvb_frontend_event event;
1282 if ( ioctl( p_sys->i_frontend_handle, FE_GET_EVENT, &event ) < 0
1283 && errno == EWOULDBLOCK )
1287 /* Now send it all to the frontend device */
1288 if( (ret = ioctl( p_sys->i_frontend_handle, FE_SET_FRONTEND, &fep )) < 0 )
1290 msg_Err( p_access, "DVB-T: setting frontend failed (%d): %m", ret );
1297 /*****************************************************************************
1298 * FrontendSetATSC : controls the FE device
1299 *****************************************************************************/
1300 static int FrontendSetATSC( access_t *p_access )
1302 access_sys_t *p_sys = p_access->p_sys;
1303 struct dvb_frontend_parameters fep;
1306 /* Prepare the fep structure */
1308 fep.frequency = var_GetInteger( p_access, "dvb-frequency" );
1310 fep.u.vsb.modulation = DecodeModulationATSC( p_access );
1312 /* Empty the event queue */
1315 struct dvb_frontend_event event;
1316 if ( ioctl( p_sys->i_frontend_handle, FE_GET_EVENT, &event ) < 0
1317 && errno == EWOULDBLOCK )
1321 /* Now send it all to the frontend device */
1322 if( (i_ret = ioctl( p_sys->i_frontend_handle, FE_SET_FRONTEND, &fep )) < 0 )
1324 msg_Err( p_access, "ATSC: setting frontend failed (%d): %m", i_ret );
1325 return VLC_EGENERIC;
1336 /*****************************************************************************
1337 * DMXSetFilter : controls the demux to add a filter
1338 *****************************************************************************/
1339 int DMXSetFilter( access_t * p_access, int i_pid, int * pi_fd, int i_type )
1341 struct dmx_pes_filter_params s_filter_params;
1343 unsigned int i_adapter, i_device;
1346 i_adapter = var_GetInteger( p_access, "dvb-adapter" );
1347 i_device = var_GetInteger( p_access, "dvb-device" );
1349 if( snprintf( dmx, sizeof(dmx), DMX, i_adapter, i_device )
1350 >= (int)sizeof(dmx) )
1352 msg_Err( p_access, "snprintf() truncated string for DMX" );
1353 dmx[sizeof(dmx) - 1] = '\0';
1356 msg_Dbg( p_access, "Opening device %s", dmx );
1357 if( (*pi_fd = vlc_open(dmx, O_RDWR)) < 0 )
1359 msg_Err( p_access, "DMXSetFilter: opening device failed (%m)" );
1360 return VLC_EGENERIC;
1363 /* We fill the DEMUX structure : */
1364 s_filter_params.pid = i_pid;
1365 s_filter_params.input = DMX_IN_FRONTEND;
1366 s_filter_params.output = DMX_OUT_TS_TAP;
1367 s_filter_params.flags = DMX_IMMEDIATE_START;
1370 { /* First device */
1372 msg_Dbg(p_access, "DMXSetFilter: DMX_PES_VIDEO0 for PID %d", i_pid);
1373 s_filter_params.pes_type = DMX_PES_VIDEO0;
1376 msg_Dbg(p_access, "DMXSetFilter: DMX_PES_AUDIO0 for PID %d", i_pid);
1377 s_filter_params.pes_type = DMX_PES_AUDIO0;
1380 msg_Dbg(p_access, "DMXSetFilter: DMX_PES_TELETEXT0 for PID %d", i_pid);
1381 s_filter_params.pes_type = DMX_PES_TELETEXT0;
1384 msg_Dbg(p_access, "DMXSetFilter: DMX_PES_SUBTITLE0 for PID %d", i_pid);
1385 s_filter_params.pes_type = DMX_PES_SUBTITLE0;
1388 msg_Dbg(p_access, "DMXSetFilter: DMX_PES_PCR0 for PID %d", i_pid);
1389 s_filter_params.pes_type = DMX_PES_PCR0;
1393 msg_Dbg(p_access, "DMXSetFilter: DMX_PES_VIDEO1 for PID %d", i_pid);
1394 s_filter_params.pes_type = DMX_PES_VIDEO1;
1397 msg_Dbg(p_access, "DMXSetFilter: DMX_PES_AUDIO1 for PID %d", i_pid);
1398 s_filter_params.pes_type = DMX_PES_AUDIO1;
1401 msg_Dbg(p_access, "DMXSetFilter: DMX_PES_TELETEXT1 for PID %d", i_pid);
1402 s_filter_params.pes_type = DMX_PES_TELETEXT1;
1405 msg_Dbg(p_access, "DMXSetFilter: DMX_PES_SUBTITLE1 for PID %d", i_pid);
1406 s_filter_params.pes_type = DMX_PES_SUBTITLE1;
1409 msg_Dbg(p_access, "DMXSetFilter: DMX_PES_PCR1 for PID %d", i_pid);
1410 s_filter_params.pes_type = DMX_PES_PCR1;
1414 msg_Dbg(p_access, "DMXSetFilter: DMX_PES_VIDEO2 for PID %d", i_pid);
1415 s_filter_params.pes_type = DMX_PES_VIDEO2;
1418 msg_Dbg(p_access, "DMXSetFilter: DMX_PES_AUDIO2 for PID %d", i_pid);
1419 s_filter_params.pes_type = DMX_PES_AUDIO2;
1422 msg_Dbg(p_access, "DMXSetFilter: DMX_PES_TELETEXT2 for PID %d", i_pid);
1423 s_filter_params.pes_type = DMX_PES_TELETEXT2;
1426 msg_Dbg(p_access, "DMXSetFilter: DMX_PES_SUBTITLE2 for PID %d", i_pid);
1427 s_filter_params.pes_type = DMX_PES_SUBTITLE2;
1430 msg_Dbg(p_access, "DMXSetFilter: DMX_PES_PCR2 for PID %d", i_pid);
1431 s_filter_params.pes_type = DMX_PES_PCR2;
1435 msg_Dbg(p_access, "DMXSetFilter: DMX_PES_VIDEO3 for PID %d", i_pid);
1436 s_filter_params.pes_type = DMX_PES_VIDEO3;
1439 msg_Dbg(p_access, "DMXSetFilter: DMX_PES_AUDIO3 for PID %d", i_pid);
1440 s_filter_params.pes_type = DMX_PES_AUDIO3;
1443 msg_Dbg(p_access, "DMXSetFilter: DMX_PES_TELETEXT3 for PID %d", i_pid);
1444 s_filter_params.pes_type = DMX_PES_TELETEXT3;
1447 msg_Dbg(p_access, "DMXSetFilter: DMX_PES_SUBTITLE3 for PID %d", i_pid);
1448 s_filter_params.pes_type = DMX_PES_SUBTITLE3;
1451 msg_Dbg(p_access, "DMXSetFilter: DMX_PES_PCR3 for PID %d", i_pid);
1452 s_filter_params.pes_type = DMX_PES_PCR3;
1454 /* Usually used by Nova cards */
1457 msg_Dbg(p_access, "DMXSetFilter: DMX_PES_OTHER for PID %d", i_pid);
1458 s_filter_params.pes_type = DMX_PES_OTHER;
1462 /* We then give the order to the device : */
1463 if( (i_ret = ioctl( *pi_fd, DMX_SET_PES_FILTER, &s_filter_params )) < 0 )
1465 msg_Err( p_access, "DMXSetFilter: failed with %d (%m)", i_ret );
1466 return VLC_EGENERIC;
1471 /*****************************************************************************
1472 * DMXUnsetFilter : removes a filter
1473 *****************************************************************************/
1474 int DMXUnsetFilter( access_t * p_access, int i_fd )
1478 if( (i_ret = ioctl( i_fd, DMX_STOP )) < 0 )
1480 msg_Err( p_access, "DMX_STOP failed for demux (%d): %m", i_ret );
1484 msg_Dbg( p_access, "DMXUnsetFilter: closing demux %d", i_fd );
1494 /*****************************************************************************
1496 *****************************************************************************/
1497 int DVROpen( access_t * p_access )
1499 access_sys_t *p_sys = p_access->p_sys;
1500 unsigned int i_adapter, i_device;
1503 i_adapter = var_GetInteger( p_access, "dvb-adapter" );
1504 i_device = var_GetInteger( p_access, "dvb-device" );
1506 if( snprintf( dvr, sizeof(dvr), DVR, i_adapter, i_device )
1507 >= (int)sizeof(dvr) )
1509 msg_Err( p_access, "snprintf() truncated string for DVR" );
1510 dvr[sizeof(dvr) - 1] = '\0';
1513 msg_Dbg( p_access, "Opening device %s", dvr );
1514 if( (p_sys->i_handle = vlc_open(dvr, O_RDONLY)) < 0 )
1516 msg_Err( p_access, "DVROpen: opening device failed (%m)" );
1517 return VLC_EGENERIC;
1520 if( fcntl( p_sys->i_handle, F_SETFL, O_NONBLOCK ) == -1 )
1522 msg_Warn( p_access, "DVROpen: couldn't set non-blocking mode (%m)" );
1528 /*****************************************************************************
1530 *****************************************************************************/
1531 void DVRClose( access_t * p_access )
1533 access_sys_t *p_sys = p_access->p_sys;
1535 close( p_sys->i_handle );
1543 /*****************************************************************************
1545 *****************************************************************************/
1546 int CAMOpen( access_t *p_access )
1548 access_sys_t *p_sys = p_access->p_sys;
1550 int i_adapter, i_device;
1553 i_adapter = var_GetInteger( p_access, "dvb-adapter" );
1554 i_device = var_GetInteger( p_access, "dvb-device" );
1556 if( snprintf( ca, sizeof(ca), CA, i_adapter, i_device ) >= (int)sizeof(ca) )
1558 msg_Err( p_access, "snprintf() truncated string for CA" );
1559 ca[sizeof(ca) - 1] = '\0';
1561 memset( &caps, 0, sizeof( ca_caps_t ));
1563 msg_Dbg( p_access, "Opening device %s", ca );
1564 if( (p_sys->i_ca_handle = vlc_open(ca, O_RDWR | O_NONBLOCK)) < 0 )
1566 msg_Warn( p_access, "CAMInit: opening CAM device failed (%m)" );
1567 p_sys->i_ca_handle = 0;
1568 return VLC_EGENERIC;
1571 if ( ioctl( p_sys->i_ca_handle, CA_GET_CAP, &caps ) != 0 )
1573 msg_Err( p_access, "CAMInit: ioctl() error getting CAM capabilities" );
1574 close( p_sys->i_ca_handle );
1575 p_sys->i_ca_handle = 0;
1576 return VLC_EGENERIC;
1579 /* Output CA capabilities */
1580 msg_Dbg( p_access, "CAMInit: CA interface with %d %s", caps.slot_num,
1581 caps.slot_num == 1 ? "slot" : "slots" );
1582 if ( caps.slot_type & CA_CI )
1583 msg_Dbg( p_access, "CAMInit: CI high level interface type" );
1584 if ( caps.slot_type & CA_CI_LINK )
1585 msg_Dbg( p_access, "CAMInit: CI link layer level interface type" );
1586 if ( caps.slot_type & CA_CI_PHYS )
1587 msg_Dbg( p_access, "CAMInit: CI physical layer level interface type (not supported) " );
1588 if ( caps.slot_type & CA_DESCR )
1589 msg_Dbg( p_access, "CAMInit: built-in descrambler detected" );
1590 if ( caps.slot_type & CA_SC )
1591 msg_Dbg( p_access, "CAMInit: simple smart card interface" );
1593 msg_Dbg( p_access, "CAMInit: %d available %s", caps.descr_num,
1594 caps.descr_num == 1 ? "descrambler (key)" : "descramblers (keys)" );
1595 if ( caps.descr_type & CA_ECD )
1596 msg_Dbg( p_access, "CAMInit: ECD scrambling system supported" );
1597 if ( caps.descr_type & CA_NDS )
1598 msg_Dbg( p_access, "CAMInit: NDS scrambling system supported" );
1599 if ( caps.descr_type & CA_DSS )
1600 msg_Dbg( p_access, "CAMInit: DSS scrambling system supported" );
1602 if ( caps.slot_num == 0 )
1604 msg_Err( p_access, "CAMInit: CAM module with no slots" );
1605 close( p_sys->i_ca_handle );
1606 p_sys->i_ca_handle = 0;
1607 return VLC_EGENERIC;
1610 if( caps.slot_type & CA_CI_LINK )
1612 p_sys->i_ca_type = CA_CI_LINK;
1614 else if( caps.slot_type & CA_CI )
1616 p_sys->i_ca_type = CA_CI;
1620 p_sys->i_ca_type = -1;
1621 msg_Err( p_access, "CAMInit: incompatible CAM interface" );
1622 close( p_sys->i_ca_handle );
1623 p_sys->i_ca_handle = 0;
1624 return VLC_EGENERIC;
1627 p_sys->i_nb_slots = caps.slot_num;
1628 memset( p_sys->pb_active_slot, 0, sizeof(bool) * MAX_CI_SLOTS );
1629 memset( p_sys->pb_slot_mmi_expected, 0, sizeof(bool) * MAX_CI_SLOTS );
1630 memset( p_sys->pb_slot_mmi_undisplayed, 0,
1631 sizeof(bool) * MAX_CI_SLOTS );
1633 return en50221_Init( p_access );
1636 /*****************************************************************************
1638 *****************************************************************************/
1639 int CAMPoll( access_t * p_access )
1641 access_sys_t *p_sys = p_access->p_sys;
1642 int i_ret = VLC_EGENERIC;
1644 if ( p_sys->i_ca_handle == 0 )
1646 return VLC_EGENERIC;
1649 switch( p_sys->i_ca_type )
1652 i_ret = en50221_Poll( p_access );
1655 i_ret = VLC_SUCCESS;
1658 msg_Err( p_access, "CAMPoll: This should not happen" );
1666 /*****************************************************************************
1668 *****************************************************************************/
1669 void CAMStatus( access_t * p_access )
1671 access_sys_t *p_sys = p_access->p_sys;
1676 if ( p_sys->psz_request != NULL && *p_sys->psz_request )
1678 /* Check if we have an undisplayed MMI message : in that case we ignore
1679 * the user input to avoid confusing the CAM. */
1680 for ( i_slot = 0; i_slot < p_sys->i_nb_slots; i_slot++ )
1682 if ( p_sys->pb_slot_mmi_undisplayed[i_slot] == true )
1684 p_sys->psz_request = NULL;
1686 "ignoring user request because of a new MMI object" );
1692 if ( p_sys->psz_request != NULL && *p_sys->psz_request )
1694 /* We have a mission to accomplish. */
1695 en50221_mmi_object_t mmi_object;
1696 char *psz_request = p_sys->psz_request;
1697 char psz_value[255];
1701 p_sys->psz_request = NULL;
1703 if ( HTTPExtractValue( psz_request, "slot", psz_value,
1704 sizeof(psz_value) ) == NULL )
1706 p_sys->psz_mmi_info = strdup( "invalid request parameter\n" );
1709 i_slot = atoi(psz_value);
1711 if ( HTTPExtractValue( psz_request, "open", psz_value,
1712 sizeof(psz_value) ) != NULL )
1714 en50221_OpenMMI( p_access, i_slot );
1718 if ( HTTPExtractValue( psz_request, "close", psz_value,
1719 sizeof(psz_value) ) != NULL )
1721 en50221_CloseMMI( p_access, i_slot );
1725 if ( HTTPExtractValue( psz_request, "cancel", psz_value,
1726 sizeof(psz_value) ) == NULL )
1731 if ( HTTPExtractValue( psz_request, "type", psz_value,
1732 sizeof(psz_value) ) == NULL )
1734 p_sys->psz_mmi_info = strdup( "invalid request parameter\n" );
1738 if ( !strcmp( psz_value, "enq" ) )
1740 mmi_object.i_object_type = EN50221_MMI_ANSW;
1741 mmi_object.u.answ.b_ok = b_ok;
1742 if ( b_ok == false )
1744 mmi_object.u.answ.psz_answ = strdup("");
1748 if ( HTTPExtractValue( psz_request, "answ", psz_value,
1749 sizeof(psz_value) ) == NULL )
1751 p_sys->psz_mmi_info = strdup( "invalid request parameter\n" );
1755 mmi_object.u.answ.psz_answ = strdup(psz_value);
1760 mmi_object.i_object_type = EN50221_MMI_MENU_ANSW;
1761 if ( b_ok == false )
1763 mmi_object.u.menu_answ.i_choice = 0;
1767 if ( HTTPExtractValue( psz_request, "choice", psz_value,
1768 sizeof(psz_value) ) == NULL )
1769 mmi_object.u.menu_answ.i_choice = 0;
1771 mmi_object.u.menu_answ.i_choice = atoi(psz_value);
1775 en50221_SendMMIObject( p_access, i_slot, &mmi_object );
1779 /* Check that we have all necessary MMI information. */
1780 for ( i_slot = 0; i_slot < p_sys->i_nb_slots; i_slot++ )
1782 if ( p_sys->pb_slot_mmi_expected[i_slot] == true )
1786 p = p_sys->psz_mmi_info = malloc( 10000 );
1788 if ( ioctl( p_sys->i_ca_handle, CA_GET_CAP, &caps ) != 0 )
1791 strerror_r( errno, buf, sizeof( buf ) );
1792 p += sprintf( p, "ioctl CA_GET_CAP failed (%s)\n", buf );
1796 /* Output CA capabilities */
1797 p += sprintf( p, "CA interface with %d %s, type:\n<table>", caps.slot_num,
1798 caps.slot_num == 1 ? "slot" : "slots" );
1799 #define CHECK_CAPS( x, s ) \
1800 if ( caps.slot_type & (CA_##x) ) \
1801 p += sprintf( p, "<tr><td>" s "</td></tr>\n" );
1803 CHECK_CAPS( CI, "CI high level interface" );
1804 CHECK_CAPS( CI_LINK, "CI link layer level interface" );
1805 CHECK_CAPS( CI_PHYS, "CI physical layer level interface (not supported)" );
1806 CHECK_CAPS( DESCR, "built-in descrambler" );
1807 CHECK_CAPS( SC, "simple smartcard interface" );
1810 p += sprintf( p, "</table>%d available %s\n<table>", caps.descr_num,
1811 caps.descr_num == 1 ? "descrambler (key)" : "descramblers (keys)" );
1812 #define CHECK_DESC( x ) \
1813 if ( caps.descr_type & (CA_##x) ) \
1814 p += sprintf( p, "<tr><td>" STRINGIFY(x) "</td></tr>\n" );
1821 p += sprintf( p, "</table>" );
1823 for ( i_slot = 0; i_slot < p_sys->i_nb_slots; i_slot++ )
1825 ca_slot_info_t sinfo;
1827 p_sys->pb_slot_mmi_undisplayed[i_slot] = false;
1828 p += sprintf( p, "<p>CA slot #%d: ", i_slot );
1831 if ( ioctl( p_sys->i_ca_handle, CA_GET_SLOT_INFO, &sinfo ) != 0 )
1834 strerror_r( errno, buf, sizeof( buf ) );
1835 p += sprintf( p, "ioctl CA_GET_SLOT_INFO failed (%s)<br>\n", buf );
1839 #define CHECK_TYPE( x, s ) \
1840 if ( sinfo.type & (CA_##x) ) \
1841 p += sprintf( p, "%s", s );
1843 CHECK_TYPE( CI, "high level, " );
1844 CHECK_TYPE( CI_LINK, "link layer level, " );
1845 CHECK_TYPE( CI_PHYS, "physical layer level, " );
1848 if ( sinfo.flags & CA_CI_MODULE_READY )
1850 en50221_mmi_object_t *p_object = en50221_GetMMIObject( p_access,
1853 p += sprintf( p, "module present and ready<p>\n" );
1854 p += sprintf( p, "<form action=index.html method=get>\n" );
1855 p += sprintf( p, "<input type=hidden name=slot value=\"%d\">\n",
1858 if ( p_object == NULL )
1860 p += sprintf( p, "<input type=submit name=open value=\"Open session\">\n" );
1864 switch ( p_object->i_object_type )
1866 case EN50221_MMI_ENQ:
1867 p += sprintf( p, "<input type=hidden name=type value=enq>\n" );
1868 p += sprintf( p, "<table border=1><tr><th>%s</th></tr>\n",
1869 p_object->u.enq.psz_text );
1870 if ( p_object->u.enq.b_blind == false )
1871 p += sprintf( p, "<tr><td><input type=text name=answ></td></tr>\n" );
1873 p += sprintf( p, "<tr><td><input type=password name=answ></td></tr>\n" );
1876 case EN50221_MMI_MENU:
1877 p += sprintf( p, "<input type=hidden name=type value=menu>\n" );
1878 p += sprintf( p, "<table border=1><tr><th>%s</th></tr>\n",
1879 p_object->u.menu.psz_title );
1880 p += sprintf( p, "<tr><td>%s</td></tr><tr><td>\n",
1881 p_object->u.menu.psz_subtitle );
1882 for ( i = 0; i < p_object->u.menu.i_choices; i++ )
1883 p += sprintf( p, "<input type=radio name=choice value=\"%d\">%s<br>\n", i + 1, p_object->u.menu.ppsz_choices[i] );
1884 p += sprintf( p, "</td></tr><tr><td>%s</td></tr>\n",
1885 p_object->u.menu.psz_bottom );
1888 case EN50221_MMI_LIST:
1889 p += sprintf( p, "<input type=hidden name=type value=menu>\n" );
1890 p += sprintf( p, "<input type=hidden name=choice value=0>\n" );
1891 p += sprintf( p, "<table border=1><tr><th>%s</th></tr>\n",
1892 p_object->u.menu.psz_title );
1893 p += sprintf( p, "<tr><td>%s</td></tr><tr><td>\n",
1894 p_object->u.menu.psz_subtitle );
1895 for ( i = 0; i < p_object->u.menu.i_choices; i++ )
1896 p += sprintf( p, "%s<br>\n",
1897 p_object->u.menu.ppsz_choices[i] );
1898 p += sprintf( p, "</td></tr><tr><td>%s</td></tr>\n",
1899 p_object->u.menu.psz_bottom );
1903 p += sprintf( p, "<table><tr><th>Unknown MMI object type</th></tr>\n" );
1906 p += sprintf( p, "</table><p><input type=submit name=ok value=\"OK\">\n" );
1907 p += sprintf( p, "<input type=submit name=cancel value=\"Cancel\">\n" );
1908 p += sprintf( p, "<input type=submit name=close value=\"Close Session\">\n" );
1910 p += sprintf( p, "</form>\n" );
1912 else if ( sinfo.flags & CA_CI_MODULE_PRESENT )
1913 p += sprintf( p, "module present, not ready<br>\n" );
1915 p += sprintf( p, "module not present<br>\n" );
1919 vlc_mutex_lock( &p_sys->httpd_mutex );
1920 p_sys->b_request_mmi_info = false;
1921 vlc_cond_signal( &p_sys->httpd_cond );
1922 vlc_mutex_unlock( &p_sys->httpd_mutex );
1926 /*****************************************************************************
1928 *****************************************************************************/
1929 int CAMSet( access_t * p_access, dvbpsi_pmt_t *p_pmt )
1931 access_sys_t *p_sys = p_access->p_sys;
1933 if( p_sys->i_ca_handle == 0 )
1935 dvbpsi_DeletePMT( p_pmt );
1936 return VLC_EGENERIC;
1939 en50221_SetCAPMT( p_access, p_pmt );
1944 /*****************************************************************************
1946 *****************************************************************************/
1947 void CAMClose( access_t * p_access )
1949 access_sys_t *p_sys = p_access->p_sys;
1951 en50221_End( p_access );
1953 if ( p_sys->i_ca_handle )
1955 close( p_sys->i_ca_handle );