]> git.sesse.net Git - vlc/blob - modules/access/dvb/linux_dvb.c
Merge branch 'master' into lpcm_encoder
[vlc] / modules / access / dvb / linux_dvb.c
1 /*****************************************************************************
2  * linux_dvb.c : functions to control a DVB card under Linux with v4l2
3  *****************************************************************************
4  * Copyright (C) 1998-2010 the VideoLAN team
5  *
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>
12  *
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.
17  *
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.
22  *
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  *****************************************************************************/
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <vlc_common.h>
33 #include <vlc_access.h>
34 #include <sys/ioctl.h>
35 #include <errno.h>
36
37 #include <sys/types.h>
38 #include <fcntl.h>
39 #include <time.h>
40 #include <unistd.h>
41 #include <poll.h>
42 #include <vlc_fs.h>
43
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>
49
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 #else
61 #   include "dvbpsi.h"
62 #   include "descriptor.h"
63 #   include "tables/pat.h"
64 #   include "tables/pmt.h"
65 #   include "descriptors/dr.h"
66 #   include "psi.h"
67 #   include "demux.h"
68 #   include "tables/sdt.h"
69 #endif
70
71 #ifdef ENABLE_HTTPD
72 #   include <vlc_httpd.h>
73 #endif
74
75 #include "dvb.h"
76
77 /*
78  * Frontends
79  */
80 struct frontend_t
81 {
82     fe_status_t i_last_status;
83     struct dvb_frontend_info info;
84 };
85
86 #define FRONTEND_LOCK_TIMEOUT 10000000 /* 10 s */
87
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 * );
94
95 /*****************************************************************************
96  * FrontendOpen : Determine frontend device information and capabilities
97  *****************************************************************************/
98 int FrontendOpen( access_t *p_access )
99 {
100     access_sys_t *p_sys = p_access->p_sys;
101     frontend_t * p_frontend;
102     unsigned int i_adapter, i_device;
103     bool b_probe;
104     char frontend[128];
105
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" );
109
110     if( snprintf( frontend, sizeof(frontend), FRONTEND, i_adapter, i_device ) >= (int)sizeof(frontend) )
111     {
112         msg_Err( p_access, "snprintf() truncated string for FRONTEND" );
113         frontend[sizeof(frontend) - 1] = '\0';
114     }
115
116     p_sys->p_frontend = p_frontend = malloc( sizeof(frontend_t) );
117     if( !p_frontend )
118         return VLC_ENOMEM;
119
120     msg_Dbg( p_access, "Opening device %s", frontend );
121     if( (p_sys->i_frontend_handle = vlc_open(frontend, O_RDWR | O_NONBLOCK)) < 0 )
122     {
123         msg_Err( p_access, "FrontEndOpen: opening device failed (%m)" );
124         free( p_frontend );
125         return VLC_EGENERIC;
126     }
127
128     if( b_probe )
129     {
130         const char * psz_expected = NULL;
131         const char * psz_real;
132
133         if( FrontendInfo( p_access ) < 0 )
134         {
135             close( p_sys->i_frontend_handle );
136             free( p_frontend );
137             return VLC_EGENERIC;
138         }
139
140         switch( p_frontend->info.type )
141         {
142         case FE_OFDM:
143             psz_real = "DVB-T";
144             break;
145         case FE_QAM:
146             psz_real = "DVB-C";
147             break;
148         case FE_QPSK:
149             psz_real = "DVB-S";
150             break;
151         case FE_ATSC:
152             psz_real = "ATSC";
153             break;
154         default:
155             psz_real = "unknown";
156         }
157
158         /* Sanity checks */
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) )
163         {
164             psz_expected = "DVB-S";
165         }
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) )
169         {
170             psz_expected = "DVB-C";
171         }
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) )
175         {
176             psz_expected = "DVB-T";
177         }
178
179         if( (!strncmp( p_access->psz_access, "usdigital", 9 ) ||
180              !strncmp( p_access->psz_access, "atsc", 4 ) ) &&
181              (p_frontend->info.type != FE_ATSC) )
182         {
183             psz_expected = "ATSC";
184         }
185
186         if( psz_expected != NULL )
187         {
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 );
191             free( p_frontend );
192             return VLC_EGENERIC;
193         }
194     }
195     else /* no frontend probing is done so use default border values. */
196     {
197         msg_Dbg( p_access, "using default values for frontend info" );
198
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;
213     }
214
215     return VLC_SUCCESS;
216 }
217
218 /*****************************************************************************
219  * FrontendClose : Close the frontend
220  *****************************************************************************/
221 void FrontendClose( access_t *p_access )
222 {
223     access_sys_t *p_sys = p_access->p_sys;
224
225     if( p_sys->p_frontend )
226     {
227         close( p_sys->i_frontend_handle );
228         free( p_sys->p_frontend );
229
230         p_sys->p_frontend = NULL;
231     }
232 }
233
234 /*****************************************************************************
235  * FrontendSet : Tune !
236  *****************************************************************************/
237 int FrontendSet( access_t *p_access )
238 {
239     access_sys_t *p_sys = p_access->p_sys;
240
241     switch( p_sys->p_frontend->info.type )
242     {
243     /* DVB-S */
244     case FE_QPSK:
245         if( FrontendSetQPSK( p_access ) < 0 )
246         {
247             msg_Err( p_access, "DVB-S: tuning failed" );
248             return VLC_EGENERIC;
249         }
250         break;
251
252     /* DVB-C */
253     case FE_QAM:
254         if( FrontendSetQAM( p_access ) < 0 )
255         {
256             msg_Err( p_access, "DVB-C: tuning failed" );
257             return VLC_EGENERIC;
258         }
259         break;
260
261     /* DVB-T */
262     case FE_OFDM:
263         if( FrontendSetOFDM( p_access ) < 0 )
264         {
265             msg_Err( p_access, "DVB-T: tuning failed" );
266             return VLC_EGENERIC;
267         }
268         break;
269
270     /* ATSC */
271     case FE_ATSC:
272         if( FrontendSetATSC( p_access ) < 0 )
273         {
274             msg_Err( p_access, "ATSC: tuning failed" );
275             return VLC_EGENERIC;
276         }
277         break;
278
279     default:
280         msg_Err( p_access, "Could not determine frontend type on %s",
281                  p_sys->p_frontend->info.name );
282         return VLC_EGENERIC;
283     }
284     p_sys->p_frontend->i_last_status = 0;
285     p_sys->i_frontend_timeout = mdate() + FRONTEND_LOCK_TIMEOUT;
286     return VLC_SUCCESS;
287 }
288
289 /*****************************************************************************
290  * FrontendPoll : Poll for frontend events
291  *****************************************************************************/
292 void FrontendPoll( access_t *p_access )
293 {
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;
298
299     for( ;; )
300     {
301         int i_ret = ioctl( p_sys->i_frontend_handle, FE_GET_EVENT, &event );
302
303         if( i_ret < 0 )
304         {
305             if( errno == EWOULDBLOCK )
306                 return; /* no more events */
307
308             msg_Err( p_access, "reading frontend event failed (%d): %m",
309                      i_ret );
310             return;
311         }
312
313         i_status = event.status;
314         i_diff = i_status ^ p_frontend->i_last_status;
315         p_frontend->i_last_status = i_status;
316
317         {
318 #define IF_UP( x )                                                          \
319         }                                                                   \
320         if ( i_diff & (x) )                                                 \
321         {                                                                   \
322             if ( i_status & (x) )
323
324             IF_UP( FE_HAS_SIGNAL )
325                 msg_Dbg( p_access, "frontend has acquired signal" );
326             else
327                 msg_Dbg( p_access, "frontend has lost signal" );
328
329             IF_UP( FE_HAS_CARRIER )
330                 msg_Dbg( p_access, "frontend has acquired carrier" );
331             else
332                 msg_Dbg( p_access, "frontend has lost carrier" );
333
334             IF_UP( FE_HAS_VITERBI )
335                 msg_Dbg( p_access, "frontend has acquired stable FEC" );
336             else
337                 msg_Dbg( p_access, "frontend has lost FEC" );
338
339             IF_UP( FE_HAS_SYNC )
340                 msg_Dbg( p_access, "frontend has acquired sync" );
341             else
342                 msg_Dbg( p_access, "frontend has lost sync" );
343
344             IF_UP( FE_HAS_LOCK )
345             {
346                 frontend_statistic_t stat;
347
348                 msg_Dbg( p_access, "frontend has acquired lock" );
349                 p_sys->i_frontend_timeout = 0;
350
351                 /* Read some statistics */
352                 if( !FrontendGetStatistic( p_access, &stat ) )
353                 {
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 );
360                 }
361             }
362             else
363             {
364                 msg_Dbg( p_access, "frontend has lost lock" );
365                 p_sys->i_frontend_timeout = mdate() + FRONTEND_LOCK_TIMEOUT;
366             }
367
368             IF_UP( FE_REINIT )
369             {
370                 /* The frontend was reinited. */
371                 msg_Warn( p_access, "reiniting frontend");
372                 FrontendSet( p_access );
373             }
374         }
375 #undef IF_UP
376     }
377 }
378
379 int FrontendGetStatistic( access_t *p_access, frontend_statistic_t *p_stat )
380 {
381     access_sys_t *p_sys = p_access->p_sys;
382     frontend_t * p_frontend = p_sys->p_frontend;
383
384     if( (p_frontend->i_last_status & FE_HAS_LOCK) == 0 )
385         return VLC_EGENERIC;
386
387     memset( p_stat, 0, sizeof(*p_stat) );
388     if( ioctl( p_sys->i_frontend_handle, FE_READ_BER, &p_stat->i_ber ) < 0 )
389         p_stat->i_ber = -1;
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 )
393         p_stat->i_snr = -1;
394
395     return VLC_SUCCESS;
396 }
397
398 void FrontendGetStatus( access_t *p_access, frontend_status_t *p_status )
399 {
400     access_sys_t *p_sys = p_access->p_sys;
401     frontend_t * p_frontend = p_sys->p_frontend;
402
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;
406 }
407
408 static int ScanParametersDvbS( access_t *p_access, scan_parameter_t *p_scan )
409 {
410     const frontend_t *p_frontend = p_access->p_sys->p_frontend;
411
412     memset( p_scan, 0, sizeof(*p_scan) );
413     p_scan->type = SCAN_DVB_S;
414
415     p_scan->frequency.i_min = p_frontend->info.frequency_min;
416     p_scan->frequency.i_max = p_frontend->info.frequency_max;
417
418     return VLC_SUCCESS;
419 }
420
421 static int ScanParametersDvbC( access_t *p_access, scan_parameter_t *p_scan )
422 {
423     const frontend_t *p_frontend = p_access->p_sys->p_frontend;
424
425
426     memset( p_scan, 0, sizeof(*p_scan) );
427     p_scan->type = SCAN_DVB_C;
428     p_scan->b_exhaustive = false;
429
430     /* */
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;
436
437     /* */
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;
442     return VLC_SUCCESS;
443 }
444
445 static int ScanParametersDvbT( access_t *p_access, scan_parameter_t *p_scan )
446 {
447     const frontend_t *p_frontend = p_access->p_sys->p_frontend;
448
449
450     memset( p_scan, 0, sizeof(*p_scan) );
451     p_scan->type = SCAN_DVB_T;
452     p_scan->b_exhaustive = false;
453
454     /* */
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;
460
461     /* */
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;
466     return VLC_SUCCESS;
467 }
468
469 int  FrontendGetScanParameter( access_t *p_access, scan_parameter_t *p_scan )
470 {
471     access_sys_t *p_sys = p_access->p_sys;
472     const frontend_t *p_frontend = p_sys->p_frontend;
473
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 */
480
481     msg_Err( p_access, "Frontend type not supported for scanning" );
482     return VLC_EGENERIC;
483 }
484
485 #ifdef ENABLE_HTTPD
486 /*****************************************************************************
487  * FrontendStatus : Read frontend status
488  *****************************************************************************/
489 void FrontendStatus( access_t *p_access )
490 {
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;
495     int i_ret;
496
497     /* Determine type of frontend */
498     if( (i_ret = ioctl( p_sys->i_frontend_handle, FE_GET_INFO,
499                         &p_frontend->info )) < 0 )
500     {
501         char buf[1000];
502         strerror_r( errno, buf, sizeof( buf ) );
503         p += sprintf( p, "ioctl FE_GET_INFO failed (%d) %s\n", i_ret, buf );
504         goto out;
505     }
506
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 )
511     {
512         case FE_QPSK:
513             p += sprintf( p, "<tr><th>type</th><td>QPSK (DVB-S)</td></tr>\n" );
514             break;
515         case FE_QAM:
516             p += sprintf( p, "<tr><th>type</th><td>QAM (DVB-C)</td></tr>\n" );
517             break;
518         case FE_OFDM:
519             p += sprintf( p, "<tr><th>type</th><td>OFDM (DVB-T)</td></tr>\n" );
520             break;
521 #if 0 /* DVB_API_VERSION == 3 */
522         case FE_MEMORY:
523             p += sprintf( p, "<tr><th>type</th><td>MEMORY</td></tr>\n" );
524             break;
525         case FE_NET:
526             p += sprintf( p, "<tr><th>type</th><td>NETWORK</td></tr>\n" );
527             break;
528 #endif
529         default:
530             p += sprintf( p, "<tr><th>type</th><td>UNKNOWN (%d)</td></tr>\n",
531                           p_frontend->info.type );
532             goto out;
533     }
534 #define CHECK_INFO( x )                                                     \
535     p += sprintf( p,                                                        \
536                   "<tr><th>" STRINGIFY(x) "</th><td>%u</td></tr>\n",        \
537                   p_frontend->info.x );
538
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 );
547 #undef CHECK_INFO
548
549     p += sprintf( p, "</table><p>Frontend capability list:\n<table border=1>" );
550
551 #define CHECK_CAPS( x )                                                     \
552     if ( p_frontend->info.caps & (FE_##x) )                                 \
553         p += sprintf( p, "<tr><td>" STRINGIFY(x) "</td></tr>\n" );
554
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 );
581 #endif
582 #undef CHECK_CAPS
583
584     p += sprintf( p, "</table><p>Current frontend status:\n<table border=1>" );
585
586     if( (i_ret = ioctl( p_sys->i_frontend_handle, FE_READ_STATUS, &i_status ))
587            < 0 )
588     {
589         char buf[1000];
590         strerror_r( errno, buf, sizeof( buf ) );
591         p += sprintf( p, "</table>ioctl FE_READ_STATUS failed (%d) %s\n",
592                       i_ret, buf );
593         goto out;
594     }
595
596 #define CHECK_STATUS( x )                                                   \
597     if ( i_status & (FE_##x) )                                              \
598         p += sprintf( p, "<tr><td>" STRINGIFY(x) "</td></tr>\n" );
599
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 );
606     if( i_status == 0 )
607         p += sprintf( p, "<tr><td>Tuning failed</td></tr>\n" );
608 #undef CHECK_STATUS
609
610     if ( i_status & FE_HAS_LOCK )
611     {
612         int32_t i_value;
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",
616                           i_value );
617         if( ioctl( p_sys->i_frontend_handle, FE_READ_SIGNAL_STRENGTH,
618                    &i_value ) >= 0 )
619             p += sprintf( p, "<tr><th>Signal strength</th><td>%d</td></tr>\n",
620                           i_value );
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",
623                           i_value );
624     }
625     p += sprintf( p, "</table>" );
626
627 out:
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 );
632 }
633 #endif
634
635 /*****************************************************************************
636  * FrontendInfo : Return information about given frontend
637  *****************************************************************************/
638 static int FrontendInfo( access_t *p_access )
639 {
640     access_sys_t *p_sys = p_access->p_sys;
641     frontend_t *p_frontend = p_sys->p_frontend;
642     int i_ret;
643
644     /* Determine type of frontend */
645     if( (i_ret = ioctl( p_sys->i_frontend_handle, FE_GET_INFO,
646                         &p_frontend->info )) < 0 )
647     {
648         msg_Err( p_access, "ioctl FE_GET_INFO failed (%d): %m", i_ret );
649         return VLC_EGENERIC;
650     }
651
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 )
656     {
657         case FE_QPSK:
658             msg_Dbg( p_access, "  type = QPSK (DVB-S)" );
659             break;
660         case FE_QAM:
661             msg_Dbg( p_access, "  type = QAM (DVB-C)" );
662             break;
663         case FE_OFDM:
664             msg_Dbg( p_access, "  type = OFDM (DVB-T)" );
665             break;
666         case FE_ATSC:
667             msg_Dbg( p_access, "  type = ATSC (USA)" );
668             break;
669 #if 0 /* DVB_API_VERSION == 3 */
670         case FE_MEMORY:
671             msg_Dbg(p_access, "  type = MEMORY" );
672             break;
673         case FE_NET:
674             msg_Dbg(p_access, "  type = NETWORK" );
675             break;
676 #endif
677         default:
678             msg_Err( p_access, "  unknown frontend type (%d)",
679                      p_frontend->info.type );
680             return VLC_EGENERIC;
681     }
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 );
698
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");
753
754     return VLC_SUCCESS;
755 }
756
757 /*****************************************************************************
758  * Decoding the DVB parameters (common)
759  *****************************************************************************/
760 static fe_spectral_inversion_t DecodeInversion( access_t *p_access )
761 {
762     int i_val;
763     fe_spectral_inversion_t fe_inversion = 0;
764
765     i_val = var_GetInteger( p_access, "dvb-inversion" );
766     msg_Dbg( p_access, "using inversion=%d", i_val );
767
768     switch( i_val )
769     {
770         case 0: fe_inversion = INVERSION_OFF; break;
771         case 1: fe_inversion = INVERSION_ON; break;
772         case 2: fe_inversion = INVERSION_AUTO; break;
773         default:
774             msg_Dbg( p_access, "dvb has inversion not set, using auto");
775             fe_inversion = INVERSION_AUTO;
776             break;
777     }
778     return fe_inversion;
779 }
780
781 static fe_code_rate_t DecodeFEC( access_t *p_access, int i_val )
782 {
783     fe_code_rate_t fe_fec = FEC_NONE;
784
785     msg_Dbg( p_access, "using fec=%d", i_val );
786
787     switch( i_val )
788     {
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;
799         default:
800             /* cannot happen */
801             fe_fec = FEC_NONE;
802             msg_Err( p_access, "argument has invalid FEC (%d)", i_val);
803             break;
804     }
805     return fe_fec;
806 }
807
808 static fe_modulation_t DecodeModulationQAM( access_t *p_access )
809 {
810     switch( var_GetInteger( p_access, "dvb-modulation" ) )
811     {
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;
818         default:
819             msg_Dbg( p_access, "QAM modulation not set, using auto");
820             return QAM_AUTO;
821     }
822 }
823 static fe_modulation_t DecodeModulationOFDM( access_t *p_access )
824 {
825     switch( var_GetInteger( p_access, "dvb-modulation" ) )
826     {
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;
834         default:
835             msg_Dbg( p_access, "OFDM modulation not set, using QAM auto");
836             return QAM_AUTO;
837     }
838 }
839
840 static fe_modulation_t DecodeModulationATSC( access_t *p_access )
841 {
842     switch( var_GetInteger( p_access, "dvb-modulation" ) )
843     {
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;
851         default:
852             msg_Dbg( p_access, "ATSC modulation not set, using VSB 8");
853             return VSB_8;
854     }
855 }
856
857 /*****************************************************************************
858  * FrontendSetQPSK : controls the FE device
859  *****************************************************************************/
860 static fe_sec_voltage_t DecodeVoltage( access_t *p_access )
861 {
862     int i_val;
863     fe_sec_voltage_t    fe_voltage;
864
865     i_val = var_GetInteger( p_access, "dvb-voltage" );
866     msg_Dbg( p_access, "using voltage=%d", i_val );
867
868     switch( i_val )
869     {
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;
873         default:
874             fe_voltage = SEC_VOLTAGE_OFF;
875             msg_Err( p_access, "argument has invalid voltage (%d)", i_val );
876             break;
877     }
878     return fe_voltage;
879 }
880
881 static fe_sec_tone_mode_t DecodeTone( access_t *p_access )
882 {
883     int i_val;
884     fe_sec_tone_mode_t  fe_tone;
885
886     i_val = var_GetInteger( p_access, "dvb-tone" );
887     msg_Dbg( p_access, "using tone=%d", i_val );
888
889     switch( i_val )
890     {
891         case 0: fe_tone = SEC_TONE_OFF; break;
892         case 1: fe_tone = SEC_TONE_ON; break;
893         default:
894             fe_tone = SEC_TONE_OFF;
895             msg_Err( p_access, "argument has invalid tone mode (%d)", i_val );
896             break;
897     }
898     return fe_tone;
899 }
900
901 struct diseqc_cmd_t
902 {
903     struct dvb_diseqc_master_cmd cmd;
904     uint32_t wait;
905 };
906
907 static int DoDiseqc( access_t *p_access )
908 {
909     access_sys_t *p_sys = p_access->p_sys;
910     int i_val;
911     bool b_val;
912     int i_frequency, i_lnb_slof;
913     fe_sec_voltage_t fe_voltage;
914     fe_sec_tone_mode_t fe_tone;
915     int i_err;
916
917     i_frequency = var_GetInteger( p_access, "dvb-frequency" );
918     i_lnb_slof = var_GetInteger( p_access, "dvb-lnb-slof" );
919
920     i_val = var_GetInteger( p_access, "dvb-tone" );
921     if( i_val == -1 /* auto */ )
922     {
923         if( i_frequency >= i_lnb_slof )
924             i_val = 1;
925         else
926             i_val = 0;
927         var_SetInteger( p_access, "dvb-tone", i_val );
928     }
929
930     fe_voltage = DecodeVoltage( p_access );
931     fe_tone = DecodeTone( p_access );
932
933     /* Switch off continuous tone. */
934     if( (i_err = ioctl( p_sys->i_frontend_handle, FE_SET_TONE, SEC_TONE_OFF )) < 0 )
935     {
936         msg_Err( p_access, "ioctl FE_SET_TONE failed, tone=%s (%d) %m",
937                  fe_tone == SEC_TONE_ON ? "on" : "off", i_err );
938         return i_err;
939     }
940
941     /* Configure LNB voltage. */
942     if( (i_err = ioctl( p_sys->i_frontend_handle, FE_SET_VOLTAGE, fe_voltage )) < 0 )
943     {
944         msg_Err( p_access, "ioctl FE_SET_VOLTAGE failed, voltage=%d (%d) %m",
945                  fe_voltage, i_err );
946         return i_err;
947     }
948
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 )
952     {
953         msg_Err( p_access,
954                  "ioctl FE_ENABLE_HIGH_LNB_VOLTAGE failed, val=%d (%d) %m",
955                  b_val, i_err );
956     }
957
958     /* Wait for at least 15 ms. */
959     msleep(15000);
960
961     i_val = var_GetInteger( p_access, "dvb-satno" );
962     if( i_val > 0 && i_val < 5 )
963     {
964         /* digital satellite equipment control,
965          * specification is available from http://www.eutelsat.com/
966          */
967
968         /* 1.x compatible equipment */
969         struct diseqc_cmd_t cmd =  { {{0xe0, 0x10, 0x38, 0xf0, 0x00, 0x00}, 4}, 0 };
970
971         /* param: high nibble: reset bits, low nibble set bits,
972          * bits are: option, position, polarization, band
973          */
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);
978
979         if( (i_err = ioctl( p_sys->i_frontend_handle, FE_DISEQC_SEND_MASTER_CMD,
980                            &cmd.cmd )) < 0 )
981         {
982             msg_Err( p_access, "ioctl FE_SEND_MASTER_CMD failed (%d) %m",
983                      i_err );
984             return i_err;
985         }
986
987         msleep(15000 + cmd.wait * 1000);
988
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 )
992         {
993             msg_Err( p_access, "ioctl FE_SEND_BURST failed (%d) %m",
994                      i_err );
995             return i_err;
996         }
997
998         msleep(15000);
999     }
1000
1001     if( (i_err = ioctl( p_sys->i_frontend_handle, FE_SET_TONE, fe_tone )) < 0 )
1002     {
1003         msg_Err( p_access, "ioctl FE_SET_TONE failed, tone=%s (%d) %m",
1004                  fe_tone == SEC_TONE_ON ? "on" : "off", i_err );
1005         return i_err;
1006     }
1007
1008     msleep(50000);
1009     return 0;
1010 }
1011
1012 static int FrontendSetQPSK( access_t *p_access )
1013 {
1014     access_sys_t *p_sys = p_access->p_sys;
1015     struct dvb_frontend_parameters fep;
1016     int i_ret;
1017     int i_val;
1018     int i_frequency, i_lnb_slof = 0, i_lnb_lof1, i_lnb_lof2 = 0;
1019
1020     /* Prepare the fep structure */
1021     i_frequency = var_GetInteger( p_access, "dvb-frequency" );
1022
1023     i_val = var_GetInteger( p_access, "dvb-lnb-lof1" );
1024     if( i_val == 0 )
1025     {
1026         /* Automatic mode. */
1027         if ( i_frequency >= 950000 && i_frequency <= 2150000 )
1028         {
1029             msg_Dbg( p_access, "frequency %d is in IF-band", i_frequency );
1030             i_lnb_lof1 = 0;
1031         }
1032         else if ( i_frequency >= 2500000 && i_frequency <= 2700000 )
1033         {
1034             msg_Dbg( p_access, "frequency %d is in S-band", i_frequency );
1035             i_lnb_lof1 = 3650000;
1036         }
1037         else if ( i_frequency >= 3400000 && i_frequency <= 4200000 )
1038         {
1039             msg_Dbg( p_access, "frequency %d is in C-band (lower)",
1040                      i_frequency );
1041             i_lnb_lof1 = 5150000;
1042         }
1043         else if ( i_frequency >= 4500000 && i_frequency <= 4800000 )
1044         {
1045             msg_Dbg( p_access, "frequency %d is in C-band (higher)",
1046                      i_frequency );
1047             i_lnb_lof1 = 5950000;
1048         }
1049         else if ( i_frequency >= 10700000 && i_frequency <= 13250000 )
1050         {
1051             msg_Dbg( p_access, "frequency %d is in Ku-band",
1052                      i_frequency );
1053             i_lnb_lof1 = 9750000;
1054             i_lnb_lof2 = 10600000;
1055             i_lnb_slof = 11700000;
1056         }
1057         else
1058         {
1059             msg_Err( p_access, "frequency %d is out of any known band",
1060                      i_frequency );
1061             msg_Err( p_access, "specify dvb-lnb-lof1 manually for the local "
1062                      "oscillator frequency" );
1063             return VLC_EGENERIC;
1064         }
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 );
1068     }
1069     else
1070     {
1071         i_lnb_lof1 = i_val;
1072         i_lnb_lof2 = var_GetInteger( p_access, "dvb-lnb-lof2" );
1073         i_lnb_slof = var_GetInteger( p_access, "dvb-lnb-slof" );
1074     }
1075
1076     if( i_lnb_slof && i_frequency >= i_lnb_slof )
1077     {
1078         i_frequency -= i_lnb_lof2;
1079     }
1080     else
1081     {
1082         i_frequency -= i_lnb_lof1;
1083     }
1084     fep.frequency = i_frequency >= 0 ? i_frequency : -i_frequency;
1085
1086     fep.inversion = DecodeInversion( p_access );
1087
1088     fep.u.qpsk.symbol_rate = var_GetInteger( p_access, "dvb-srate" );
1089
1090     fep.u.qpsk.fec_inner = DecodeFEC( p_access, var_GetInteger( p_access, "dvb-fec" ) );
1091
1092     if( DoDiseqc( p_access ) < 0 )
1093     {
1094         return VLC_EGENERIC;
1095     }
1096
1097     /* Empty the event queue */
1098     for( ; ; )
1099     {
1100         struct dvb_frontend_event event;
1101         if ( ioctl( p_sys->i_frontend_handle, FE_GET_EVENT, &event ) < 0
1102               && errno == EWOULDBLOCK )
1103             break;
1104     }
1105
1106     /* Now send it all to the frontend device */
1107     if( (i_ret = ioctl( p_sys->i_frontend_handle, FE_SET_FRONTEND, &fep )) < 0 )
1108     {
1109         msg_Err( p_access, "DVB-S: setting frontend failed (%d) %m", i_ret );
1110         return VLC_EGENERIC;
1111     }
1112
1113     return VLC_SUCCESS;
1114 }
1115
1116 /*****************************************************************************
1117  * FrontendSetQAM : controls the FE device
1118  *****************************************************************************/
1119 static int FrontendSetQAM( access_t *p_access )
1120 {
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;
1124     int i_val;
1125     int i_ret;
1126
1127     /* Prepare the fep structure */
1128
1129     fep.frequency = var_GetInteger( p_access, "dvb-frequency" );
1130
1131     fep.inversion = DecodeInversion( p_access );
1132
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
1136      */
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;
1141     else
1142         fep.u.qam.symbol_rate = 6875000;
1143
1144     fep.u.qam.fec_inner = DecodeFEC( p_access, var_GetInteger( p_access,
1145                                                                "dvb-fec" ) );
1146
1147     fep.u.qam.modulation = DecodeModulationQAM( p_access );
1148
1149     /* Empty the event queue */
1150     for( ; ; )
1151     {
1152         struct dvb_frontend_event event;
1153         if ( ioctl( p_sys->i_frontend_handle, FE_GET_EVENT, &event ) < 0
1154               && errno == EWOULDBLOCK )
1155             break;
1156     }
1157
1158     /* Now send it all to the frontend device */
1159     if( (i_ret = ioctl( p_sys->i_frontend_handle, FE_SET_FRONTEND, &fep )) < 0 )
1160     {
1161         msg_Err( p_access, "DVB-C: setting frontend failed (%d): %m", i_ret );
1162         return VLC_EGENERIC;
1163     }
1164
1165     return VLC_SUCCESS;
1166 }
1167
1168 /*****************************************************************************
1169  * FrontendSetOFDM : controls the FE device
1170  *****************************************************************************/
1171 static fe_bandwidth_t DecodeBandwidth( access_t *p_access )
1172 {
1173     fe_bandwidth_t      fe_bandwidth = 0;
1174     int i_bandwith = var_GetInteger( p_access, "dvb-bandwidth" );
1175
1176     msg_Dbg( p_access, "using bandwidth=%d", i_bandwith );
1177
1178     switch( i_bandwith )
1179     {
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;
1184         default:
1185             msg_Dbg( p_access, "terrestrial dvb has bandwidth not set, using auto" );
1186             fe_bandwidth = BANDWIDTH_AUTO;
1187             break;
1188     }
1189     return fe_bandwidth;
1190 }
1191
1192 static fe_transmit_mode_t DecodeTransmission( access_t *p_access )
1193 {
1194     fe_transmit_mode_t  fe_transmission = 0;
1195     int i_transmission = var_GetInteger( p_access, "dvb-transmission" );
1196
1197     msg_Dbg( p_access, "using transmission=%d", i_transmission );
1198
1199     switch( i_transmission )
1200     {
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;
1204         default:
1205             msg_Dbg( p_access, "terrestrial dvb has transmission mode not set, using auto");
1206             fe_transmission = TRANSMISSION_MODE_AUTO;
1207             break;
1208     }
1209     return fe_transmission;
1210 }
1211
1212 static fe_guard_interval_t DecodeGuardInterval( access_t *p_access )
1213 {
1214     fe_guard_interval_t fe_guard = 0;
1215     int i_guard = var_GetInteger( p_access, "dvb-guard" );
1216
1217     msg_Dbg( p_access, "using guard=%d", i_guard );
1218
1219     switch( i_guard )
1220     {
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;
1226         default:
1227             msg_Dbg( p_access, "terrestrial dvb has guard interval not set, using auto");
1228             fe_guard = GUARD_INTERVAL_AUTO;
1229             break;
1230     }
1231     return fe_guard;
1232 }
1233
1234 static fe_hierarchy_t DecodeHierarchy( access_t *p_access )
1235 {
1236     fe_hierarchy_t      fe_hierarchy = 0;
1237     int i_hierarchy = var_GetInteger( p_access, "dvb-hierarchy" );
1238
1239     msg_Dbg( p_access, "using hierarchy=%d", i_hierarchy );
1240
1241     switch( i_hierarchy )
1242     {
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;
1248         default:
1249             msg_Dbg( p_access, "terrestrial dvb has hierarchy not set, using auto");
1250             fe_hierarchy = HIERARCHY_AUTO;
1251             break;
1252     }
1253     return fe_hierarchy;
1254 }
1255
1256 static int FrontendSetOFDM( access_t * p_access )
1257 {
1258     access_sys_t *p_sys = p_access->p_sys;
1259     struct dvb_frontend_parameters fep;
1260     int ret;
1261
1262     /* Prepare the fep structure */
1263
1264     fep.frequency = var_GetInteger( p_access, "dvb-frequency" );
1265
1266     fep.inversion = DecodeInversion( p_access );
1267
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 );
1277
1278     /* Empty the event queue */
1279     for( ; ; )
1280     {
1281         struct dvb_frontend_event event;
1282         if ( ioctl( p_sys->i_frontend_handle, FE_GET_EVENT, &event ) < 0
1283               && errno == EWOULDBLOCK )
1284             break;
1285     }
1286
1287     /* Now send it all to the frontend device */
1288     if( (ret = ioctl( p_sys->i_frontend_handle, FE_SET_FRONTEND, &fep )) < 0 )
1289     {
1290         msg_Err( p_access, "DVB-T: setting frontend failed (%d): %m", ret );
1291         return -1;
1292     }
1293
1294     return VLC_SUCCESS;
1295 }
1296
1297 /*****************************************************************************
1298  * FrontendSetATSC : controls the FE device
1299  *****************************************************************************/
1300 static int FrontendSetATSC( access_t *p_access )
1301 {
1302     access_sys_t *p_sys = p_access->p_sys;
1303     struct dvb_frontend_parameters fep;
1304     int i_ret;
1305
1306     /* Prepare the fep structure */
1307
1308     fep.frequency = var_GetInteger( p_access, "dvb-frequency" );
1309
1310     fep.u.vsb.modulation = DecodeModulationATSC( p_access );
1311
1312     /* Empty the event queue */
1313     for( ; ; )
1314     {
1315         struct dvb_frontend_event event;
1316         if ( ioctl( p_sys->i_frontend_handle, FE_GET_EVENT, &event ) < 0
1317               && errno == EWOULDBLOCK )
1318             break;
1319     }
1320
1321     /* Now send it all to the frontend device */
1322     if( (i_ret = ioctl( p_sys->i_frontend_handle, FE_SET_FRONTEND, &fep )) < 0 )
1323     {
1324         msg_Err( p_access, "ATSC: setting frontend failed (%d): %m", i_ret );
1325         return VLC_EGENERIC;
1326     }
1327
1328     return VLC_SUCCESS;
1329 }
1330
1331
1332 /*
1333  * Demux
1334  */
1335
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 )
1340 {
1341     struct dmx_pes_filter_params s_filter_params;
1342     int i_ret;
1343     unsigned int i_adapter, i_device;
1344     char dmx[128];
1345
1346     i_adapter = var_GetInteger( p_access, "dvb-adapter" );
1347     i_device = var_GetInteger( p_access, "dvb-device" );
1348
1349     if( snprintf( dmx, sizeof(dmx), DMX, i_adapter, i_device )
1350             >= (int)sizeof(dmx) )
1351     {
1352         msg_Err( p_access, "snprintf() truncated string for DMX" );
1353         dmx[sizeof(dmx) - 1] = '\0';
1354     }
1355
1356     msg_Dbg( p_access, "Opening device %s", dmx );
1357     if( (*pi_fd = vlc_open(dmx, O_RDWR)) < 0 )
1358     {
1359         msg_Err( p_access, "DMXSetFilter: opening device failed (%m)" );
1360         return VLC_EGENERIC;
1361     }
1362
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;
1368
1369     switch ( i_type )
1370     {   /* First device */
1371         case 1:
1372             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_VIDEO0 for PID %d", i_pid);
1373             s_filter_params.pes_type = DMX_PES_VIDEO0;
1374             break;
1375         case 2:
1376             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_AUDIO0 for PID %d", i_pid);
1377             s_filter_params.pes_type = DMX_PES_AUDIO0;
1378             break;
1379         case 3:
1380             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_TELETEXT0 for PID %d", i_pid);
1381             s_filter_params.pes_type = DMX_PES_TELETEXT0;
1382             break;
1383         case 4:
1384             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_SUBTITLE0 for PID %d", i_pid);
1385             s_filter_params.pes_type = DMX_PES_SUBTITLE0;
1386             break;
1387         case 5:
1388             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_PCR0 for PID %d", i_pid);
1389             s_filter_params.pes_type = DMX_PES_PCR0;
1390             break;
1391         /* Second device */
1392         case 6:
1393             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_VIDEO1 for PID %d", i_pid);
1394             s_filter_params.pes_type = DMX_PES_VIDEO1;
1395             break;
1396         case 7:
1397             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_AUDIO1 for PID %d", i_pid);
1398             s_filter_params.pes_type = DMX_PES_AUDIO1;
1399             break;
1400         case 8:
1401             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_TELETEXT1 for PID %d", i_pid);
1402             s_filter_params.pes_type = DMX_PES_TELETEXT1;
1403             break;
1404         case 9:
1405             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_SUBTITLE1 for PID %d", i_pid);
1406             s_filter_params.pes_type = DMX_PES_SUBTITLE1;
1407             break;
1408         case 10:
1409             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_PCR1 for PID %d", i_pid);
1410             s_filter_params.pes_type = DMX_PES_PCR1;
1411             break;
1412         /* Third device */
1413         case 11:
1414             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_VIDEO2 for PID %d", i_pid);
1415             s_filter_params.pes_type = DMX_PES_VIDEO2;
1416             break;
1417         case 12:
1418             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_AUDIO2 for PID %d", i_pid);
1419             s_filter_params.pes_type = DMX_PES_AUDIO2;
1420             break;
1421         case 13:
1422             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_TELETEXT2 for PID %d", i_pid);
1423             s_filter_params.pes_type = DMX_PES_TELETEXT2;
1424             break;
1425         case 14:
1426             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_SUBTITLE2 for PID %d", i_pid);
1427             s_filter_params.pes_type = DMX_PES_SUBTITLE2;
1428             break;
1429         case 15:
1430             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_PCR2 for PID %d", i_pid);
1431             s_filter_params.pes_type = DMX_PES_PCR2;
1432             break;
1433         /* Forth device */
1434         case 16:
1435             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_VIDEO3 for PID %d", i_pid);
1436             s_filter_params.pes_type = DMX_PES_VIDEO3;
1437             break;
1438         case 17:
1439             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_AUDIO3 for PID %d", i_pid);
1440             s_filter_params.pes_type = DMX_PES_AUDIO3;
1441             break;
1442         case 18:
1443             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_TELETEXT3 for PID %d", i_pid);
1444             s_filter_params.pes_type = DMX_PES_TELETEXT3;
1445             break;
1446         case 19:
1447             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_SUBTITLE3 for PID %d", i_pid);
1448             s_filter_params.pes_type = DMX_PES_SUBTITLE3;
1449             break;
1450         case 20:
1451             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_PCR3 for PID %d", i_pid);
1452             s_filter_params.pes_type = DMX_PES_PCR3;
1453             break;
1454         /* Usually used by Nova cards */
1455         case 21:
1456         default:
1457             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_OTHER for PID %d", i_pid);
1458             s_filter_params.pes_type = DMX_PES_OTHER;
1459             break;
1460     }
1461
1462     /* We then give the order to the device : */
1463     if( (i_ret = ioctl( *pi_fd, DMX_SET_PES_FILTER, &s_filter_params )) < 0 )
1464     {
1465         msg_Err( p_access, "DMXSetFilter: failed with %d (%m)", i_ret );
1466         return VLC_EGENERIC;
1467     }
1468     return VLC_SUCCESS;
1469 }
1470
1471 /*****************************************************************************
1472  * DMXUnsetFilter : removes a filter
1473  *****************************************************************************/
1474 int DMXUnsetFilter( access_t * p_access, int i_fd )
1475 {
1476     int i_ret;
1477
1478     if( (i_ret = ioctl( i_fd, DMX_STOP )) < 0 )
1479     {
1480         msg_Err( p_access, "DMX_STOP failed for demux (%d): %m", i_ret );
1481         return i_ret;
1482     }
1483
1484     msg_Dbg( p_access, "DMXUnsetFilter: closing demux %d", i_fd );
1485     close( i_fd );
1486     return VLC_SUCCESS;
1487 }
1488
1489
1490 /*
1491  * DVR device
1492  */
1493
1494 /*****************************************************************************
1495  * DVROpen :
1496  *****************************************************************************/
1497 int DVROpen( access_t * p_access )
1498 {
1499     access_sys_t *p_sys = p_access->p_sys;
1500     unsigned int i_adapter, i_device;
1501     char dvr[128];
1502
1503     i_adapter = var_GetInteger( p_access, "dvb-adapter" );
1504     i_device = var_GetInteger( p_access, "dvb-device" );
1505
1506     if( snprintf( dvr, sizeof(dvr), DVR, i_adapter, i_device )
1507             >= (int)sizeof(dvr) )
1508     {
1509         msg_Err( p_access, "snprintf() truncated string for DVR" );
1510         dvr[sizeof(dvr) - 1] = '\0';
1511     }
1512
1513     msg_Dbg( p_access, "Opening device %s", dvr );
1514     if( (p_sys->i_handle = vlc_open(dvr, O_RDONLY)) < 0 )
1515     {
1516         msg_Err( p_access, "DVROpen: opening device failed (%m)" );
1517         return VLC_EGENERIC;
1518     }
1519
1520     if( fcntl( p_sys->i_handle, F_SETFL, O_NONBLOCK ) == -1 )
1521     {
1522         msg_Warn( p_access, "DVROpen: couldn't set non-blocking mode (%m)" );
1523     }
1524
1525     return VLC_SUCCESS;
1526 }
1527
1528 /*****************************************************************************
1529  * DVRClose :
1530  *****************************************************************************/
1531 void DVRClose( access_t * p_access )
1532 {
1533     access_sys_t *p_sys = p_access->p_sys;
1534
1535     close( p_sys->i_handle );
1536 }
1537
1538
1539 /*
1540  * CAM device
1541  */
1542
1543 /*****************************************************************************
1544  * CAMOpen :
1545  *****************************************************************************/
1546 int CAMOpen( access_t *p_access )
1547 {
1548     access_sys_t *p_sys = p_access->p_sys;
1549     char ca[128];
1550     int i_adapter, i_device;
1551     ca_caps_t caps;
1552
1553     i_adapter = var_GetInteger( p_access, "dvb-adapter" );
1554     i_device = var_GetInteger( p_access, "dvb-device" );
1555
1556     if( snprintf( ca, sizeof(ca), CA, i_adapter, i_device ) >= (int)sizeof(ca) )
1557     {
1558         msg_Err( p_access, "snprintf() truncated string for CA" );
1559         ca[sizeof(ca) - 1] = '\0';
1560     }
1561     memset( &caps, 0, sizeof( ca_caps_t ));
1562
1563     msg_Dbg( p_access, "Opening device %s", ca );
1564     if( (p_sys->i_ca_handle = vlc_open(ca, O_RDWR | O_NONBLOCK)) < 0 )
1565     {
1566         msg_Warn( p_access, "CAMInit: opening CAM device failed (%m)" );
1567         p_sys->i_ca_handle = 0;
1568         return VLC_EGENERIC;
1569     }
1570
1571     if ( ioctl( p_sys->i_ca_handle, CA_GET_CAP, &caps ) != 0 )
1572     {
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;
1577     }
1578
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" );
1592
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" );
1601  
1602     if ( caps.slot_num == 0 )
1603     {
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;
1608     }
1609
1610     if( caps.slot_type & CA_CI_LINK )
1611     {
1612         p_sys->i_ca_type = CA_CI_LINK;
1613     }
1614     else if( caps.slot_type & CA_CI )
1615     {
1616         p_sys->i_ca_type = CA_CI;
1617     }
1618     else
1619     {
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;
1625     }
1626
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 );
1632
1633     return en50221_Init( p_access );
1634 }
1635
1636 /*****************************************************************************
1637  * CAMPoll :
1638  *****************************************************************************/
1639 int CAMPoll( access_t * p_access )
1640 {
1641     access_sys_t *p_sys = p_access->p_sys;
1642     int i_ret = VLC_EGENERIC;
1643
1644     if ( p_sys->i_ca_handle == 0 )
1645     {
1646         return VLC_EGENERIC;
1647     }
1648
1649     switch( p_sys->i_ca_type )
1650     {
1651     case CA_CI_LINK:
1652         i_ret = en50221_Poll( p_access );
1653         break;
1654     case CA_CI:
1655         i_ret = VLC_SUCCESS;
1656         break;
1657     default:
1658         msg_Err( p_access, "CAMPoll: This should not happen" );
1659         break;
1660     }
1661
1662     return i_ret;
1663 }
1664
1665 #ifdef ENABLE_HTTPD
1666 /*****************************************************************************
1667  * CAMStatus :
1668  *****************************************************************************/
1669 void CAMStatus( access_t * p_access )
1670 {
1671     access_sys_t *p_sys = p_access->p_sys;
1672     char *p;
1673     ca_caps_t caps;
1674     int i_slot, i;
1675
1676     if ( p_sys->psz_request != NULL && *p_sys->psz_request )
1677     {
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++ )
1681         {
1682             if ( p_sys->pb_slot_mmi_undisplayed[i_slot] == true )
1683             {
1684                 p_sys->psz_request = NULL;
1685                 msg_Dbg( p_access,
1686                          "ignoring user request because of a new MMI object" );
1687                 break;
1688             }
1689         }
1690     }
1691
1692     if ( p_sys->psz_request != NULL && *p_sys->psz_request )
1693     {
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];
1698         int i_slot;
1699         bool b_ok = false;
1700
1701         p_sys->psz_request = NULL;
1702
1703         if ( HTTPExtractValue( psz_request, "slot", psz_value,
1704                                    sizeof(psz_value) ) == NULL )
1705         {
1706             p_sys->psz_mmi_info = strdup( "invalid request parameter\n" );
1707             goto out;
1708         }
1709         i_slot = atoi(psz_value);
1710
1711         if ( HTTPExtractValue( psz_request, "open", psz_value,
1712                                    sizeof(psz_value) ) != NULL )
1713         {
1714             en50221_OpenMMI( p_access, i_slot );
1715             return;
1716         }
1717
1718         if ( HTTPExtractValue( psz_request, "close", psz_value,
1719                                    sizeof(psz_value) ) != NULL )
1720         {
1721             en50221_CloseMMI( p_access, i_slot );
1722             return;
1723         }
1724
1725         if ( HTTPExtractValue( psz_request, "cancel", psz_value,
1726                                    sizeof(psz_value) ) == NULL )
1727         {
1728             b_ok = true;
1729         }
1730
1731         if ( HTTPExtractValue( psz_request, "type", psz_value,
1732                                    sizeof(psz_value) ) == NULL )
1733         {
1734             p_sys->psz_mmi_info = strdup( "invalid request parameter\n" );
1735             goto out;
1736         }
1737
1738         if ( !strcmp( psz_value, "enq" ) )
1739         {
1740             mmi_object.i_object_type = EN50221_MMI_ANSW;
1741             mmi_object.u.answ.b_ok = b_ok;
1742             if ( b_ok == false )
1743             {
1744                 mmi_object.u.answ.psz_answ = strdup("");
1745             }
1746             else
1747             {
1748                 if ( HTTPExtractValue( psz_request, "answ", psz_value,
1749                                            sizeof(psz_value) ) == NULL )
1750                 {
1751                     p_sys->psz_mmi_info = strdup( "invalid request parameter\n" );
1752                     goto out;
1753                 }
1754
1755                 mmi_object.u.answ.psz_answ = strdup(psz_value);
1756             }
1757         }
1758         else
1759         {
1760             mmi_object.i_object_type = EN50221_MMI_MENU_ANSW;
1761             if ( b_ok == false )
1762             {
1763                 mmi_object.u.menu_answ.i_choice = 0;
1764             }
1765             else
1766             {
1767                 if ( HTTPExtractValue( psz_request, "choice", psz_value,
1768                                            sizeof(psz_value) ) == NULL )
1769                     mmi_object.u.menu_answ.i_choice = 0;
1770                 else
1771                     mmi_object.u.menu_answ.i_choice = atoi(psz_value);
1772             }
1773         }
1774
1775         en50221_SendMMIObject( p_access, i_slot, &mmi_object );
1776         return;
1777     }
1778
1779     /* Check that we have all necessary MMI information. */
1780     for ( i_slot = 0; i_slot < p_sys->i_nb_slots; i_slot++ )
1781     {
1782         if ( p_sys->pb_slot_mmi_expected[i_slot] == true )
1783             return;
1784     }
1785
1786     p = p_sys->psz_mmi_info = malloc( 10000 );
1787
1788     if ( ioctl( p_sys->i_ca_handle, CA_GET_CAP, &caps ) != 0 )
1789     {
1790         char buf[1000];
1791         strerror_r( errno, buf, sizeof( buf ) );
1792         p += sprintf( p, "ioctl CA_GET_CAP failed (%s)\n", buf );
1793         goto out;
1794     }
1795
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" );
1802
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" );
1808 #undef CHECK_CAPS
1809
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" );
1815
1816     CHECK_DESC( ECD );
1817     CHECK_DESC( NDS );
1818     CHECK_DESC( DSS );
1819 #undef CHECK_DESC
1820
1821     p += sprintf( p, "</table>" );
1822
1823     for ( i_slot = 0; i_slot < p_sys->i_nb_slots; i_slot++ )
1824     {
1825         ca_slot_info_t sinfo;
1826
1827         p_sys->pb_slot_mmi_undisplayed[i_slot] = false;
1828         p += sprintf( p, "<p>CA slot #%d: ", i_slot );
1829
1830         sinfo.num = i_slot;
1831         if ( ioctl( p_sys->i_ca_handle, CA_GET_SLOT_INFO, &sinfo ) != 0 )
1832         {
1833             char buf[1000];
1834             strerror_r( errno, buf, sizeof( buf ) );
1835             p += sprintf( p, "ioctl CA_GET_SLOT_INFO failed (%s)<br>\n", buf );
1836             continue;
1837         }
1838
1839 #define CHECK_TYPE( x, s )                                                  \
1840         if ( sinfo.type & (CA_##x) )                                        \
1841             p += sprintf( p, "%s", s );
1842
1843         CHECK_TYPE( CI, "high level, " );
1844         CHECK_TYPE( CI_LINK, "link layer level, " );
1845         CHECK_TYPE( CI_PHYS, "physical layer level, " );
1846 #undef CHECK_TYPE
1847
1848         if ( sinfo.flags & CA_CI_MODULE_READY )
1849         {
1850             en50221_mmi_object_t *p_object = en50221_GetMMIObject( p_access,
1851                                                                        i_slot );
1852
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",
1856                           i_slot );
1857
1858             if ( p_object == NULL )
1859             {
1860                 p += sprintf( p, "<input type=submit name=open value=\"Open session\">\n" );
1861             }
1862             else
1863             {
1864                 switch ( p_object->i_object_type )
1865                 {
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" );
1872                     else
1873                         p += sprintf( p, "<tr><td><input type=password name=answ></td></tr>\n" );
1874                     break;
1875
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 );
1886                     break;
1887
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 );
1900                     break;
1901
1902                 default:
1903                     p += sprintf( p, "<table><tr><th>Unknown MMI object type</th></tr>\n" );
1904                 }
1905
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" );
1909             }
1910             p += sprintf( p, "</form>\n" );
1911         }
1912         else if ( sinfo.flags & CA_CI_MODULE_PRESENT )
1913             p += sprintf( p, "module present, not ready<br>\n" );
1914         else
1915             p += sprintf( p, "module not present<br>\n" );
1916     }
1917
1918 out:
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 );
1923 }
1924 #endif
1925
1926 /*****************************************************************************
1927  * CAMSet :
1928  *****************************************************************************/
1929 int CAMSet( access_t * p_access, dvbpsi_pmt_t *p_pmt )
1930 {
1931     access_sys_t *p_sys = p_access->p_sys;
1932
1933     if( p_sys->i_ca_handle == 0 )
1934     {
1935         dvbpsi_DeletePMT( p_pmt );
1936         return VLC_EGENERIC;
1937     }
1938
1939     en50221_SetCAPMT( p_access, p_pmt );
1940
1941     return VLC_SUCCESS;
1942 }
1943
1944 /*****************************************************************************
1945  * CAMClose :
1946  *****************************************************************************/
1947 void CAMClose( access_t * p_access )
1948 {
1949     access_sys_t *p_sys = p_access->p_sys;
1950
1951     en50221_End( p_access );
1952
1953     if ( p_sys->i_ca_handle )
1954     {
1955         close( p_sys->i_ca_handle );
1956     }
1957 }
1958