1 /*****************************************************************************
2 * linux_dvb.c : functions to control a DVB card under Linux with v4l2
3 *****************************************************************************
4 * Copyright (C) 1998-2005 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>
12 * This program 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.
17 * This program 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.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
25 *****************************************************************************/
31 #include <vlc_common.h>
32 #include <vlc_access.h>
33 #include <sys/ioctl.h>
36 #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>
60 # include <dvbpsi/nit.h>
63 # include "descriptor.h"
64 # include "tables/pat.h"
65 # include "tables/pmt.h"
66 # include "descriptors/dr.h"
74 # include "vlc_httpd.h"
84 fe_status_t i_last_status;
85 struct dvb_frontend_info info;
88 #define FRONTEND_LOCK_TIMEOUT 10000000 /* 10 s */
90 /* Local prototypes */
91 static int FrontendInfo( access_t * );
92 static int FrontendSetQPSK( access_t * );
93 static int FrontendSetQAM( access_t * );
94 static int FrontendSetOFDM( access_t * );
95 static int FrontendSetATSC( access_t * );
97 /*****************************************************************************
98 * FrontendOpen : Determine frontend device information and capabilities
99 *****************************************************************************/
100 int FrontendOpen( access_t *p_access )
102 access_sys_t *p_sys = p_access->p_sys;
103 frontend_t * p_frontend;
104 unsigned int i_adapter, i_device;
108 i_adapter = var_GetInteger( p_access, "dvb-adapter" );
109 i_device = var_GetInteger( p_access, "dvb-device" );
110 b_probe = var_GetBool( p_access, "dvb-probe" );
112 if( snprintf( frontend, sizeof(frontend), FRONTEND, i_adapter, i_device ) >= (int)sizeof(frontend) )
114 msg_Err( p_access, "snprintf() truncated string for FRONTEND" );
115 frontend[sizeof(frontend) - 1] = '\0';
118 p_sys->p_frontend = p_frontend = malloc( sizeof(frontend_t) );
122 msg_Dbg( p_access, "Opening device %s", frontend );
123 if( (p_sys->i_frontend_handle = open(frontend, O_RDWR | O_NONBLOCK)) < 0 )
125 msg_Err( p_access, "FrontEndOpen: opening device failed (%m)" );
132 const char * psz_expected = NULL;
133 const char * psz_real;
135 if( FrontendInfo( p_access ) < 0 )
137 close( p_sys->i_frontend_handle );
142 switch( p_frontend->info.type )
157 psz_real = "unknown";
161 if( (!strncmp( p_access->psz_access, "qpsk", 4 ) ||
162 !strncmp( p_access->psz_access, "dvb-s", 5 ) ||
163 !strncmp( p_access->psz_access, "satellite", 9 ) ) &&
164 (p_frontend->info.type != FE_QPSK) )
166 psz_expected = "DVB-S";
168 if( (!strncmp( p_access->psz_access, "cable", 5 ) ||
169 !strncmp( p_access->psz_access, "dvb-c", 5 ) ) &&
170 (p_frontend->info.type != FE_QAM) )
172 psz_expected = "DVB-C";
174 if( (!strncmp( p_access->psz_access, "terrestrial", 11 ) ||
175 !strncmp( p_access->psz_access, "dvb-t", 5 ) ) &&
176 (p_frontend->info.type != FE_OFDM) )
178 psz_expected = "DVB-T";
181 if( (!strncmp( p_access->psz_access, "usdigital", 9 ) ||
182 !strncmp( p_access->psz_access, "atsc", 4 ) ) &&
183 (p_frontend->info.type != FE_ATSC) )
185 psz_expected = "ATSC";
188 if( psz_expected != NULL )
190 msg_Err( p_access, "the user asked for %s, and the tuner is %s",
191 psz_expected, psz_real );
192 close( p_sys->i_frontend_handle );
197 else /* no frontend probing is done so use default border values. */
199 msg_Dbg( p_access, "using default values for frontend info" );
201 msg_Dbg( p_access, "method of access is %s", p_access->psz_access );
202 p_frontend->info.type = FE_QPSK;
203 if( !strncmp( p_access->psz_access, "qpsk", 4 ) ||
204 !strncmp( p_access->psz_access, "dvb-s", 5 ) )
205 p_frontend->info.type = FE_QPSK;
206 else if( !strncmp( p_access->psz_access, "cable", 5 ) ||
207 !strncmp( p_access->psz_access, "dvb-c", 5 ) )
208 p_frontend->info.type = FE_QAM;
209 else if( !strncmp( p_access->psz_access, "terrestrial", 11 ) ||
210 !strncmp( p_access->psz_access, "dvb-t", 5 ) )
211 p_frontend->info.type = FE_OFDM;
212 else if( !strncmp( p_access->psz_access, "usdigital", 9 ) ||
213 !strncmp( p_access->psz_access, "atsc", 4 ) )
214 p_frontend->info.type = FE_ATSC;
220 /*****************************************************************************
221 * FrontendClose : Close the frontend
222 *****************************************************************************/
223 void FrontendClose( access_t *p_access )
225 access_sys_t *p_sys = p_access->p_sys;
227 if( p_sys->p_frontend )
229 close( p_sys->i_frontend_handle );
230 free( p_sys->p_frontend );
232 p_sys->p_frontend = NULL;
236 /*****************************************************************************
237 * FrontendSet : Tune !
238 *****************************************************************************/
239 int FrontendSet( access_t *p_access )
241 access_sys_t *p_sys = p_access->p_sys;
243 switch( p_sys->p_frontend->info.type )
247 if( FrontendSetQPSK( p_access ) < 0 )
249 msg_Err( p_access, "DVB-S: tuning failed" );
256 if( FrontendSetQAM( p_access ) < 0 )
258 msg_Err( p_access, "DVB-C: tuning failed" );
265 if( FrontendSetOFDM( p_access ) < 0 )
267 msg_Err( p_access, "DVB-T: tuning failed" );
274 if( FrontendSetATSC( p_access ) < 0 )
276 msg_Err( p_access, "ATSC: tuning failed" );
282 msg_Err( p_access, "Could not determine frontend type on %s",
283 p_sys->p_frontend->info.name );
286 p_sys->p_frontend->i_last_status = 0;
287 p_sys->i_frontend_timeout = mdate() + FRONTEND_LOCK_TIMEOUT;
291 /*****************************************************************************
292 * FrontendPoll : Poll for frontend events
293 *****************************************************************************/
294 void FrontendPoll( access_t *p_access )
296 access_sys_t *p_sys = p_access->p_sys;
297 frontend_t * p_frontend = p_sys->p_frontend;
298 struct dvb_frontend_event event;
299 fe_status_t i_status, i_diff;
303 int i_ret = ioctl( p_sys->i_frontend_handle, FE_GET_EVENT, &event );
307 if( errno == EWOULDBLOCK )
308 return; /* no more events */
310 msg_Err( p_access, "reading frontend event failed (%d): %m",
315 i_status = event.status;
316 i_diff = i_status ^ p_frontend->i_last_status;
317 p_frontend->i_last_status = i_status;
322 if ( i_diff & (x) ) \
324 if ( i_status & (x) )
326 IF_UP( FE_HAS_SIGNAL )
327 msg_Dbg( p_access, "frontend has acquired signal" );
329 msg_Dbg( p_access, "frontend has lost signal" );
331 IF_UP( FE_HAS_CARRIER )
332 msg_Dbg( p_access, "frontend has acquired carrier" );
334 msg_Dbg( p_access, "frontend has lost carrier" );
336 IF_UP( FE_HAS_VITERBI )
337 msg_Dbg( p_access, "frontend has acquired stable FEC" );
339 msg_Dbg( p_access, "frontend has lost FEC" );
342 msg_Dbg( p_access, "frontend has acquired sync" );
344 msg_Dbg( p_access, "frontend has lost sync" );
348 frontend_statistic_t stat;
350 msg_Dbg( p_access, "frontend has acquired lock" );
351 p_sys->i_frontend_timeout = 0;
353 /* Read some statistics */
354 if( !FrontendGetStatistic( p_access, &stat ) )
356 if( stat.i_ber >= 0 )
357 msg_Dbg( p_access, "- Bit error rate: %d", stat.i_ber );
358 if( stat.i_signal_strenth >= 0 )
359 msg_Dbg( p_access, "- Signal strength: %d", stat.i_signal_strenth );
360 if( stat.i_snr >= 0 )
361 msg_Dbg( p_access, "- SNR: %d", stat.i_snr );
366 msg_Dbg( p_access, "frontend has lost lock" );
367 p_sys->i_frontend_timeout = mdate() + FRONTEND_LOCK_TIMEOUT;
372 /* The frontend was reinited. */
373 msg_Warn( p_access, "reiniting frontend");
374 FrontendSet( p_access );
380 int FrontendGetStatistic( access_t *p_access, frontend_statistic_t *p_stat )
382 access_sys_t *p_sys = p_access->p_sys;
383 frontend_t * p_frontend = p_sys->p_frontend;
385 if( (p_frontend->i_last_status & FE_HAS_LOCK) == 0 )
388 memset( p_stat, 0, sizeof(*p_stat) );
389 if( ioctl( p_sys->i_frontend_handle, FE_READ_BER, &p_stat->i_ber ) < 0 )
391 if( ioctl( p_sys->i_frontend_handle, FE_READ_SIGNAL_STRENGTH, &p_stat->i_signal_strenth ) < 0 )
392 p_stat->i_signal_strenth = -1;
393 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;
407 static int ScanParametersDvbT( access_t *p_access, scan_parameter_t *p_scan )
409 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_T;
414 p_scan->b_exhaustive = false;
417 p_scan->frequency.i_min = p_frontend->info.frequency_min;
418 p_scan->frequency.i_max = p_frontend->info.frequency_max;
419 p_scan->frequency.i_step = p_frontend->info.frequency_stepsize;
420 p_scan->frequency.i_count = (p_scan->frequency.i_max-p_scan->frequency.i_min)/p_scan->frequency.i_step;
423 p_scan->bandwidth.i_min = 6;
424 p_scan->bandwidth.i_max = 8;
425 p_scan->bandwidth.i_step = 1;
426 p_scan->bandwidth.i_count = 3;
429 int FrontendGetScanParameter( access_t *p_access, scan_parameter_t *p_scan )
431 access_sys_t *p_sys = p_access->p_sys;
432 const frontend_t *p_frontend = p_sys->p_frontend;
434 if( p_frontend->info.type == FE_OFDM ) // DVB-T
435 return ScanParametersDvbT( p_access, p_scan );
437 msg_Err( p_access, "Frontend type not supported for scanning" );
442 /*****************************************************************************
443 * FrontendStatus : Read frontend status
444 *****************************************************************************/
445 void FrontendStatus( access_t *p_access )
447 access_sys_t *p_sys = p_access->p_sys;
448 frontend_t *p_frontend = p_sys->p_frontend;
449 char *p = p_sys->psz_frontend_info = malloc( 10000 );
450 fe_status_t i_status;
453 /* Determine type of frontend */
454 if( (i_ret = ioctl( p_sys->i_frontend_handle, FE_GET_INFO,
455 &p_frontend->info )) < 0 )
458 strerror_r( errno, buf, sizeof( buf ) );
459 p += sprintf( p, "ioctl FE_GET_INFO failed (%d) %s\n", i_ret, buf );
463 /* Print out frontend capabilities. */
464 p += sprintf( p, "<table border=1><tr><th>name</th><td>%s</td></tr>\n",
465 p_frontend->info.name );
466 switch( p_frontend->info.type )
469 p += sprintf( p, "<tr><th>type</th><td>QPSK (DVB-S)</td></tr>\n" );
472 p += sprintf( p, "<tr><th>type</th><td>QAM (DVB-C)</td></tr>\n" );
475 p += sprintf( p, "<tr><th>type</th><td>OFDM (DVB-T)</td></tr>\n" );
477 #if 0 /* DVB_API_VERSION == 3 */
479 p += sprintf( p, "<tr><th>type</th><td>MEMORY</td></tr>\n" );
482 p += sprintf( p, "<tr><th>type</th><td>NETWORK</td></tr>\n" );
486 p += sprintf( p, "<tr><th>type</th><td>UNKNOWN (%d)</td></tr>\n",
487 p_frontend->info.type );
490 #define CHECK_INFO( x ) \
492 "<tr><th>" STRINGIFY(x) "</th><td>%u</td></tr>\n", \
493 p_frontend->info.x );
495 CHECK_INFO( frequency_min );
496 CHECK_INFO( frequency_max );
497 CHECK_INFO( frequency_stepsize );
498 CHECK_INFO( frequency_tolerance );
499 CHECK_INFO( symbol_rate_min );
500 CHECK_INFO( symbol_rate_max );
501 CHECK_INFO( symbol_rate_tolerance );
502 CHECK_INFO( notifier_delay );
505 p += sprintf( p, "</table><p>Frontend capability list:\n<table border=1>" );
507 #define CHECK_CAPS( x ) \
508 if ( p_frontend->info.caps & (FE_##x) ) \
509 p += sprintf( p, "<tr><td>" STRINGIFY(x) "</td></tr>\n" );
511 CHECK_CAPS( IS_STUPID );
512 CHECK_CAPS( CAN_INVERSION_AUTO );
513 CHECK_CAPS( CAN_FEC_1_2 );
514 CHECK_CAPS( CAN_FEC_2_3 );
515 CHECK_CAPS( CAN_FEC_3_4 );
516 CHECK_CAPS( CAN_FEC_4_5 );
517 CHECK_CAPS( CAN_FEC_5_6 );
518 CHECK_CAPS( CAN_FEC_6_7 );
519 CHECK_CAPS( CAN_FEC_7_8 );
520 CHECK_CAPS( CAN_FEC_8_9 );
521 CHECK_CAPS( CAN_FEC_AUTO );
522 CHECK_CAPS( CAN_QPSK );
523 CHECK_CAPS( CAN_QAM_16 );
524 CHECK_CAPS( CAN_QAM_32 );
525 CHECK_CAPS( CAN_QAM_64 );
526 CHECK_CAPS( CAN_QAM_128 );
527 CHECK_CAPS( CAN_QAM_256 );
528 CHECK_CAPS( CAN_QAM_AUTO );
529 CHECK_CAPS( CAN_TRANSMISSION_MODE_AUTO );
530 CHECK_CAPS( CAN_BANDWIDTH_AUTO );
531 CHECK_CAPS( CAN_GUARD_INTERVAL_AUTO );
532 CHECK_CAPS( CAN_HIERARCHY_AUTO );
533 CHECK_CAPS( CAN_MUTE_TS );
534 CHECK_CAPS( CAN_RECOVER );
535 #if 0 /* Disabled because of older distributions */
536 CHECK_CAPS( CAN_CLEAN_SETUP );
540 p += sprintf( p, "</table><p>Current frontend status:\n<table border=1>" );
542 if( (i_ret = ioctl( p_sys->i_frontend_handle, FE_READ_STATUS, &i_status ))
546 strerror_r( errno, buf, sizeof( buf ) );
547 p += sprintf( p, "</table>ioctl FE_READ_STATUS failed (%d) %s\n",
552 #define CHECK_STATUS( x ) \
553 if ( i_status & (FE_##x) ) \
554 p += sprintf( p, "<tr><td>" STRINGIFY(x) "</td></tr>\n" );
556 CHECK_STATUS( HAS_SIGNAL );
557 CHECK_STATUS( HAS_CARRIER );
558 CHECK_STATUS( HAS_VITERBI );
559 CHECK_STATUS( HAS_SYNC );
560 CHECK_STATUS( HAS_LOCK );
561 CHECK_STATUS( REINIT );
563 p += sprintf( p, "<tr><td>Tuning failed</td></tr>\n" );
566 if ( i_status & FE_HAS_LOCK )
569 p += sprintf( p, "</table><p>Signal status:\n<table border=1>" );
570 if( ioctl( p_sys->i_frontend_handle, FE_READ_BER, &i_value ) >= 0 )
571 p += sprintf( p, "<tr><th>Bit error rate</th><td>%d</td></tr>\n",
573 if( ioctl( p_sys->i_frontend_handle, FE_READ_SIGNAL_STRENGTH,
575 p += sprintf( p, "<tr><th>Signal strength</th><td>%d</td></tr>\n",
577 if( ioctl( p_sys->i_frontend_handle, FE_READ_SNR, &i_value ) >= 0 )
578 p += sprintf( p, "<tr><th>SNR</th><td>%d</td></tr>\n",
581 p += sprintf( p, "</table>" );
584 vlc_mutex_lock( &p_sys->httpd_mutex );
585 p_sys->b_request_frontend_info = false;
586 vlc_cond_signal( &p_sys->httpd_cond );
587 vlc_mutex_unlock( &p_sys->httpd_mutex );
591 /*****************************************************************************
592 * FrontendInfo : Return information about given frontend
593 *****************************************************************************/
594 static int FrontendInfo( access_t *p_access )
596 access_sys_t *p_sys = p_access->p_sys;
597 frontend_t *p_frontend = p_sys->p_frontend;
600 /* Determine type of frontend */
601 if( (i_ret = ioctl( p_sys->i_frontend_handle, FE_GET_INFO,
602 &p_frontend->info )) < 0 )
604 msg_Err( p_access, "ioctl FE_GET_INFO failed (%d): %m", i_ret );
608 /* Print out frontend capabilities. */
609 msg_Dbg(p_access, "Frontend Info:" );
610 msg_Dbg(p_access, " name = %s", p_frontend->info.name );
611 switch( p_frontend->info.type )
614 msg_Dbg( p_access, " type = QPSK (DVB-S)" );
617 msg_Dbg( p_access, " type = QAM (DVB-C)" );
620 msg_Dbg( p_access, " type = OFDM (DVB-T)" );
623 msg_Dbg( p_access, " type = ATSC (USA)" );
625 #if 0 /* DVB_API_VERSION == 3 */
627 msg_Dbg(p_access, " type = MEMORY" );
630 msg_Dbg(p_access, " type = NETWORK" );
634 msg_Err( p_access, " unknown frontend type (%d)",
635 p_frontend->info.type );
638 msg_Dbg(p_access, " frequency_min = %u (kHz)",
639 p_frontend->info.frequency_min);
640 msg_Dbg(p_access, " frequency_max = %u (kHz)",
641 p_frontend->info.frequency_max);
642 msg_Dbg(p_access, " frequency_stepsize = %u",
643 p_frontend->info.frequency_stepsize);
644 msg_Dbg(p_access, " frequency_tolerance = %u",
645 p_frontend->info.frequency_tolerance);
646 msg_Dbg(p_access, " symbol_rate_min = %u (kHz)",
647 p_frontend->info.symbol_rate_min);
648 msg_Dbg(p_access, " symbol_rate_max = %u (kHz)",
649 p_frontend->info.symbol_rate_max);
650 msg_Dbg(p_access, " symbol_rate_tolerance (ppm) = %u",
651 p_frontend->info.symbol_rate_tolerance);
652 msg_Dbg(p_access, " notifier_delay (ms) = %u",
653 p_frontend->info.notifier_delay );
655 msg_Dbg(p_access, "Frontend Info capability list:");
656 if( p_frontend->info.caps & FE_IS_STUPID)
657 msg_Dbg(p_access, " no capabilities - frontend is stupid!");
658 if( p_frontend->info.caps & FE_CAN_INVERSION_AUTO)
659 msg_Dbg(p_access, " inversion auto");
660 if( p_frontend->info.caps & FE_CAN_FEC_1_2)
661 msg_Dbg(p_access, " forward error correction 1/2");
662 if( p_frontend->info.caps & FE_CAN_FEC_2_3)
663 msg_Dbg(p_access, " forward error correction 2/3");
664 if( p_frontend->info.caps & FE_CAN_FEC_3_4)
665 msg_Dbg(p_access, " forward error correction 3/4");
666 if( p_frontend->info.caps & FE_CAN_FEC_4_5)
667 msg_Dbg(p_access, " forward error correction 4/5");
668 if( p_frontend->info.caps & FE_CAN_FEC_5_6)
669 msg_Dbg(p_access, " forward error correction 5/6");
670 if( p_frontend->info.caps & FE_CAN_FEC_6_7)
671 msg_Dbg(p_access, " forward error correction 6/7");
672 if( p_frontend->info.caps & FE_CAN_FEC_7_8)
673 msg_Dbg(p_access, " forward error correction 7/8");
674 if( p_frontend->info.caps & FE_CAN_FEC_8_9)
675 msg_Dbg(p_access, " forward error correction 8/9");
676 if( p_frontend->info.caps & FE_CAN_FEC_AUTO)
677 msg_Dbg(p_access, " forward error correction auto");
678 if( p_frontend->info.caps & FE_CAN_QPSK)
679 msg_Dbg(p_access, " card can do QPSK");
680 if( p_frontend->info.caps & FE_CAN_QAM_16)
681 msg_Dbg(p_access, " card can do QAM 16");
682 if( p_frontend->info.caps & FE_CAN_QAM_32)
683 msg_Dbg(p_access, " card can do QAM 32");
684 if( p_frontend->info.caps & FE_CAN_QAM_64)
685 msg_Dbg(p_access, " card can do QAM 64");
686 if( p_frontend->info.caps & FE_CAN_QAM_128)
687 msg_Dbg(p_access, " card can do QAM 128");
688 if( p_frontend->info.caps & FE_CAN_QAM_256)
689 msg_Dbg(p_access, " card can do QAM 256");
690 if( p_frontend->info.caps & FE_CAN_QAM_AUTO)
691 msg_Dbg(p_access, " card can do QAM auto");
692 if( p_frontend->info.caps & FE_CAN_TRANSMISSION_MODE_AUTO)
693 msg_Dbg(p_access, " transmission mode auto");
694 if( p_frontend->info.caps & FE_CAN_BANDWIDTH_AUTO)
695 msg_Dbg(p_access, " bandwidth mode auto");
696 if( p_frontend->info.caps & FE_CAN_GUARD_INTERVAL_AUTO)
697 msg_Dbg(p_access, " guard interval mode auto");
698 if( p_frontend->info.caps & FE_CAN_HIERARCHY_AUTO)
699 msg_Dbg(p_access, " hierarchy mode auto");
700 if( p_frontend->info.caps & FE_CAN_MUTE_TS)
701 msg_Dbg(p_access, " card can mute TS");
702 if( p_frontend->info.caps & FE_CAN_RECOVER)
703 msg_Dbg(p_access, " card can recover from a cable unplug");
704 if( p_frontend->info.caps & FE_CAN_8VSB)
705 msg_Dbg(p_access, " card can do 8vsb");
706 if( p_frontend->info.caps & FE_CAN_16VSB)
707 msg_Dbg(p_access, " card can do 16vsb");
708 msg_Dbg(p_access, "End of capability list");
713 /*****************************************************************************
714 * Decoding the DVB parameters (common)
715 *****************************************************************************/
716 static fe_spectral_inversion_t DecodeInversion( access_t *p_access )
719 fe_spectral_inversion_t fe_inversion = 0;
721 var_Get( p_access, "dvb-inversion", &val );
722 msg_Dbg( p_access, "using inversion=%d", val.i_int );
726 case 0: fe_inversion = INVERSION_OFF; break;
727 case 1: fe_inversion = INVERSION_ON; break;
728 case 2: fe_inversion = INVERSION_AUTO; break;
730 msg_Dbg( p_access, "dvb has inversion not set, using auto");
731 fe_inversion = INVERSION_AUTO;
737 static fe_code_rate_t DecodeFEC( access_t *p_access, int i_val )
739 fe_code_rate_t fe_fec = FEC_NONE;
741 msg_Dbg( p_access, "using fec=%d", i_val );
745 case 0: fe_fec = FEC_NONE; break;
746 case 1: fe_fec = FEC_1_2; break;
747 case 2: fe_fec = FEC_2_3; break;
748 case 3: fe_fec = FEC_3_4; break;
749 case 4: fe_fec = FEC_4_5; break;
750 case 5: fe_fec = FEC_5_6; break;
751 case 6: fe_fec = FEC_6_7; break;
752 case 7: fe_fec = FEC_7_8; break;
753 case 8: fe_fec = FEC_8_9; break;
754 case 9: fe_fec = FEC_AUTO; break;
758 msg_Err( p_access, "argument has invalid FEC (%d)", i_val);
764 static fe_modulation_t DecodeModulationQAM( access_t *p_access )
766 switch( var_GetInteger( p_access, "dvb-modulation" ) )
768 case 0: return QAM_AUTO;
769 case 16: return QAM_16;
770 case 32: return QAM_32;
771 case 64: return QAM_64;
772 case 128: return QAM_128;
773 case 256: return QAM_256;
775 msg_Dbg( p_access, "QAM modulation not set, using auto");
779 static fe_modulation_t DecodeModulationOFDM( access_t *p_access )
781 switch( var_GetInteger( p_access, "dvb-modulation" ) )
783 case -1: return QPSK;
784 case 0: return QAM_AUTO;
785 case 16: return QAM_16;
786 case 32: return QAM_32;
787 case 64: return QAM_64;
788 case 128: return QAM_128;
789 case 256: return QAM_256;
791 msg_Dbg( p_access, "OFDM modulation not set, using QAM auto");
795 static fe_modulation_t DecodeModulationATSC( access_t *p_access )
797 switch( var_GetInteger( p_access, "dvb-modulation" ) )
799 case 8: return VSB_8;
800 case 16: return VSB_16;
802 msg_Dbg( p_access, "ATSC modulation not set, using VSB 8");
807 /*****************************************************************************
808 * FrontendSetQPSK : controls the FE device
809 *****************************************************************************/
810 static fe_sec_voltage_t DecodeVoltage( access_t *p_access )
813 fe_sec_voltage_t fe_voltage;
815 var_Get( p_access, "dvb-voltage", &val );
816 msg_Dbg( p_access, "using voltage=%d", val.i_int );
820 case 0: fe_voltage = SEC_VOLTAGE_OFF; break;
821 case 13: fe_voltage = SEC_VOLTAGE_13; break;
822 case 18: fe_voltage = SEC_VOLTAGE_18; break;
824 fe_voltage = SEC_VOLTAGE_OFF;
825 msg_Err( p_access, "argument has invalid voltage (%d)", val.i_int );
831 static fe_sec_tone_mode_t DecodeTone( access_t *p_access )
834 fe_sec_tone_mode_t fe_tone;
836 var_Get( p_access, "dvb-tone", &val );
837 msg_Dbg( p_access, "using tone=%d", val.i_int );
841 case 0: fe_tone = SEC_TONE_OFF; break;
842 case 1: fe_tone = SEC_TONE_ON; break;
844 fe_tone = SEC_TONE_OFF;
845 msg_Err( p_access, "argument has invalid tone mode (%d)", val.i_int);
853 struct dvb_diseqc_master_cmd cmd;
857 static int DoDiseqc( access_t *p_access )
859 access_sys_t *p_sys = p_access->p_sys;
861 int i_frequency, i_lnb_slof;
862 fe_sec_voltage_t fe_voltage;
863 fe_sec_tone_mode_t fe_tone;
866 var_Get( p_access, "dvb-frequency", &val );
867 i_frequency = val.i_int;
868 var_Get( p_access, "dvb-lnb-slof", &val );
869 i_lnb_slof = val.i_int;
871 var_Get( p_access, "dvb-tone", &val );
872 if( val.i_int == -1 /* auto */ )
874 if( i_frequency >= i_lnb_slof )
878 var_Set( p_access, "dvb-tone", val );
881 fe_voltage = DecodeVoltage( p_access );
882 fe_tone = DecodeTone( p_access );
884 /* Switch off continuous tone. */
885 if( (i_err = ioctl( p_sys->i_frontend_handle, FE_SET_TONE, SEC_TONE_OFF )) < 0 )
887 msg_Err( p_access, "ioctl FE_SET_TONE failed, tone=%s (%d) %m",
888 fe_tone == SEC_TONE_ON ? "on" : "off", i_err );
892 /* Configure LNB voltage. */
893 if( (i_err = ioctl( p_sys->i_frontend_handle, FE_SET_VOLTAGE, fe_voltage )) < 0 )
895 msg_Err( p_access, "ioctl FE_SET_VOLTAGE failed, voltage=%d (%d) %m",
900 var_Get( p_access, "dvb-high-voltage", &val );
901 if( (i_err = ioctl( p_sys->i_frontend_handle, FE_ENABLE_HIGH_LNB_VOLTAGE,
902 val.b_bool )) < 0 && val.b_bool )
905 "ioctl FE_ENABLE_HIGH_LNB_VOLTAGE failed, val=%d (%d) %m",
909 /* Wait for at least 15 ms. */
912 var_Get( p_access, "dvb-satno", &val );
913 if( val.i_int > 0 && val.i_int < 5 )
915 /* digital satellite equipment control,
916 * specification is available from http://www.eutelsat.com/
919 /* 1.x compatible equipment */
920 struct diseqc_cmd_t cmd = { {{0xe0, 0x10, 0x38, 0xf0, 0x00, 0x00}, 4}, 0 };
922 /* param: high nibble: reset bits, low nibble set bits,
923 * bits are: option, position, polarization, band
925 cmd.cmd.msg[3] = 0xf0 /* reset bits */
926 | (((val.i_int - 1) * 4) & 0xc)
927 | (fe_voltage == SEC_VOLTAGE_13 ? 0 : 2)
928 | (fe_tone == SEC_TONE_ON ? 1 : 0);
930 if( (i_err = ioctl( p_sys->i_frontend_handle, FE_DISEQC_SEND_MASTER_CMD,
933 msg_Err( p_access, "ioctl FE_SEND_MASTER_CMD failed (%d) %m",
938 msleep(15000 + cmd.wait * 1000);
940 /* A or B simple diseqc ("diseqc-compatible") */
941 if( (i_err = ioctl( p_sys->i_frontend_handle, FE_DISEQC_SEND_BURST,
942 ((val.i_int - 1) % 2) ? SEC_MINI_B : SEC_MINI_A )) < 0 )
944 msg_Err( p_access, "ioctl FE_SEND_BURST failed (%d) %m",
952 if( (i_err = ioctl( p_sys->i_frontend_handle, FE_SET_TONE, fe_tone )) < 0 )
954 msg_Err( p_access, "ioctl FE_SET_TONE failed, tone=%s (%d) %m",
955 fe_tone == SEC_TONE_ON ? "on" : "off", i_err );
963 static int FrontendSetQPSK( access_t *p_access )
965 access_sys_t *p_sys = p_access->p_sys;
966 struct dvb_frontend_parameters fep;
969 int i_frequency, i_lnb_slof = 0, i_lnb_lof1, i_lnb_lof2 = 0;
971 /* Prepare the fep structure */
972 var_Get( p_access, "dvb-frequency", &val );
973 i_frequency = val.i_int;
975 var_Get( p_access, "dvb-lnb-lof1", &val );
976 if ( val.i_int == 0 )
978 /* Automatic mode. */
979 if ( i_frequency >= 950000 && i_frequency <= 2150000 )
981 msg_Dbg( p_access, "frequency %d is in IF-band", i_frequency );
984 else if ( i_frequency >= 2500000 && i_frequency <= 2700000 )
986 msg_Dbg( p_access, "frequency %d is in S-band", i_frequency );
987 i_lnb_lof1 = 3650000;
989 else if ( i_frequency >= 3400000 && i_frequency <= 4200000 )
991 msg_Dbg( p_access, "frequency %d is in C-band (lower)",
993 i_lnb_lof1 = 5150000;
995 else if ( i_frequency >= 4500000 && i_frequency <= 4800000 )
997 msg_Dbg( p_access, "frequency %d is in C-band (higher)",
999 i_lnb_lof1 = 5950000;
1001 else if ( i_frequency >= 10700000 && i_frequency <= 13250000 )
1003 msg_Dbg( p_access, "frequency %d is in Ku-band",
1005 i_lnb_lof1 = 9750000;
1006 i_lnb_lof2 = 10600000;
1007 i_lnb_slof = 11700000;
1011 msg_Err( p_access, "frequency %d is out of any known band",
1013 msg_Err( p_access, "specify dvb-lnb-lof1 manually for the local "
1014 "oscillator frequency" );
1015 return VLC_EGENERIC;
1017 val.i_int = i_lnb_lof1;
1018 var_Set( p_access, "dvb-lnb-lof1", val );
1019 val.i_int = i_lnb_lof2;
1020 var_Set( p_access, "dvb-lnb-lof2", val );
1021 val.i_int = i_lnb_slof;
1022 var_Set( p_access, "dvb-lnb-slof", val );
1026 i_lnb_lof1 = val.i_int;
1027 var_Get( p_access, "dvb-lnb-lof2", &val );
1028 i_lnb_lof2 = val.i_int;
1029 var_Get( p_access, "dvb-lnb-slof", &val );
1030 i_lnb_slof = val.i_int;
1033 if( i_lnb_slof && i_frequency >= i_lnb_slof )
1035 i_frequency -= i_lnb_lof2;
1039 i_frequency -= i_lnb_lof1;
1041 fep.frequency = i_frequency >= 0 ? i_frequency : -i_frequency;
1043 fep.inversion = DecodeInversion( p_access );
1045 var_Get( p_access, "dvb-srate", &val );
1046 fep.u.qpsk.symbol_rate = val.i_int;
1048 var_Get( p_access, "dvb-fec", &val );
1049 fep.u.qpsk.fec_inner = DecodeFEC( p_access, val.i_int );
1051 if( DoDiseqc( p_access ) < 0 )
1053 return VLC_EGENERIC;
1056 /* Empty the event queue */
1059 struct dvb_frontend_event event;
1060 if ( ioctl( p_sys->i_frontend_handle, FE_GET_EVENT, &event ) < 0
1061 && errno == EWOULDBLOCK )
1065 /* Now send it all to the frontend device */
1066 if( (i_ret = ioctl( p_sys->i_frontend_handle, FE_SET_FRONTEND, &fep )) < 0 )
1068 msg_Err( p_access, "DVB-S: setting frontend failed (%d) %m", i_ret );
1069 return VLC_EGENERIC;
1075 /*****************************************************************************
1076 * FrontendSetQAM : controls the FE device
1077 *****************************************************************************/
1078 static int FrontendSetQAM( access_t *p_access )
1080 access_sys_t *p_sys = p_access->p_sys;
1081 struct dvb_frontend_parameters fep;
1085 /* Prepare the fep structure */
1087 var_Get( p_access, "dvb-frequency", &val );
1088 fep.frequency = val.i_int;
1090 fep.inversion = DecodeInversion( p_access );
1092 var_Get( p_access, "dvb-srate", &val );
1093 fep.u.qam.symbol_rate = val.i_int;
1095 var_Get( p_access, "dvb-fec", &val );
1096 fep.u.qam.fec_inner = DecodeFEC( p_access, val.i_int );
1098 fep.u.qam.modulation = DecodeModulationQAM( p_access );
1100 /* Empty the event queue */
1103 struct dvb_frontend_event event;
1104 if ( ioctl( p_sys->i_frontend_handle, FE_GET_EVENT, &event ) < 0
1105 && errno == EWOULDBLOCK )
1109 /* Now send it all to the frontend device */
1110 if( (i_ret = ioctl( p_sys->i_frontend_handle, FE_SET_FRONTEND, &fep )) < 0 )
1112 msg_Err( p_access, "DVB-C: setting frontend failed (%d): %m", i_ret );
1113 return VLC_EGENERIC;
1119 /*****************************************************************************
1120 * FrontendSetOFDM : controls the FE device
1121 *****************************************************************************/
1122 static fe_bandwidth_t DecodeBandwidth( access_t *p_access )
1125 fe_bandwidth_t fe_bandwidth = 0;
1127 var_Get( p_access, "dvb-bandwidth", &val );
1128 msg_Dbg( p_access, "using bandwidth=%d", val.i_int );
1132 case 0: fe_bandwidth = BANDWIDTH_AUTO; break;
1133 case 6: fe_bandwidth = BANDWIDTH_6_MHZ; break;
1134 case 7: fe_bandwidth = BANDWIDTH_7_MHZ; break;
1135 case 8: fe_bandwidth = BANDWIDTH_8_MHZ; break;
1137 msg_Dbg( p_access, "terrestrial dvb has bandwidth not set, using auto" );
1138 fe_bandwidth = BANDWIDTH_AUTO;
1141 return fe_bandwidth;
1144 static fe_transmit_mode_t DecodeTransmission( access_t *p_access )
1147 fe_transmit_mode_t fe_transmission = 0;
1149 var_Get( p_access, "dvb-transmission", &val );
1150 msg_Dbg( p_access, "using transmission=%d", val.i_int );
1154 case 0: fe_transmission = TRANSMISSION_MODE_AUTO; break;
1155 case 2: fe_transmission = TRANSMISSION_MODE_2K; break;
1156 case 8: fe_transmission = TRANSMISSION_MODE_8K; break;
1158 msg_Dbg( p_access, "terrestrial dvb has transmission mode not set, using auto");
1159 fe_transmission = TRANSMISSION_MODE_AUTO;
1162 return fe_transmission;
1165 static fe_guard_interval_t DecodeGuardInterval( access_t *p_access )
1168 fe_guard_interval_t fe_guard = 0;
1170 var_Get( p_access, "dvb-guard", &val );
1171 msg_Dbg( p_access, "using guard=%d", val.i_int );
1175 case 0: fe_guard = GUARD_INTERVAL_AUTO; break;
1176 case 4: fe_guard = GUARD_INTERVAL_1_4; break;
1177 case 8: fe_guard = GUARD_INTERVAL_1_8; break;
1178 case 16: fe_guard = GUARD_INTERVAL_1_16; break;
1179 case 32: fe_guard = GUARD_INTERVAL_1_32; break;
1181 msg_Dbg( p_access, "terrestrial dvb has guard interval not set, using auto");
1182 fe_guard = GUARD_INTERVAL_AUTO;
1188 static fe_hierarchy_t DecodeHierarchy( access_t *p_access )
1191 fe_hierarchy_t fe_hierarchy = 0;
1193 var_Get( p_access, "dvb-hierarchy", &val );
1194 msg_Dbg( p_access, "using hierarchy=%d", val.i_int );
1198 case -1: fe_hierarchy = HIERARCHY_NONE; break;
1199 case 0: fe_hierarchy = HIERARCHY_AUTO; break;
1200 case 1: fe_hierarchy = HIERARCHY_1; break;
1201 case 2: fe_hierarchy = HIERARCHY_2; break;
1202 case 4: fe_hierarchy = HIERARCHY_4; break;
1204 msg_Dbg( p_access, "terrestrial dvb has hierarchy not set, using auto");
1205 fe_hierarchy = HIERARCHY_AUTO;
1208 return fe_hierarchy;
1211 static int FrontendSetOFDM( access_t * p_access )
1213 access_sys_t *p_sys = p_access->p_sys;
1214 struct dvb_frontend_parameters fep;
1218 /* Prepare the fep structure */
1220 var_Get( p_access, "dvb-frequency", &val );
1221 fep.frequency = val.i_int;
1223 fep.inversion = DecodeInversion( p_access );
1225 fep.u.ofdm.bandwidth = DecodeBandwidth( p_access );
1226 var_Get( p_access, "dvb-code-rate-hp", &val );
1227 fep.u.ofdm.code_rate_HP = DecodeFEC( p_access, val.i_int );
1228 var_Get( p_access, "dvb-code-rate-lp", &val );
1229 fep.u.ofdm.code_rate_LP = DecodeFEC( p_access, val.i_int );
1230 fep.u.ofdm.constellation = DecodeModulationOFDM( p_access );
1231 fep.u.ofdm.transmission_mode = DecodeTransmission( p_access );
1232 fep.u.ofdm.guard_interval = DecodeGuardInterval( p_access );
1233 fep.u.ofdm.hierarchy_information = DecodeHierarchy( p_access );
1235 /* Empty the event queue */
1238 struct dvb_frontend_event event;
1239 if ( ioctl( p_sys->i_frontend_handle, FE_GET_EVENT, &event ) < 0
1240 && errno == EWOULDBLOCK )
1244 /* Now send it all to the frontend device */
1245 if( (ret = ioctl( p_sys->i_frontend_handle, FE_SET_FRONTEND, &fep )) < 0 )
1247 msg_Err( p_access, "DVB-T: setting frontend failed (%d): %m", ret );
1254 /*****************************************************************************
1255 * FrontendSetATSC : controls the FE device
1256 *****************************************************************************/
1257 static int FrontendSetATSC( access_t *p_access )
1259 access_sys_t *p_sys = p_access->p_sys;
1260 struct dvb_frontend_parameters fep;
1264 /* Prepare the fep structure */
1266 var_Get( p_access, "dvb-frequency", &val );
1267 fep.frequency = val.i_int;
1269 fep.u.vsb.modulation = DecodeModulationATSC( p_access );
1271 /* Empty the event queue */
1274 struct dvb_frontend_event event;
1275 if ( ioctl( p_sys->i_frontend_handle, FE_GET_EVENT, &event ) < 0
1276 && errno == EWOULDBLOCK )
1280 /* Now send it all to the frontend device */
1281 if( (i_ret = ioctl( p_sys->i_frontend_handle, FE_SET_FRONTEND, &fep )) < 0 )
1283 msg_Err( p_access, "ATSC: setting frontend failed (%d): %m", i_ret );
1284 return VLC_EGENERIC;
1295 /*****************************************************************************
1296 * DMXSetFilter : controls the demux to add a filter
1297 *****************************************************************************/
1298 int DMXSetFilter( access_t * p_access, int i_pid, int * pi_fd, int i_type )
1300 struct dmx_pes_filter_params s_filter_params;
1302 unsigned int i_adapter, i_device;
1306 var_Get( p_access, "dvb-adapter", &val );
1307 i_adapter = val.i_int;
1308 var_Get( p_access, "dvb-device", &val );
1309 i_device = val.i_int;
1311 if( snprintf( dmx, sizeof(dmx), DMX, i_adapter, i_device )
1312 >= (int)sizeof(dmx) )
1314 msg_Err( p_access, "snprintf() truncated string for DMX" );
1315 dmx[sizeof(dmx) - 1] = '\0';
1318 msg_Dbg( p_access, "Opening device %s", dmx );
1319 if( (*pi_fd = open(dmx, O_RDWR)) < 0 )
1321 msg_Err( p_access, "DMXSetFilter: opening device failed (%m)" );
1322 return VLC_EGENERIC;
1325 /* We fill the DEMUX structure : */
1326 s_filter_params.pid = i_pid;
1327 s_filter_params.input = DMX_IN_FRONTEND;
1328 s_filter_params.output = DMX_OUT_TS_TAP;
1329 s_filter_params.flags = DMX_IMMEDIATE_START;
1332 { /* First device */
1334 msg_Dbg(p_access, "DMXSetFilter: DMX_PES_VIDEO0 for PID %d", i_pid);
1335 s_filter_params.pes_type = DMX_PES_VIDEO0;
1338 msg_Dbg(p_access, "DMXSetFilter: DMX_PES_AUDIO0 for PID %d", i_pid);
1339 s_filter_params.pes_type = DMX_PES_AUDIO0;
1342 msg_Dbg(p_access, "DMXSetFilter: DMX_PES_TELETEXT0 for PID %d", i_pid);
1343 s_filter_params.pes_type = DMX_PES_TELETEXT0;
1346 msg_Dbg(p_access, "DMXSetFilter: DMX_PES_SUBTITLE0 for PID %d", i_pid);
1347 s_filter_params.pes_type = DMX_PES_SUBTITLE0;
1350 msg_Dbg(p_access, "DMXSetFilter: DMX_PES_PCR0 for PID %d", i_pid);
1351 s_filter_params.pes_type = DMX_PES_PCR0;
1355 msg_Dbg(p_access, "DMXSetFilter: DMX_PES_VIDEO1 for PID %d", i_pid);
1356 s_filter_params.pes_type = DMX_PES_VIDEO1;
1359 msg_Dbg(p_access, "DMXSetFilter: DMX_PES_AUDIO1 for PID %d", i_pid);
1360 s_filter_params.pes_type = DMX_PES_AUDIO1;
1363 msg_Dbg(p_access, "DMXSetFilter: DMX_PES_TELETEXT1 for PID %d", i_pid);
1364 s_filter_params.pes_type = DMX_PES_TELETEXT1;
1367 msg_Dbg(p_access, "DMXSetFilter: DMX_PES_SUBTITLE1 for PID %d", i_pid);
1368 s_filter_params.pes_type = DMX_PES_SUBTITLE1;
1371 msg_Dbg(p_access, "DMXSetFilter: DMX_PES_PCR1 for PID %d", i_pid);
1372 s_filter_params.pes_type = DMX_PES_PCR1;
1376 msg_Dbg(p_access, "DMXSetFilter: DMX_PES_VIDEO2 for PID %d", i_pid);
1377 s_filter_params.pes_type = DMX_PES_VIDEO2;
1380 msg_Dbg(p_access, "DMXSetFilter: DMX_PES_AUDIO2 for PID %d", i_pid);
1381 s_filter_params.pes_type = DMX_PES_AUDIO2;
1384 msg_Dbg(p_access, "DMXSetFilter: DMX_PES_TELETEXT2 for PID %d", i_pid);
1385 s_filter_params.pes_type = DMX_PES_TELETEXT2;
1388 msg_Dbg(p_access, "DMXSetFilter: DMX_PES_SUBTITLE2 for PID %d", i_pid);
1389 s_filter_params.pes_type = DMX_PES_SUBTITLE2;
1392 msg_Dbg(p_access, "DMXSetFilter: DMX_PES_PCR2 for PID %d", i_pid);
1393 s_filter_params.pes_type = DMX_PES_PCR2;
1397 msg_Dbg(p_access, "DMXSetFilter: DMX_PES_VIDEO3 for PID %d", i_pid);
1398 s_filter_params.pes_type = DMX_PES_VIDEO3;
1401 msg_Dbg(p_access, "DMXSetFilter: DMX_PES_AUDIO3 for PID %d", i_pid);
1402 s_filter_params.pes_type = DMX_PES_AUDIO3;
1405 msg_Dbg(p_access, "DMXSetFilter: DMX_PES_TELETEXT3 for PID %d", i_pid);
1406 s_filter_params.pes_type = DMX_PES_TELETEXT3;
1409 msg_Dbg(p_access, "DMXSetFilter: DMX_PES_SUBTITLE3 for PID %d", i_pid);
1410 s_filter_params.pes_type = DMX_PES_SUBTITLE3;
1413 msg_Dbg(p_access, "DMXSetFilter: DMX_PES_PCR3 for PID %d", i_pid);
1414 s_filter_params.pes_type = DMX_PES_PCR3;
1416 /* Usually used by Nova cards */
1419 msg_Dbg(p_access, "DMXSetFilter: DMX_PES_OTHER for PID %d", i_pid);
1420 s_filter_params.pes_type = DMX_PES_OTHER;
1424 /* We then give the order to the device : */
1425 if( (i_ret = ioctl( *pi_fd, DMX_SET_PES_FILTER, &s_filter_params )) < 0 )
1427 msg_Err( p_access, "DMXSetFilter: failed with %d (%m)", i_ret );
1428 return VLC_EGENERIC;
1433 /*****************************************************************************
1434 * DMXUnsetFilter : removes a filter
1435 *****************************************************************************/
1436 int DMXUnsetFilter( access_t * p_access, int i_fd )
1440 if( (i_ret = ioctl( i_fd, DMX_STOP )) < 0 )
1442 msg_Err( p_access, "DMX_STOP failed for demux (%d): %m", i_ret );
1446 msg_Dbg( p_access, "DMXUnsetFilter: closing demux %d", i_fd );
1456 /*****************************************************************************
1458 *****************************************************************************/
1459 int DVROpen( access_t * p_access )
1461 access_sys_t *p_sys = p_access->p_sys;
1462 unsigned int i_adapter, i_device;
1466 var_Get( p_access, "dvb-adapter", &val );
1467 i_adapter = val.i_int;
1468 var_Get( p_access, "dvb-device", &val );
1469 i_device = val.i_int;
1471 if( snprintf( dvr, sizeof(dvr), DVR, i_adapter, i_device )
1472 >= (int)sizeof(dvr) )
1474 msg_Err( p_access, "snprintf() truncated string for DVR" );
1475 dvr[sizeof(dvr) - 1] = '\0';
1478 msg_Dbg( p_access, "Opening device %s", dvr );
1479 if( (p_sys->i_handle = open(dvr, O_RDONLY)) < 0 )
1481 msg_Err( p_access, "DVROpen: opening device failed (%m)" );
1482 return VLC_EGENERIC;
1485 if( fcntl( p_sys->i_handle, F_SETFL, O_NONBLOCK ) == -1 )
1487 msg_Warn( p_access, "DVROpen: couldn't set non-blocking mode (%m)" );
1493 /*****************************************************************************
1495 *****************************************************************************/
1496 void DVRClose( access_t * p_access )
1498 access_sys_t *p_sys = p_access->p_sys;
1500 close( p_sys->i_handle );
1508 /*****************************************************************************
1510 *****************************************************************************/
1511 int CAMOpen( access_t *p_access )
1513 access_sys_t *p_sys = p_access->p_sys;
1515 int i_adapter, i_device;
1518 i_adapter = var_GetInteger( p_access, "dvb-adapter" );
1519 i_device = var_GetInteger( p_access, "dvb-device" );
1521 if( snprintf( ca, sizeof(ca), CA, i_adapter, i_device ) >= (int)sizeof(ca) )
1523 msg_Err( p_access, "snprintf() truncated string for CA" );
1524 ca[sizeof(ca) - 1] = '\0';
1526 memset( &caps, 0, sizeof( ca_caps_t ));
1528 msg_Dbg( p_access, "Opening device %s", ca );
1529 if( (p_sys->i_ca_handle = open(ca, O_RDWR | O_NONBLOCK)) < 0 )
1531 msg_Warn( p_access, "CAMInit: opening CAM device failed (%m)" );
1532 p_sys->i_ca_handle = 0;
1533 return VLC_EGENERIC;
1536 if ( ioctl( p_sys->i_ca_handle, CA_GET_CAP, &caps ) != 0 )
1538 msg_Err( p_access, "CAMInit: ioctl() error getting CAM capabilities" );
1539 close( p_sys->i_ca_handle );
1540 p_sys->i_ca_handle = 0;
1541 return VLC_EGENERIC;
1544 /* Output CA capabilities */
1545 msg_Dbg( p_access, "CAMInit: CA interface with %d %s", caps.slot_num,
1546 caps.slot_num == 1 ? "slot" : "slots" );
1547 if ( caps.slot_type & CA_CI )
1548 msg_Dbg( p_access, "CAMInit: CI high level interface type" );
1549 if ( caps.slot_type & CA_CI_LINK )
1550 msg_Dbg( p_access, "CAMInit: CI link layer level interface type" );
1551 if ( caps.slot_type & CA_CI_PHYS )
1552 msg_Dbg( p_access, "CAMInit: CI physical layer level interface type (not supported) " );
1553 if ( caps.slot_type & CA_DESCR )
1554 msg_Dbg( p_access, "CAMInit: built-in descrambler detected" );
1555 if ( caps.slot_type & CA_SC )
1556 msg_Dbg( p_access, "CAMInit: simple smart card interface" );
1558 msg_Dbg( p_access, "CAMInit: %d available %s", caps.descr_num,
1559 caps.descr_num == 1 ? "descrambler (key)" : "descramblers (keys)" );
1560 if ( caps.descr_type & CA_ECD )
1561 msg_Dbg( p_access, "CAMInit: ECD scrambling system supported" );
1562 if ( caps.descr_type & CA_NDS )
1563 msg_Dbg( p_access, "CAMInit: NDS scrambling system supported" );
1564 if ( caps.descr_type & CA_DSS )
1565 msg_Dbg( p_access, "CAMInit: DSS scrambling system supported" );
1567 if ( caps.slot_num == 0 )
1569 msg_Err( p_access, "CAMInit: CAM module with no slots" );
1570 close( p_sys->i_ca_handle );
1571 p_sys->i_ca_handle = 0;
1572 return VLC_EGENERIC;
1575 if( caps.slot_type & CA_CI_LINK )
1577 p_sys->i_ca_type = CA_CI_LINK;
1579 else if( caps.slot_type & CA_CI )
1581 p_sys->i_ca_type = CA_CI;
1585 p_sys->i_ca_type = -1;
1586 msg_Err( p_access, "CAMInit: incompatible CAM interface" );
1587 close( p_sys->i_ca_handle );
1588 p_sys->i_ca_handle = 0;
1589 return VLC_EGENERIC;
1592 p_sys->i_nb_slots = caps.slot_num;
1593 memset( p_sys->pb_active_slot, 0, sizeof(bool) * MAX_CI_SLOTS );
1594 memset( p_sys->pb_slot_mmi_expected, 0, sizeof(bool) * MAX_CI_SLOTS );
1595 memset( p_sys->pb_slot_mmi_undisplayed, 0,
1596 sizeof(bool) * MAX_CI_SLOTS );
1598 return en50221_Init( p_access );
1601 /*****************************************************************************
1603 *****************************************************************************/
1604 int CAMPoll( access_t * p_access )
1606 access_sys_t *p_sys = p_access->p_sys;
1607 int i_ret = VLC_EGENERIC;
1609 if ( p_sys->i_ca_handle == 0 )
1611 return VLC_EGENERIC;
1614 switch( p_sys->i_ca_type )
1617 i_ret = en50221_Poll( p_access );
1620 i_ret = VLC_SUCCESS;
1623 msg_Err( p_access, "CAMPoll: This should not happen" );
1631 /*****************************************************************************
1633 *****************************************************************************/
1634 void CAMStatus( access_t * p_access )
1636 access_sys_t *p_sys = p_access->p_sys;
1641 if ( p_sys->psz_request != NULL && *p_sys->psz_request )
1643 /* Check if we have an undisplayed MMI message : in that case we ignore
1644 * the user input to avoid confusing the CAM. */
1645 for ( i_slot = 0; i_slot < p_sys->i_nb_slots; i_slot++ )
1647 if ( p_sys->pb_slot_mmi_undisplayed[i_slot] == true )
1649 p_sys->psz_request = NULL;
1651 "ignoring user request because of a new MMI object" );
1657 if ( p_sys->psz_request != NULL && *p_sys->psz_request )
1659 /* We have a mission to accomplish. */
1660 en50221_mmi_object_t mmi_object;
1661 char *psz_request = p_sys->psz_request;
1662 char psz_value[255];
1666 p_sys->psz_request = NULL;
1668 if ( HTTPExtractValue( psz_request, "slot", psz_value,
1669 sizeof(psz_value) ) == NULL )
1671 p_sys->psz_mmi_info = strdup( "invalid request parameter\n" );
1674 i_slot = atoi(psz_value);
1676 if ( HTTPExtractValue( psz_request, "open", psz_value,
1677 sizeof(psz_value) ) != NULL )
1679 en50221_OpenMMI( p_access, i_slot );
1683 if ( HTTPExtractValue( psz_request, "close", psz_value,
1684 sizeof(psz_value) ) != NULL )
1686 en50221_CloseMMI( p_access, i_slot );
1690 if ( HTTPExtractValue( psz_request, "cancel", psz_value,
1691 sizeof(psz_value) ) == NULL )
1696 if ( HTTPExtractValue( psz_request, "type", psz_value,
1697 sizeof(psz_value) ) == NULL )
1699 p_sys->psz_mmi_info = strdup( "invalid request parameter\n" );
1703 if ( !strcmp( psz_value, "enq" ) )
1705 mmi_object.i_object_type = EN50221_MMI_ANSW;
1706 mmi_object.u.answ.b_ok = b_ok;
1707 if ( b_ok == false )
1709 mmi_object.u.answ.psz_answ = strdup("");
1713 if ( HTTPExtractValue( psz_request, "answ", psz_value,
1714 sizeof(psz_value) ) == NULL )
1716 p_sys->psz_mmi_info = strdup( "invalid request parameter\n" );
1720 mmi_object.u.answ.psz_answ = strdup(psz_value);
1725 mmi_object.i_object_type = EN50221_MMI_MENU_ANSW;
1726 if ( b_ok == false )
1728 mmi_object.u.menu_answ.i_choice = 0;
1732 if ( HTTPExtractValue( psz_request, "choice", psz_value,
1733 sizeof(psz_value) ) == NULL )
1734 mmi_object.u.menu_answ.i_choice = 0;
1736 mmi_object.u.menu_answ.i_choice = atoi(psz_value);
1740 en50221_SendMMIObject( p_access, i_slot, &mmi_object );
1744 /* Check that we have all necessary MMI information. */
1745 for ( i_slot = 0; i_slot < p_sys->i_nb_slots; i_slot++ )
1747 if ( p_sys->pb_slot_mmi_expected[i_slot] == true )
1751 p = p_sys->psz_mmi_info = malloc( 10000 );
1753 if ( ioctl( p_sys->i_ca_handle, CA_GET_CAP, &caps ) != 0 )
1756 strerror_r( errno, buf, sizeof( buf ) );
1757 p += sprintf( p, "ioctl CA_GET_CAP failed (%s)\n", buf );
1761 /* Output CA capabilities */
1762 p += sprintf( p, "CA interface with %d %s, type:\n<table>", caps.slot_num,
1763 caps.slot_num == 1 ? "slot" : "slots" );
1764 #define CHECK_CAPS( x, s ) \
1765 if ( caps.slot_type & (CA_##x) ) \
1766 p += sprintf( p, "<tr><td>" s "</td></tr>\n" );
1768 CHECK_CAPS( CI, "CI high level interface" );
1769 CHECK_CAPS( CI_LINK, "CI link layer level interface" );
1770 CHECK_CAPS( CI_PHYS, "CI physical layer level interface (not supported)" );
1771 CHECK_CAPS( DESCR, "built-in descrambler" );
1772 CHECK_CAPS( SC, "simple smartcard interface" );
1775 p += sprintf( p, "</table>%d available %s\n<table>", caps.descr_num,
1776 caps.descr_num == 1 ? "descrambler (key)" : "descramblers (keys)" );
1777 #define CHECK_DESC( x ) \
1778 if ( caps.descr_type & (CA_##x) ) \
1779 p += sprintf( p, "<tr><td>" STRINGIFY(x) "</td></tr>\n" );
1786 p += sprintf( p, "</table>" );
1788 for ( i_slot = 0; i_slot < p_sys->i_nb_slots; i_slot++ )
1790 ca_slot_info_t sinfo;
1792 p_sys->pb_slot_mmi_undisplayed[i_slot] = false;
1793 p += sprintf( p, "<p>CA slot #%d: ", i_slot );
1796 if ( ioctl( p_sys->i_ca_handle, CA_GET_SLOT_INFO, &sinfo ) != 0 )
1799 strerror_r( errno, buf, sizeof( buf ) );
1800 p += sprintf( p, "ioctl CA_GET_SLOT_INFO failed (%s)<br>\n", buf );
1804 #define CHECK_TYPE( x, s ) \
1805 if ( sinfo.type & (CA_##x) ) \
1806 p += sprintf( p, "%s", s );
1808 CHECK_TYPE( CI, "high level, " );
1809 CHECK_TYPE( CI_LINK, "link layer level, " );
1810 CHECK_TYPE( CI_PHYS, "physical layer level, " );
1813 if ( sinfo.flags & CA_CI_MODULE_READY )
1815 en50221_mmi_object_t *p_object = en50221_GetMMIObject( p_access,
1818 p += sprintf( p, "module present and ready<p>\n" );
1819 p += sprintf( p, "<form action=index.html method=get>\n" );
1820 p += sprintf( p, "<input type=hidden name=slot value=\"%d\">\n",
1823 if ( p_object == NULL )
1825 p += sprintf( p, "<input type=submit name=open value=\"Open session\">\n" );
1829 switch ( p_object->i_object_type )
1831 case EN50221_MMI_ENQ:
1832 p += sprintf( p, "<input type=hidden name=type value=enq>\n" );
1833 p += sprintf( p, "<table border=1><tr><th>%s</th></tr>\n",
1834 p_object->u.enq.psz_text );
1835 if ( p_object->u.enq.b_blind == false )
1836 p += sprintf( p, "<tr><td><input type=text name=answ></td></tr>\n" );
1838 p += sprintf( p, "<tr><td><input type=password name=answ></td></tr>\n" );
1841 case EN50221_MMI_MENU:
1842 p += sprintf( p, "<input type=hidden name=type value=menu>\n" );
1843 p += sprintf( p, "<table border=1><tr><th>%s</th></tr>\n",
1844 p_object->u.menu.psz_title );
1845 p += sprintf( p, "<tr><td>%s</td></tr><tr><td>\n",
1846 p_object->u.menu.psz_subtitle );
1847 for ( i = 0; i < p_object->u.menu.i_choices; i++ )
1848 p += sprintf( p, "<input type=radio name=choice value=\"%d\">%s<br>\n", i + 1, p_object->u.menu.ppsz_choices[i] );
1849 p += sprintf( p, "</td></tr><tr><td>%s</td></tr>\n",
1850 p_object->u.menu.psz_bottom );
1853 case EN50221_MMI_LIST:
1854 p += sprintf( p, "<input type=hidden name=type value=menu>\n" );
1855 p += sprintf( p, "<input type=hidden name=choice value=0>\n" );
1856 p += sprintf( p, "<table border=1><tr><th>%s</th></tr>\n",
1857 p_object->u.menu.psz_title );
1858 p += sprintf( p, "<tr><td>%s</td></tr><tr><td>\n",
1859 p_object->u.menu.psz_subtitle );
1860 for ( i = 0; i < p_object->u.menu.i_choices; i++ )
1861 p += sprintf( p, "%s<br>\n",
1862 p_object->u.menu.ppsz_choices[i] );
1863 p += sprintf( p, "</td></tr><tr><td>%s</td></tr>\n",
1864 p_object->u.menu.psz_bottom );
1868 p += sprintf( p, "<table><tr><th>Unknown MMI object type</th></tr>\n" );
1871 p += sprintf( p, "</table><p><input type=submit name=ok value=\"OK\">\n" );
1872 p += sprintf( p, "<input type=submit name=cancel value=\"Cancel\">\n" );
1873 p += sprintf( p, "<input type=submit name=close value=\"Close Session\">\n" );
1875 p += sprintf( p, "</form>\n" );
1877 else if ( sinfo.flags & CA_CI_MODULE_PRESENT )
1878 p += sprintf( p, "module present, not ready<br>\n" );
1880 p += sprintf( p, "module not present<br>\n" );
1884 vlc_mutex_lock( &p_sys->httpd_mutex );
1885 p_sys->b_request_mmi_info = false;
1886 vlc_cond_signal( &p_sys->httpd_cond );
1887 vlc_mutex_unlock( &p_sys->httpd_mutex );
1891 /*****************************************************************************
1893 *****************************************************************************/
1894 int CAMSet( access_t * p_access, dvbpsi_pmt_t *p_pmt )
1896 access_sys_t *p_sys = p_access->p_sys;
1898 if( p_sys->i_ca_handle == 0 )
1900 dvbpsi_DeletePMT( p_pmt );
1901 return VLC_EGENERIC;
1904 en50221_SetCAPMT( p_access, p_pmt );
1909 /*****************************************************************************
1911 *****************************************************************************/
1912 void CAMClose( access_t * p_access )
1914 access_sys_t *p_sys = p_access->p_sys;
1916 en50221_End( p_access );
1918 if ( p_sys->i_ca_handle )
1920 close( p_sys->i_ca_handle );