]> git.sesse.net Git - vlc/blob - modules/access/dvb/linux_dvb.c
DVB access: kill 3 warnings
[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 # include <dvbpsi/dvbpsi.h>
52 # include <dvbpsi/descriptor.h>
53 # include <dvbpsi/pat.h>
54 # include <dvbpsi/pmt.h>
55 # include <dvbpsi/dr.h>
56 # include <dvbpsi/psi.h>
57 # include <dvbpsi/demux.h>
58 # include <dvbpsi/sdt.h>
59
60 #ifdef ENABLE_HTTPD
61 #   include <vlc_httpd.h>
62 #endif
63
64 #include "dvb.h"
65
66 /*
67  * Frontends
68  */
69 struct frontend_t
70 {
71     fe_status_t i_last_status;
72     struct dvb_frontend_info info;
73 };
74
75 #define FRONTEND_LOCK_TIMEOUT 10000000 /* 10 s */
76
77 /* Local prototypes */
78 static int FrontendInfo( access_t * );
79 static int FrontendSetQPSK( access_t * );
80 static int FrontendSetQAM( access_t * );
81 static int FrontendSetOFDM( access_t * );
82 static int FrontendSetATSC( access_t * );
83
84 /*****************************************************************************
85  * FrontendOpen : Determine frontend device information and capabilities
86  *****************************************************************************/
87 int FrontendOpen( access_t *p_access )
88 {
89     access_sys_t *p_sys = p_access->p_sys;
90     frontend_t * p_frontend;
91     unsigned int i_adapter, i_device;
92     bool b_probe;
93     char frontend[128];
94
95     i_adapter = var_GetInteger( p_access, "dvb-adapter" );
96     i_device = var_GetInteger( p_access, "dvb-device" );
97     b_probe = var_GetBool( p_access, "dvb-probe" );
98
99     if( snprintf( frontend, sizeof(frontend), FRONTEND, i_adapter, i_device ) >= (int)sizeof(frontend) )
100     {
101         msg_Err( p_access, "snprintf() truncated string for FRONTEND" );
102         frontend[sizeof(frontend) - 1] = '\0';
103     }
104
105     p_sys->p_frontend = p_frontend = malloc( sizeof(frontend_t) );
106     if( !p_frontend )
107         return VLC_ENOMEM;
108
109     msg_Dbg( p_access, "Opening device %s", frontend );
110     if( (p_sys->i_frontend_handle = vlc_open(frontend, O_RDWR | O_NONBLOCK)) < 0 )
111     {
112         msg_Err( p_access, "FrontEndOpen: opening device failed (%m)" );
113         free( p_frontend );
114         return VLC_EGENERIC;
115     }
116
117     if( b_probe )
118     {
119         const char * psz_expected = NULL;
120         const char * psz_real;
121
122         if( FrontendInfo( p_access ) < 0 )
123         {
124             close( p_sys->i_frontend_handle );
125             free( p_frontend );
126             return VLC_EGENERIC;
127         }
128
129         switch( p_frontend->info.type )
130         {
131         case FE_OFDM:
132             psz_real = "DVB-T";
133             break;
134         case FE_QAM:
135             psz_real = "DVB-C";
136             break;
137         case FE_QPSK:
138             psz_real = "DVB-S";
139             break;
140         case FE_ATSC:
141             psz_real = "ATSC";
142             break;
143         default:
144             psz_real = "unknown";
145         }
146
147         /* Sanity checks */
148         if( (!strncmp( p_access->psz_access, "qpsk", 4 ) ||
149              !strncmp( p_access->psz_access, "dvb-s", 5 ) ||
150              !strncmp( p_access->psz_access, "satellite", 9 ) ) &&
151              (p_frontend->info.type != FE_QPSK) )
152         {
153             psz_expected = "DVB-S";
154         }
155         if( (!strncmp( p_access->psz_access, "cable", 5 ) ||
156              !strncmp( p_access->psz_access, "dvb-c", 5 ) ) &&
157              (p_frontend->info.type != FE_QAM) )
158         {
159             psz_expected = "DVB-C";
160         }
161         if( (!strncmp( p_access->psz_access, "terrestrial", 11 ) ||
162              !strncmp( p_access->psz_access, "dvb-t", 5 ) ) &&
163              (p_frontend->info.type != FE_OFDM) )
164         {
165             psz_expected = "DVB-T";
166         }
167
168         if( (!strncmp( p_access->psz_access, "usdigital", 9 ) ||
169              !strncmp( p_access->psz_access, "atsc", 4 ) ) &&
170              (p_frontend->info.type != FE_ATSC) )
171         {
172             psz_expected = "ATSC";
173         }
174
175         if( psz_expected != NULL )
176         {
177             msg_Err( p_access, "requested type %s not supported by %s tuner",
178                      psz_expected, psz_real );
179             close( p_sys->i_frontend_handle );
180             free( p_frontend );
181             return VLC_EGENERIC;
182         }
183     }
184     else /* no frontend probing is done so use default border values. */
185     {
186         msg_Dbg( p_access, "using default values for frontend info" );
187
188         msg_Dbg( p_access, "method of access is %s", p_access->psz_access );
189         p_frontend->info.type = FE_QPSK;
190         if( !strncmp( p_access->psz_access, "qpsk", 4 ) ||
191             !strncmp( p_access->psz_access, "dvb-s", 5 ) )
192             p_frontend->info.type = FE_QPSK;
193         else if( !strncmp( p_access->psz_access, "cable", 5 ) ||
194                  !strncmp( p_access->psz_access, "dvb-c", 5 ) )
195             p_frontend->info.type = FE_QAM;
196         else if( !strncmp( p_access->psz_access, "terrestrial", 11 ) ||
197                  !strncmp( p_access->psz_access, "dvb-t", 5 ) )
198             p_frontend->info.type = FE_OFDM;
199         else if( !strncmp( p_access->psz_access, "usdigital", 9 ) ||
200                  !strncmp( p_access->psz_access, "atsc", 4 ) )
201             p_frontend->info.type = FE_ATSC;
202     }
203
204     return VLC_SUCCESS;
205 }
206
207 /*****************************************************************************
208  * FrontendClose : Close the frontend
209  *****************************************************************************/
210 void FrontendClose( access_t *p_access )
211 {
212     access_sys_t *p_sys = p_access->p_sys;
213
214     if( p_sys->p_frontend )
215     {
216         close( p_sys->i_frontend_handle );
217         free( p_sys->p_frontend );
218
219         p_sys->p_frontend = NULL;
220     }
221 }
222
223 /*****************************************************************************
224  * FrontendSet : Tune !
225  *****************************************************************************/
226 int FrontendSet( access_t *p_access )
227 {
228     access_sys_t *p_sys = p_access->p_sys;
229
230     switch( p_sys->p_frontend->info.type )
231     {
232     /* DVB-S */
233     case FE_QPSK:
234         if( FrontendSetQPSK( p_access ) )
235         {
236             msg_Err( p_access, "DVB-S tuning error" );
237             return VLC_EGENERIC;
238         }
239         break;
240
241     /* DVB-C */
242     case FE_QAM:
243         if( FrontendSetQAM( p_access ) )
244         {
245             msg_Err( p_access, "DVB-C tuning error" );
246             return VLC_EGENERIC;
247         }
248         break;
249
250     /* DVB-T */
251     case FE_OFDM:
252         if( FrontendSetOFDM( p_access ) )
253         {
254             msg_Err( p_access, "DVB-T tuning error" );
255             return VLC_EGENERIC;
256         }
257         break;
258
259     /* ATSC */
260     case FE_ATSC:
261         if( FrontendSetATSC( p_access ) )
262         {
263             msg_Err( p_access, "ATSC tuning error" );
264             return VLC_EGENERIC;
265         }
266         break;
267
268     default:
269         msg_Err( p_access, "tuner type %s not supported",
270                  p_sys->p_frontend->info.name );
271         return VLC_EGENERIC;
272     }
273     p_sys->p_frontend->i_last_status = 0;
274     p_sys->i_frontend_timeout = mdate() + FRONTEND_LOCK_TIMEOUT;
275     return VLC_SUCCESS;
276 }
277
278 /*****************************************************************************
279  * FrontendPoll : Poll for frontend events
280  *****************************************************************************/
281 void FrontendPoll( access_t *p_access )
282 {
283     access_sys_t *p_sys = p_access->p_sys;
284     frontend_t * p_frontend = p_sys->p_frontend;
285     struct dvb_frontend_event event;
286     fe_status_t i_status, i_diff;
287
288     for( ;; )
289     {
290         if( ioctl( p_sys->i_frontend_handle, FE_GET_EVENT, &event ) < 0 )
291         {
292             if( errno != EWOULDBLOCK )
293                 msg_Err( p_access, "frontend event error: %m" );
294             return;
295         }
296
297         i_status = event.status;
298         i_diff = i_status ^ p_frontend->i_last_status;
299         p_frontend->i_last_status = i_status;
300
301         {
302 #define IF_UP( x )                                                          \
303         }                                                                   \
304         if ( i_diff & (x) )                                                 \
305         {                                                                   \
306             if ( i_status & (x) )
307
308             IF_UP( FE_HAS_SIGNAL )
309                 msg_Dbg( p_access, "frontend has acquired signal" );
310             else
311                 msg_Dbg( p_access, "frontend has lost signal" );
312
313             IF_UP( FE_HAS_CARRIER )
314                 msg_Dbg( p_access, "frontend has acquired carrier" );
315             else
316                 msg_Dbg( p_access, "frontend has lost carrier" );
317
318             IF_UP( FE_HAS_VITERBI )
319                 msg_Dbg( p_access, "frontend has acquired stable FEC" );
320             else
321                 msg_Dbg( p_access, "frontend has lost FEC" );
322
323             IF_UP( FE_HAS_SYNC )
324                 msg_Dbg( p_access, "frontend has acquired sync" );
325             else
326                 msg_Dbg( p_access, "frontend has lost sync" );
327
328             IF_UP( FE_HAS_LOCK )
329             {
330                 frontend_statistic_t stat;
331
332                 msg_Dbg( p_access, "frontend has acquired lock" );
333                 p_sys->i_frontend_timeout = 0;
334
335                 /* Read some statistics */
336                 if( !FrontendGetStatistic( p_access, &stat ) )
337                 {
338                     if( stat.i_ber >= 0 )
339                         msg_Dbg( p_access, "- Bit error rate: %d", stat.i_ber );
340                     if( stat.i_signal_strenth >= 0 )
341                         msg_Dbg( p_access, "- Signal strength: %d", stat.i_signal_strenth );
342                     if( stat.i_snr >= 0 )
343                         msg_Dbg( p_access, "- SNR: %d", stat.i_snr );
344                 }
345             }
346             else
347             {
348                 msg_Dbg( p_access, "frontend has lost lock" );
349                 p_sys->i_frontend_timeout = mdate() + FRONTEND_LOCK_TIMEOUT;
350             }
351
352             IF_UP( FE_REINIT )
353             {
354                 /* The frontend was reinited. */
355                 msg_Warn( p_access, "reiniting frontend");
356                 FrontendSet( p_access );
357             }
358         }
359 #undef IF_UP
360     }
361 }
362
363 int FrontendGetStatistic( access_t *p_access, frontend_statistic_t *p_stat )
364 {
365     access_sys_t *p_sys = p_access->p_sys;
366     frontend_t * p_frontend = p_sys->p_frontend;
367
368     if( (p_frontend->i_last_status & FE_HAS_LOCK) == 0 )
369         return VLC_EGENERIC;
370
371     memset( p_stat, 0, sizeof(*p_stat) );
372     if( ioctl( p_sys->i_frontend_handle, FE_READ_BER, &p_stat->i_ber ) < 0 )
373         p_stat->i_ber = -1;
374     if( ioctl( p_sys->i_frontend_handle, FE_READ_SIGNAL_STRENGTH, &p_stat->i_signal_strenth ) < 0 )
375         p_stat->i_signal_strenth = -1;
376     if( ioctl( p_sys->i_frontend_handle, FE_READ_SNR, &p_stat->i_snr ) < 0 )
377         p_stat->i_snr = -1;
378
379     return VLC_SUCCESS;
380 }
381
382 void FrontendGetStatus( access_t *p_access, frontend_status_t *p_status )
383 {
384     access_sys_t *p_sys = p_access->p_sys;
385     frontend_t * p_frontend = p_sys->p_frontend;
386
387     p_status->b_has_signal = (p_frontend->i_last_status & FE_HAS_SIGNAL) != 0;
388     p_status->b_has_carrier = (p_frontend->i_last_status & FE_HAS_CARRIER) != 0;
389     p_status->b_has_lock = (p_frontend->i_last_status & FE_HAS_LOCK) != 0;
390 }
391
392 static int ScanParametersDvbS( access_t *p_access, scan_parameter_t *p_scan )
393 {
394     const frontend_t *p_frontend = p_access->p_sys->p_frontend;
395
396     memset( p_scan, 0, sizeof(*p_scan) );
397     p_scan->type = SCAN_DVB_S;
398
399     p_scan->frequency.i_min = p_frontend->info.frequency_min;
400     p_scan->frequency.i_max = p_frontend->info.frequency_max;
401
402     return VLC_SUCCESS;
403 }
404
405 static int ScanParametersDvbC( access_t *p_access, scan_parameter_t *p_scan )
406 {
407     const frontend_t *p_frontend = p_access->p_sys->p_frontend;
408
409
410     memset( p_scan, 0, sizeof(*p_scan) );
411     p_scan->type = SCAN_DVB_C;
412     p_scan->b_exhaustive = false;
413
414     /* */
415     p_scan->frequency.i_min = p_frontend->info.frequency_min;
416     p_scan->frequency.i_max = p_frontend->info.frequency_max;
417     p_scan->frequency.i_step = p_frontend->info.frequency_stepsize
418         ? p_frontend->info.frequency_stepsize : 166667;
419     p_scan->frequency.i_count = (p_scan->frequency.i_max-p_scan->frequency.i_min)/p_scan->frequency.i_step;
420
421     /* */
422     p_scan->bandwidth.i_min  = 6;
423     p_scan->bandwidth.i_max  = 8;
424     p_scan->bandwidth.i_step = 1;
425     p_scan->bandwidth.i_count = 3;
426     return VLC_SUCCESS;
427 }
428
429 static int ScanParametersDvbT( access_t *p_access, scan_parameter_t *p_scan )
430 {
431     const frontend_t *p_frontend = p_access->p_sys->p_frontend;
432
433
434     memset( p_scan, 0, sizeof(*p_scan) );
435     p_scan->type = SCAN_DVB_T;
436     p_scan->b_exhaustive = false;
437
438     /* */
439     p_scan->frequency.i_min = p_frontend->info.frequency_min;
440     p_scan->frequency.i_max = p_frontend->info.frequency_max;
441     p_scan->frequency.i_step = p_frontend->info.frequency_stepsize
442         ? p_frontend->info.frequency_stepsize : 166667;
443     p_scan->frequency.i_count = (p_scan->frequency.i_max-p_scan->frequency.i_min)/p_scan->frequency.i_step;
444
445     /* */
446     p_scan->bandwidth.i_min  = 6;
447     p_scan->bandwidth.i_max  = 8;
448     p_scan->bandwidth.i_step = 1;
449     p_scan->bandwidth.i_count = 3;
450     return VLC_SUCCESS;
451 }
452
453 int  FrontendGetScanParameter( access_t *p_access, scan_parameter_t *p_scan )
454 {
455     access_sys_t *p_sys = p_access->p_sys;
456     const frontend_t *p_frontend = p_sys->p_frontend;
457
458     if( p_frontend->info.type == FE_OFDM )              /* DVB-T */
459         return ScanParametersDvbT( p_access, p_scan );
460     else if( p_frontend->info.type == FE_QAM )          /* DVB-C */
461         return ScanParametersDvbC( p_access, p_scan );
462     else if( p_frontend->info.type == FE_QPSK )
463         return ScanParametersDvbS( p_access, p_scan );  /* DVB-S */
464
465     msg_Err( p_access, "frontend scanning not supported" );
466     return VLC_EGENERIC;
467 }
468
469 #ifdef ENABLE_HTTPD
470 /*****************************************************************************
471  * FrontendStatus : Read frontend status
472  *****************************************************************************/
473 void FrontendStatus( access_t *p_access )
474 {
475     access_sys_t *p_sys = p_access->p_sys;
476     frontend_t *p_frontend = p_sys->p_frontend;
477     char *p = p_sys->psz_frontend_info = malloc( 10000 );
478     fe_status_t i_status;
479
480     /* Determine type of frontend */
481     if( ioctl( p_sys->i_frontend_handle, FE_GET_INFO,  &p_frontend->info ) < 0 )
482     {
483         char buf[1000];
484         strerror_r( errno, buf, sizeof( buf ) );
485         p += sprintf( p, "ioctl FE_GET_INFO failed %s\n", buf );
486         goto out;
487     }
488
489     /* Print out frontend capabilities. */
490     p += sprintf( p, "<table border=1><tr><th>name</th><td>%s</td></tr>\n",
491                   p_frontend->info.name );
492     switch( p_frontend->info.type )
493     {
494         case FE_QPSK:
495             p += sprintf( p, "<tr><th>type</th><td>QPSK (DVB-S)</td></tr>\n" );
496             break;
497         case FE_QAM:
498             p += sprintf( p, "<tr><th>type</th><td>QAM (DVB-C)</td></tr>\n" );
499             break;
500         case FE_OFDM:
501             p += sprintf( p, "<tr><th>type</th><td>OFDM (DVB-T)</td></tr>\n" );
502             break;
503 #if 0 /* DVB_API_VERSION == 3 */
504         case FE_MEMORY:
505             p += sprintf( p, "<tr><th>type</th><td>MEMORY</td></tr>\n" );
506             break;
507         case FE_NET:
508             p += sprintf( p, "<tr><th>type</th><td>NETWORK</td></tr>\n" );
509             break;
510 #endif
511         default:
512             p += sprintf( p, "<tr><th>type</th><td>UNKNOWN (%d)</td></tr>\n",
513                           p_frontend->info.type );
514             goto out;
515     }
516 #define CHECK_INFO( x )                                                     \
517     p += sprintf( p,                                                        \
518                   "<tr><th>" STRINGIFY(x) "</th><td>%u</td></tr>\n",        \
519                   p_frontend->info.x );
520
521     CHECK_INFO( frequency_min );
522     CHECK_INFO( frequency_max );
523     CHECK_INFO( frequency_stepsize );
524     CHECK_INFO( frequency_tolerance );
525     CHECK_INFO( symbol_rate_min );
526     CHECK_INFO( symbol_rate_max );
527     CHECK_INFO( symbol_rate_tolerance );
528     CHECK_INFO( notifier_delay );
529 #undef CHECK_INFO
530
531     p += sprintf( p, "</table><p>Frontend capability list:\n<table border=1>" );
532
533 #define CHECK_CAPS( x )                                                     \
534     if ( p_frontend->info.caps & (FE_##x) )                                 \
535         p += sprintf( p, "<tr><td>" STRINGIFY(x) "</td></tr>\n" );
536
537     CHECK_CAPS( IS_STUPID );
538     CHECK_CAPS( CAN_INVERSION_AUTO );
539     CHECK_CAPS( CAN_FEC_1_2 );
540     CHECK_CAPS( CAN_FEC_2_3 );
541     CHECK_CAPS( CAN_FEC_3_4 );
542     CHECK_CAPS( CAN_FEC_4_5 );
543     CHECK_CAPS( CAN_FEC_5_6 );
544     CHECK_CAPS( CAN_FEC_6_7 );
545     CHECK_CAPS( CAN_FEC_7_8 );
546     CHECK_CAPS( CAN_FEC_8_9 );
547     CHECK_CAPS( CAN_FEC_AUTO );
548     CHECK_CAPS( CAN_QPSK );
549     CHECK_CAPS( CAN_QAM_16 );
550     CHECK_CAPS( CAN_QAM_32 );
551     CHECK_CAPS( CAN_QAM_64 );
552     CHECK_CAPS( CAN_QAM_128 );
553     CHECK_CAPS( CAN_QAM_256 );
554     CHECK_CAPS( CAN_QAM_AUTO );
555     CHECK_CAPS( CAN_TRANSMISSION_MODE_AUTO );
556     CHECK_CAPS( CAN_BANDWIDTH_AUTO );
557     CHECK_CAPS( CAN_GUARD_INTERVAL_AUTO );
558     CHECK_CAPS( CAN_HIERARCHY_AUTO );
559     CHECK_CAPS( CAN_MUTE_TS );
560     CHECK_CAPS( CAN_RECOVER );
561 #if 0 /* Disabled because of older distributions */
562     CHECK_CAPS( CAN_CLEAN_SETUP );
563 #endif
564 #undef CHECK_CAPS
565
566     p += sprintf( p, "</table><p>Current frontend status:\n<table border=1>" );
567
568     if( ioctl( p_sys->i_frontend_handle, FE_READ_STATUS, &i_status ) < 0 )
569     {
570         char buf[1000];
571         strerror_r( errno, buf, sizeof( buf ) );
572         p += sprintf( p, "</table>ioctl FE_READ_STATUS failed %s\n", buf );
573         goto out;
574     }
575
576 #define CHECK_STATUS( x )                                                   \
577     if ( i_status & (FE_##x) )                                              \
578         p += sprintf( p, "<tr><td>" STRINGIFY(x) "</td></tr>\n" );
579
580     CHECK_STATUS( HAS_SIGNAL );
581     CHECK_STATUS( HAS_CARRIER );
582     CHECK_STATUS( HAS_VITERBI );
583     CHECK_STATUS( HAS_SYNC );
584     CHECK_STATUS( HAS_LOCK );
585     CHECK_STATUS( REINIT );
586     if( i_status == 0 )
587         p += sprintf( p, "<tr><td>Tuning failed</td></tr>\n" );
588 #undef CHECK_STATUS
589
590     if ( i_status & FE_HAS_LOCK )
591     {
592         int32_t i_value;
593         p += sprintf( p, "</table><p>Signal status:\n<table border=1>" );
594         if( ioctl( p_sys->i_frontend_handle, FE_READ_BER, &i_value ) >= 0 )
595             p += sprintf( p, "<tr><th>Bit error rate</th><td>%d</td></tr>\n",
596                           i_value );
597         if( ioctl( p_sys->i_frontend_handle, FE_READ_SIGNAL_STRENGTH,
598                    &i_value ) >= 0 )
599             p += sprintf( p, "<tr><th>Signal strength</th><td>%d</td></tr>\n",
600                           i_value );
601         if( ioctl( p_sys->i_frontend_handle, FE_READ_SNR, &i_value ) >= 0 )
602             p += sprintf( p, "<tr><th>SNR</th><td>%d</td></tr>\n",
603                           i_value );
604     }
605     p += sprintf( p, "</table>" );
606
607 out:
608     vlc_mutex_lock( &p_sys->httpd_mutex );
609     p_sys->b_request_frontend_info = false;
610     vlc_cond_signal( &p_sys->httpd_cond );
611     vlc_mutex_unlock( &p_sys->httpd_mutex );
612 }
613 #endif
614
615 /*****************************************************************************
616  * FrontendInfo : Return information about given frontend
617  *****************************************************************************/
618 static int FrontendInfo( access_t *p_access )
619 {
620     access_sys_t *p_sys = p_access->p_sys;
621     frontend_t *p_frontend = p_sys->p_frontend;
622
623     /* Determine type of frontend */
624     if( ioctl( p_sys->i_frontend_handle, FE_GET_INFO, &p_frontend->info ) < 0 )
625     {
626         msg_Err( p_access, "frontend info request error: %m" );
627         return VLC_EGENERIC;
628     }
629
630     /* Print out frontend capabilities. */
631     msg_Dbg(p_access, "Frontend Info:" );
632     msg_Dbg(p_access, "  name = %s", p_frontend->info.name );
633     switch( p_frontend->info.type )
634     {
635         case FE_QPSK:
636             msg_Dbg( p_access, "  type = QPSK (DVB-S)" );
637             break;
638         case FE_QAM:
639             msg_Dbg( p_access, "  type = QAM (DVB-C)" );
640             break;
641         case FE_OFDM:
642             msg_Dbg( p_access, "  type = OFDM (DVB-T)" );
643             break;
644         case FE_ATSC:
645             msg_Dbg( p_access, "  type = ATSC (USA)" );
646             break;
647 #if 0 /* DVB_API_VERSION == 3 */
648         case FE_MEMORY:
649             msg_Dbg(p_access, "  type = MEMORY" );
650             break;
651         case FE_NET:
652             msg_Dbg(p_access, "  type = NETWORK" );
653             break;
654 #endif
655         default:
656             msg_Err( p_access, "  unknown frontend type (%d)",
657                      p_frontend->info.type );
658             return VLC_EGENERIC;
659     }
660     msg_Dbg(p_access, "  frequency_min = %u (kHz)",
661             p_frontend->info.frequency_min);
662     msg_Dbg(p_access, "  frequency_max = %u (kHz)",
663             p_frontend->info.frequency_max);
664     msg_Dbg(p_access, "  frequency_stepsize = %u",
665             p_frontend->info.frequency_stepsize);
666     msg_Dbg(p_access, "  frequency_tolerance = %u",
667             p_frontend->info.frequency_tolerance);
668     msg_Dbg(p_access, "  symbol_rate_min = %u (kHz)",
669             p_frontend->info.symbol_rate_min);
670     msg_Dbg(p_access, "  symbol_rate_max = %u (kHz)",
671             p_frontend->info.symbol_rate_max);
672     msg_Dbg(p_access, "  symbol_rate_tolerance (ppm) = %u",
673             p_frontend->info.symbol_rate_tolerance);
674     msg_Dbg(p_access, "  notifier_delay (ms) = %u",
675             p_frontend->info.notifier_delay );
676
677     msg_Dbg(p_access, "Frontend Info capability list:");
678     if( p_frontend->info.caps == FE_IS_STUPID)
679         msg_Dbg(p_access, "  no capabilities - frontend is stupid!");
680     if( p_frontend->info.caps & FE_CAN_INVERSION_AUTO)
681         msg_Dbg(p_access, "  inversion auto");
682     if( p_frontend->info.caps & FE_CAN_FEC_1_2)
683         msg_Dbg(p_access, "  forward error correction 1/2");
684     if( p_frontend->info.caps & FE_CAN_FEC_2_3)
685         msg_Dbg(p_access, "  forward error correction 2/3");
686     if( p_frontend->info.caps & FE_CAN_FEC_3_4)
687         msg_Dbg(p_access, "  forward error correction 3/4");
688     if( p_frontend->info.caps & FE_CAN_FEC_4_5)
689         msg_Dbg(p_access, "  forward error correction 4/5");
690     if( p_frontend->info.caps & FE_CAN_FEC_5_6)
691         msg_Dbg(p_access, "  forward error correction 5/6");
692     if( p_frontend->info.caps & FE_CAN_FEC_6_7)
693         msg_Dbg(p_access, "  forward error correction 6/7");
694     if( p_frontend->info.caps & FE_CAN_FEC_7_8)
695         msg_Dbg(p_access, "  forward error correction 7/8");
696     if( p_frontend->info.caps & FE_CAN_FEC_8_9)
697         msg_Dbg(p_access, "  forward error correction 8/9");
698     if( p_frontend->info.caps & FE_CAN_FEC_AUTO)
699         msg_Dbg(p_access, "  forward error correction auto");
700     if( p_frontend->info.caps & FE_CAN_QPSK)
701         msg_Dbg(p_access, "  QPSK modulation");
702     if( p_frontend->info.caps & FE_CAN_QAM_16)
703         msg_Dbg(p_access, "  QAM 16 modulation");
704     if( p_frontend->info.caps & FE_CAN_QAM_32)
705         msg_Dbg(p_access, "  QAM 32 modulation");
706     if( p_frontend->info.caps & FE_CAN_QAM_64)
707         msg_Dbg(p_access, "  QAM 64 modulation");
708     if( p_frontend->info.caps & FE_CAN_QAM_128)
709         msg_Dbg(p_access, "  QAM 128 modulation");
710     if( p_frontend->info.caps & FE_CAN_QAM_256)
711         msg_Dbg(p_access, "  QAM 256 modulation");
712     if( p_frontend->info.caps & FE_CAN_QAM_AUTO)
713         msg_Dbg(p_access, "  QAM auto modulation");
714     if( p_frontend->info.caps & FE_CAN_TRANSMISSION_MODE_AUTO)
715         msg_Dbg(p_access, "  transmission mode auto");
716     if( p_frontend->info.caps & FE_CAN_BANDWIDTH_AUTO)
717         msg_Dbg(p_access, "  bandwidth mode auto");
718     if( p_frontend->info.caps & FE_CAN_GUARD_INTERVAL_AUTO)
719         msg_Dbg(p_access, "  guard interval mode auto");
720     if( p_frontend->info.caps & FE_CAN_HIERARCHY_AUTO)
721         msg_Dbg(p_access, "  hierarchy mode auto");
722     if( p_frontend->info.caps & FE_CAN_8VSB)
723         msg_Dbg(p_access, "  8-level VSB modulation");
724     if( p_frontend->info.caps & FE_CAN_16VSB)
725         msg_Dbg(p_access, "  16-level VSB modulation");
726     if( p_frontend->info.caps & FE_HAS_EXTENDED_CAPS)
727         msg_Dbg(p_access, "  8-level VSB modulation");
728     /* 3 capabilities that don't exist yet HERE */
729 #ifdef FE_CAN_TURBO_FEC
730     if( p_frontend->info.caps & FE_CAN_TURBO_FEC)
731         msg_Dbg(p_access, "  Turbo FEC modulation");
732 #else
733 # warning Please update your Linux kernel headers!
734 #endif
735     if( p_frontend->info.caps & FE_CAN_2G_MODULATION)
736         msg_Dbg(p_access, "  2nd generation modulation (DVB-S2)");
737     /* FE_NEEDS_BENDING is deprecated */
738     if( p_frontend->info.caps & FE_CAN_RECOVER)
739         msg_Dbg(p_access, "  cable unplug recovery");
740     if( p_frontend->info.caps & FE_CAN_MUTE_TS)
741         msg_Dbg(p_access, "  spurious TS muting");
742    msg_Dbg(p_access, "End of capability list");
743
744     return VLC_SUCCESS;
745 }
746
747 /*****************************************************************************
748  * Decoding the DVB parameters (common)
749  *****************************************************************************/
750 static fe_spectral_inversion_t DecodeInversion( access_t *p_access )
751 {
752     int i_val;
753     fe_spectral_inversion_t fe_inversion = 0;
754
755     i_val = var_GetInteger( p_access, "dvb-inversion" );
756     msg_Dbg( p_access, "using inversion=%d", i_val );
757
758     switch( i_val )
759     {
760         case 0: fe_inversion = INVERSION_OFF; break;
761         case 1: fe_inversion = INVERSION_ON; break;
762         case 2: fe_inversion = INVERSION_AUTO; break;
763         default:
764             msg_Dbg( p_access, "dvb has inversion not set, using auto");
765             fe_inversion = INVERSION_AUTO;
766             break;
767     }
768     return fe_inversion;
769 }
770
771 static fe_code_rate_t DecodeFEC( access_t *p_access, const char *varname )
772 {
773     switch( var_GetInteger(p_access, varname) )
774     {
775         case 0:  return FEC_NONE;
776         case 1:  return FEC_1_2;
777         case 2:  return FEC_2_3;
778         case 3:  return FEC_3_4;
779         case 4:  return FEC_4_5;
780         case 5:  return FEC_5_6;
781         case 6:  return FEC_6_7;
782         case 7:  return FEC_7_8;
783         case 8:  return FEC_8_9;
784         case 9:  return FEC_AUTO;
785         default: return FEC_NONE;
786     }
787 }
788
789 static fe_modulation_t DecodeModulation( access_t *p_access,
790                                          fe_modulation_t def )
791 {
792     switch( var_GetInteger( p_access, "dvb-modulation" ) )
793     {
794         case -1:    return QPSK;
795         case 0:     return QAM_AUTO;
796         case 8:     return VSB_8;
797         case 16:    return QAM_16;
798         case 32:    return QAM_32;
799         case 64:    return QAM_64;
800         case 128:   return QAM_128;
801         case 256:   return QAM_256;
802         default:    return def;
803     }
804 }
805
806 /*****************************************************************************
807  * FrontendSetQPSK : controls the FE device
808  *****************************************************************************/
809 static fe_sec_voltage_t DecodeVoltage( access_t *p_access )
810 {
811     switch( var_GetInteger( p_access, "dvb-voltage" ) )
812     {
813         case 0:  return SEC_VOLTAGE_OFF;
814         case 13: return SEC_VOLTAGE_13;
815         case 18: return SEC_VOLTAGE_18;
816         default: return SEC_VOLTAGE_OFF;
817     }
818 }
819
820 static fe_sec_tone_mode_t DecodeTone( access_t *p_access )
821 {
822     switch( var_GetInteger( p_access, "dvb-tone" ) )
823     {
824         case 0:  return SEC_TONE_OFF;
825         case 1:  return SEC_TONE_ON;
826         default: return SEC_TONE_OFF;
827     }
828 }
829
830 struct diseqc_cmd_t
831 {
832     struct dvb_diseqc_master_cmd cmd;
833     uint32_t wait;
834 };
835
836 static int DoDiseqc( access_t *p_access )
837 {
838     access_sys_t *p_sys = p_access->p_sys;
839     int i_val;
840     bool b_val;
841     int i_frequency, i_lnb_slof;
842     fe_sec_voltage_t fe_voltage;
843     fe_sec_tone_mode_t fe_tone;
844
845     i_frequency = var_GetInteger( p_access, "dvb-frequency" );
846     i_lnb_slof = var_GetInteger( p_access, "dvb-lnb-slof" );
847
848     i_val = var_GetInteger( p_access, "dvb-tone" );
849     if( i_val == -1 /* auto */ )
850     {
851         if( i_frequency >= i_lnb_slof )
852             i_val = 1;
853         else
854             i_val = 0;
855         var_SetInteger( p_access, "dvb-tone", i_val );
856     }
857
858     fe_voltage = DecodeVoltage( p_access );
859     fe_tone = DecodeTone( p_access );
860
861     /* Switch off continuous tone. */
862     if( ioctl( p_sys->i_frontend_handle, FE_SET_TONE, SEC_TONE_OFF ) < 0 )
863     {
864         msg_Err( p_access, "switching tone %s error: %m", "off" );
865         return VLC_EGENERIC;
866     }
867
868     /* Configure LNB voltage. */
869     if( ioctl( p_sys->i_frontend_handle, FE_SET_VOLTAGE, fe_voltage ) < 0 )
870     {
871         msg_Err( p_access, "voltage error: %m" );
872         return VLC_EGENERIC;
873     }
874
875     b_val = var_GetBool( p_access, "dvb-high-voltage" );
876     if( ioctl( p_sys->i_frontend_handle,
877                FE_ENABLE_HIGH_LNB_VOLTAGE, b_val ) < 0 && b_val )
878     {
879         msg_Err( p_access, "high LNB voltage error: %m" );
880     }
881
882     /* Wait for at least 15 ms. */
883     msleep(15000);
884
885     i_val = var_GetInteger( p_access, "dvb-satno" );
886     if( i_val > 0 && i_val < 5 )
887     {
888         /* digital satellite equipment control,
889          * specification is available from http://www.eutelsat.com/
890          */
891
892         /* 1.x compatible equipment */
893         struct diseqc_cmd_t cmd =  { {{0xe0, 0x10, 0x38, 0xf0, 0x00, 0x00}, 4}, 0 };
894
895         /* param: high nibble: reset bits, low nibble set bits,
896          * bits are: option, position, polarization, band
897          */
898         cmd.cmd.msg[3] = 0xf0 /* reset bits */
899                           | (((i_val - 1) * 4) & 0xc)
900                           | (fe_voltage == SEC_VOLTAGE_13 ? 0 : 2)
901                           | (fe_tone == SEC_TONE_ON ? 1 : 0);
902
903         if( ioctl( p_sys->i_frontend_handle, FE_DISEQC_SEND_MASTER_CMD,
904                    &cmd.cmd ) )
905         {
906             msg_Err( p_access, "master command sending error: %m" );
907             return VLC_EGENERIC;
908         }
909
910         msleep(15000 + cmd.wait * 1000);
911
912         /* A or B simple diseqc ("diseqc-compatible") */
913         if( ioctl( p_sys->i_frontend_handle, FE_DISEQC_SEND_BURST,
914                   ((i_val - 1) % 2) ? SEC_MINI_B : SEC_MINI_A ) )
915         {
916             msg_Err( p_access, "burst sending error: %m" );
917             return VLC_EGENERIC;
918         }
919
920         msleep(15000);
921     }
922
923     if( ioctl( p_sys->i_frontend_handle, FE_SET_TONE, fe_tone ) )
924     {
925         msg_Err( p_access, "switching tone %s error: %m",
926                  (fe_tone == SEC_TONE_ON) ? "on" : "off" );
927         return VLC_EGENERIC;
928     }
929
930     msleep(50000);
931     return 0;
932 }
933
934 static int FrontendSetQPSK( access_t *p_access )
935 {
936     access_sys_t *p_sys = p_access->p_sys;
937     struct dvb_frontend_parameters fep;
938     int i_val;
939     int i_frequency, i_lnb_slof = 0, i_lnb_lof1, i_lnb_lof2 = 0;
940
941     /* Prepare the fep structure */
942     i_frequency = var_GetInteger( p_access, "dvb-frequency" );
943
944     i_val = var_GetInteger( p_access, "dvb-lnb-lof1" );
945     if( i_val == 0 )
946     {
947         /* Automatic mode. */
948         if ( i_frequency >= 950000 && i_frequency <= 2150000 )
949         {
950             msg_Dbg( p_access, "frequency %d is in IF-band", i_frequency );
951             i_lnb_lof1 = 0;
952         }
953         else if ( i_frequency >= 2500000 && i_frequency <= 2700000 )
954         {
955             msg_Dbg( p_access, "frequency %d is in S-band", i_frequency );
956             i_lnb_lof1 = 3650000;
957         }
958         else if ( i_frequency >= 3400000 && i_frequency <= 4200000 )
959         {
960             msg_Dbg( p_access, "frequency %d is in C-band (lower)",
961                      i_frequency );
962             i_lnb_lof1 = 5150000;
963         }
964         else if ( i_frequency >= 4500000 && i_frequency <= 4800000 )
965         {
966             msg_Dbg( p_access, "frequency %d is in C-band (higher)",
967                      i_frequency );
968             i_lnb_lof1 = 5950000;
969         }
970         else if ( i_frequency >= 10700000 && i_frequency <= 13250000 )
971         {
972             msg_Dbg( p_access, "frequency %d is in Ku-band",
973                      i_frequency );
974             i_lnb_lof1 = 9750000;
975             i_lnb_lof2 = 10600000;
976             i_lnb_slof = 11700000;
977         }
978         else
979         {
980             msg_Err( p_access, "frequency %d is out of any known band",
981                      i_frequency );
982             msg_Err( p_access, "specify dvb-lnb-lof1 manually for the local "
983                      "oscillator frequency" );
984             return VLC_EGENERIC;
985         }
986         var_SetInteger( p_access, "dvb-lnb-lof1", i_lnb_lof1 );
987         var_SetInteger( p_access, "dvb-lnb-lof2", i_lnb_lof2 );
988         var_SetInteger( p_access, "dvb-lnb-slof", i_lnb_slof );
989     }
990     else
991     {
992         i_lnb_lof1 = i_val;
993         i_lnb_lof2 = var_GetInteger( p_access, "dvb-lnb-lof2" );
994         i_lnb_slof = var_GetInteger( p_access, "dvb-lnb-slof" );
995     }
996
997     if( i_lnb_slof && i_frequency >= i_lnb_slof )
998     {
999         i_frequency -= i_lnb_lof2;
1000     }
1001     else
1002     {
1003         i_frequency -= i_lnb_lof1;
1004     }
1005     fep.frequency = i_frequency >= 0 ? i_frequency : -i_frequency;
1006
1007     fep.inversion = DecodeInversion( p_access );
1008
1009     fep.u.qpsk.symbol_rate = var_GetInteger( p_access, "dvb-srate" );
1010
1011     fep.u.qpsk.fec_inner = DecodeFEC( p_access, "dvb-fec" );
1012
1013     if( DoDiseqc( p_access ) < 0 )
1014     {
1015         return VLC_EGENERIC;
1016     }
1017
1018     /* Empty the event queue */
1019     for( ; ; )
1020     {
1021         struct dvb_frontend_event event;
1022         if ( ioctl( p_sys->i_frontend_handle, FE_GET_EVENT, &event ) < 0
1023               && errno == EWOULDBLOCK )
1024             break;
1025     }
1026
1027     /* Now send it all to the frontend device */
1028     if( ioctl( p_sys->i_frontend_handle, FE_SET_FRONTEND, &fep ) < 0 )
1029     {
1030         msg_Err( p_access, "frontend error: %m" );
1031         return VLC_EGENERIC;
1032     }
1033
1034     return VLC_SUCCESS;
1035 }
1036
1037 /*****************************************************************************
1038  * FrontendSetQAM : controls the FE device
1039  *****************************************************************************/
1040 static int FrontendSetQAM( access_t *p_access )
1041 {
1042     access_sys_t *p_sys = p_access->p_sys;
1043     frontend_t *p_frontend = p_sys->p_frontend;
1044     struct dvb_frontend_parameters fep;
1045     unsigned int i_val;
1046
1047     /* Prepare the fep structure */
1048
1049     fep.frequency = var_GetInteger( p_access, "dvb-frequency" );
1050
1051     fep.inversion = DecodeInversion( p_access );
1052
1053     /* Default symbol-rate is for dvb-s, and doesn't fit
1054      * for dvb-c, so if it's over the limit of frontend, default to
1055      * somewhat common value
1056      */
1057     i_val = var_GetInteger( p_access, "dvb-srate" );
1058     if( i_val < p_frontend->info.symbol_rate_max &&
1059         i_val > p_frontend->info.symbol_rate_min )
1060         fep.u.qam.symbol_rate = i_val;
1061     else
1062         fep.u.qam.symbol_rate = 6875000;
1063
1064     fep.u.qam.fec_inner = DecodeFEC( p_access, "dvb-fec" );
1065
1066     fep.u.qam.modulation = DecodeModulation( p_access, QAM_AUTO );
1067
1068     /* Empty the event queue */
1069     for( ; ; )
1070     {
1071         struct dvb_frontend_event event;
1072         if ( ioctl( p_sys->i_frontend_handle, FE_GET_EVENT, &event ) < 0
1073               && errno == EWOULDBLOCK )
1074             break;
1075     }
1076
1077     /* Now send it all to the frontend device */
1078     if( ioctl( p_sys->i_frontend_handle, FE_SET_FRONTEND, &fep ) < 0 )
1079     {
1080         msg_Err( p_access, "frontend error: %m" );
1081         return VLC_EGENERIC;
1082     }
1083
1084     return VLC_SUCCESS;
1085 }
1086
1087 /*****************************************************************************
1088  * FrontendSetOFDM : controls the FE device
1089  *****************************************************************************/
1090 static fe_bandwidth_t DecodeBandwidth( access_t *p_access )
1091 {
1092     fe_bandwidth_t      fe_bandwidth = 0;
1093     int i_bandwith = var_GetInteger( p_access, "dvb-bandwidth" );
1094
1095     msg_Dbg( p_access, "using bandwidth=%d", i_bandwith );
1096
1097     switch( i_bandwith )
1098     {
1099         case 0: fe_bandwidth = BANDWIDTH_AUTO; break;
1100         case 6: fe_bandwidth = BANDWIDTH_6_MHZ; break;
1101         case 7: fe_bandwidth = BANDWIDTH_7_MHZ; break;
1102         case 8: fe_bandwidth = BANDWIDTH_8_MHZ; break;
1103         default:
1104             msg_Dbg( p_access, "terrestrial dvb has bandwidth not set, using auto" );
1105             fe_bandwidth = BANDWIDTH_AUTO;
1106             break;
1107     }
1108     return fe_bandwidth;
1109 }
1110
1111 static fe_transmit_mode_t DecodeTransmission( access_t *p_access )
1112 {
1113     fe_transmit_mode_t  fe_transmission = 0;
1114     int i_transmission = var_GetInteger( p_access, "dvb-transmission" );
1115
1116     msg_Dbg( p_access, "using transmission=%d", i_transmission );
1117
1118     switch( i_transmission )
1119     {
1120         case 0: fe_transmission = TRANSMISSION_MODE_AUTO; break;
1121         case 2: fe_transmission = TRANSMISSION_MODE_2K; break;
1122         case 8: fe_transmission = TRANSMISSION_MODE_8K; break;
1123         default:
1124             msg_Dbg( p_access, "terrestrial dvb has transmission mode not set, using auto");
1125             fe_transmission = TRANSMISSION_MODE_AUTO;
1126             break;
1127     }
1128     return fe_transmission;
1129 }
1130
1131 static fe_guard_interval_t DecodeGuardInterval( access_t *p_access )
1132 {
1133     fe_guard_interval_t fe_guard = 0;
1134     int i_guard = var_GetInteger( p_access, "dvb-guard" );
1135
1136     msg_Dbg( p_access, "using guard=%d", i_guard );
1137
1138     switch( i_guard )
1139     {
1140         case 0: fe_guard = GUARD_INTERVAL_AUTO; break;
1141         case 4: fe_guard = GUARD_INTERVAL_1_4; break;
1142         case 8: fe_guard = GUARD_INTERVAL_1_8; break;
1143         case 16: fe_guard = GUARD_INTERVAL_1_16; break;
1144         case 32: fe_guard = GUARD_INTERVAL_1_32; break;
1145         default:
1146             msg_Dbg( p_access, "terrestrial dvb has guard interval not set, using auto");
1147             fe_guard = GUARD_INTERVAL_AUTO;
1148             break;
1149     }
1150     return fe_guard;
1151 }
1152
1153 static fe_hierarchy_t DecodeHierarchy( access_t *p_access )
1154 {
1155     fe_hierarchy_t      fe_hierarchy = 0;
1156     int i_hierarchy = var_GetInteger( p_access, "dvb-hierarchy" );
1157
1158     msg_Dbg( p_access, "using hierarchy=%d", i_hierarchy );
1159
1160     switch( i_hierarchy )
1161     {
1162         case -1: fe_hierarchy = HIERARCHY_NONE; break;
1163         case 0: fe_hierarchy = HIERARCHY_AUTO; break;
1164         case 1: fe_hierarchy = HIERARCHY_1; break;
1165         case 2: fe_hierarchy = HIERARCHY_2; break;
1166         case 4: fe_hierarchy = HIERARCHY_4; break;
1167         default:
1168             msg_Dbg( p_access, "terrestrial dvb has hierarchy not set, using auto");
1169             fe_hierarchy = HIERARCHY_AUTO;
1170             break;
1171     }
1172     return fe_hierarchy;
1173 }
1174
1175 static int FrontendSetOFDM( access_t * p_access )
1176 {
1177     access_sys_t *p_sys = p_access->p_sys;
1178     struct dvb_frontend_parameters fep;
1179
1180     /* Prepare the fep structure */
1181
1182     fep.frequency = var_GetInteger( p_access, "dvb-frequency" );
1183
1184     fep.inversion = DecodeInversion( p_access );
1185
1186     fep.u.ofdm.bandwidth = DecodeBandwidth( p_access );
1187     fep.u.ofdm.code_rate_HP = DecodeFEC( p_access, "dvb-code-rate-hp" );
1188     fep.u.ofdm.code_rate_LP = DecodeFEC( p_access, "dvb-code-rate-lp" );
1189     fep.u.ofdm.constellation = DecodeModulation( p_access, QAM_AUTO );
1190     fep.u.ofdm.transmission_mode = DecodeTransmission( p_access );
1191     fep.u.ofdm.guard_interval = DecodeGuardInterval( p_access );
1192     fep.u.ofdm.hierarchy_information = DecodeHierarchy( p_access );
1193
1194     /* Empty the event queue */
1195     for( ; ; )
1196     {
1197         struct dvb_frontend_event event;
1198         if ( ioctl( p_sys->i_frontend_handle, FE_GET_EVENT, &event ) < 0
1199               && errno == EWOULDBLOCK )
1200             break;
1201     }
1202
1203     /* Now send it all to the frontend device */
1204     if( ioctl( p_sys->i_frontend_handle, FE_SET_FRONTEND, &fep ) < 0 )
1205     {
1206         msg_Err( p_access, "frontend error: %m" );
1207         return VLC_EGENERIC;
1208     }
1209
1210     return VLC_SUCCESS;
1211 }
1212
1213 /*****************************************************************************
1214  * FrontendSetATSC : controls the FE device
1215  *****************************************************************************/
1216 static int FrontendSetATSC( access_t *p_access )
1217 {
1218     access_sys_t *p_sys = p_access->p_sys;
1219     struct dvb_frontend_parameters fep;
1220
1221     /* Prepare the fep structure */
1222
1223     fep.frequency = var_GetInteger( p_access, "dvb-frequency" );
1224
1225     fep.u.vsb.modulation = DecodeModulation( p_access, VSB_8 );
1226
1227     /* Empty the event queue */
1228     for( ; ; )
1229     {
1230         struct dvb_frontend_event event;
1231         if ( ioctl( p_sys->i_frontend_handle, FE_GET_EVENT, &event ) < 0
1232               && errno == EWOULDBLOCK )
1233             break;
1234     }
1235
1236     /* Now send it all to the frontend device */
1237     if( ioctl( p_sys->i_frontend_handle, FE_SET_FRONTEND, &fep ) < 0 )
1238     {
1239         msg_Err( p_access, "frontend error: %m" );
1240         return VLC_EGENERIC;
1241     }
1242
1243     return VLC_SUCCESS;
1244 }
1245
1246
1247 /*
1248  * Demux
1249  */
1250
1251 /*****************************************************************************
1252  * DMXSetFilter : controls the demux to add a filter
1253  *****************************************************************************/
1254 int DMXSetFilter( access_t * p_access, int i_pid, int * pi_fd, int i_type )
1255 {
1256     struct dmx_pes_filter_params s_filter_params;
1257     unsigned int i_adapter, i_device;
1258     char dmx[128];
1259
1260     i_adapter = var_GetInteger( p_access, "dvb-adapter" );
1261     i_device = var_GetInteger( p_access, "dvb-device" );
1262
1263     if( snprintf( dmx, sizeof(dmx), DMX, i_adapter, i_device )
1264             >= (int)sizeof(dmx) )
1265     {
1266         msg_Err( p_access, "snprintf() truncated string for DMX" );
1267         dmx[sizeof(dmx) - 1] = '\0';
1268     }
1269
1270     msg_Dbg( p_access, "Opening device %s", dmx );
1271     if( (*pi_fd = vlc_open(dmx, O_RDWR)) < 0 )
1272     {
1273         msg_Err( p_access, "DMXSetFilter: opening device failed (%m)" );
1274         return VLC_EGENERIC;
1275     }
1276
1277     /* We fill the DEMUX structure : */
1278     s_filter_params.pid     =   i_pid;
1279     s_filter_params.input   =   DMX_IN_FRONTEND;
1280     s_filter_params.output  =   DMX_OUT_TS_TAP;
1281     s_filter_params.flags   =   DMX_IMMEDIATE_START;
1282
1283     switch ( i_type )
1284     {   /* First device */
1285         case 1:
1286             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_VIDEO0 for PID %d", i_pid);
1287             s_filter_params.pes_type = DMX_PES_VIDEO0;
1288             break;
1289         case 2:
1290             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_AUDIO0 for PID %d", i_pid);
1291             s_filter_params.pes_type = DMX_PES_AUDIO0;
1292             break;
1293         case 3:
1294             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_TELETEXT0 for PID %d", i_pid);
1295             s_filter_params.pes_type = DMX_PES_TELETEXT0;
1296             break;
1297         case 4:
1298             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_SUBTITLE0 for PID %d", i_pid);
1299             s_filter_params.pes_type = DMX_PES_SUBTITLE0;
1300             break;
1301         case 5:
1302             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_PCR0 for PID %d", i_pid);
1303             s_filter_params.pes_type = DMX_PES_PCR0;
1304             break;
1305         /* Second device */
1306         case 6:
1307             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_VIDEO1 for PID %d", i_pid);
1308             s_filter_params.pes_type = DMX_PES_VIDEO1;
1309             break;
1310         case 7:
1311             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_AUDIO1 for PID %d", i_pid);
1312             s_filter_params.pes_type = DMX_PES_AUDIO1;
1313             break;
1314         case 8:
1315             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_TELETEXT1 for PID %d", i_pid);
1316             s_filter_params.pes_type = DMX_PES_TELETEXT1;
1317             break;
1318         case 9:
1319             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_SUBTITLE1 for PID %d", i_pid);
1320             s_filter_params.pes_type = DMX_PES_SUBTITLE1;
1321             break;
1322         case 10:
1323             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_PCR1 for PID %d", i_pid);
1324             s_filter_params.pes_type = DMX_PES_PCR1;
1325             break;
1326         /* Third device */
1327         case 11:
1328             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_VIDEO2 for PID %d", i_pid);
1329             s_filter_params.pes_type = DMX_PES_VIDEO2;
1330             break;
1331         case 12:
1332             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_AUDIO2 for PID %d", i_pid);
1333             s_filter_params.pes_type = DMX_PES_AUDIO2;
1334             break;
1335         case 13:
1336             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_TELETEXT2 for PID %d", i_pid);
1337             s_filter_params.pes_type = DMX_PES_TELETEXT2;
1338             break;
1339         case 14:
1340             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_SUBTITLE2 for PID %d", i_pid);
1341             s_filter_params.pes_type = DMX_PES_SUBTITLE2;
1342             break;
1343         case 15:
1344             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_PCR2 for PID %d", i_pid);
1345             s_filter_params.pes_type = DMX_PES_PCR2;
1346             break;
1347         /* Forth device */
1348         case 16:
1349             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_VIDEO3 for PID %d", i_pid);
1350             s_filter_params.pes_type = DMX_PES_VIDEO3;
1351             break;
1352         case 17:
1353             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_AUDIO3 for PID %d", i_pid);
1354             s_filter_params.pes_type = DMX_PES_AUDIO3;
1355             break;
1356         case 18:
1357             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_TELETEXT3 for PID %d", i_pid);
1358             s_filter_params.pes_type = DMX_PES_TELETEXT3;
1359             break;
1360         case 19:
1361             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_SUBTITLE3 for PID %d", i_pid);
1362             s_filter_params.pes_type = DMX_PES_SUBTITLE3;
1363             break;
1364         case 20:
1365             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_PCR3 for PID %d", i_pid);
1366             s_filter_params.pes_type = DMX_PES_PCR3;
1367             break;
1368         /* Usually used by Nova cards */
1369         case 21:
1370         default:
1371             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_OTHER for PID %d", i_pid);
1372             s_filter_params.pes_type = DMX_PES_OTHER;
1373             break;
1374     }
1375
1376     /* We then give the order to the device : */
1377     if( ioctl( *pi_fd, DMX_SET_PES_FILTER, &s_filter_params ) )
1378     {
1379         msg_Err( p_access, "setting demux PES filter failed: %m" );
1380         return VLC_EGENERIC;
1381     }
1382     return VLC_SUCCESS;
1383 }
1384
1385 /*****************************************************************************
1386  * DMXUnsetFilter : removes a filter
1387  *****************************************************************************/
1388 int DMXUnsetFilter( access_t * p_access, int i_fd )
1389 {
1390     if( ioctl( i_fd, DMX_STOP ) < 0 )
1391     {
1392         msg_Err( p_access, "stopping demux failed: %m" );
1393         return VLC_EGENERIC;
1394     }
1395
1396     msg_Dbg( p_access, "DMXUnsetFilter: closing demux %d", i_fd );
1397     close( i_fd );
1398     return VLC_SUCCESS;
1399 }
1400
1401
1402 /*
1403  * DVR device
1404  */
1405
1406 /*****************************************************************************
1407  * DVROpen :
1408  *****************************************************************************/
1409 int DVROpen( access_t * p_access )
1410 {
1411     access_sys_t *p_sys = p_access->p_sys;
1412     unsigned int i_adapter, i_device;
1413     char dvr[128];
1414
1415     i_adapter = var_GetInteger( p_access, "dvb-adapter" );
1416     i_device = var_GetInteger( p_access, "dvb-device" );
1417
1418     if( snprintf( dvr, sizeof(dvr), DVR, i_adapter, i_device )
1419             >= (int)sizeof(dvr) )
1420     {
1421         msg_Err( p_access, "snprintf() truncated string for DVR" );
1422         dvr[sizeof(dvr) - 1] = '\0';
1423     }
1424
1425     msg_Dbg( p_access, "Opening device %s", dvr );
1426     if( (p_sys->i_handle = vlc_open(dvr, O_RDONLY)) < 0 )
1427     {
1428         msg_Err( p_access, "DVROpen: opening device failed (%m)" );
1429         return VLC_EGENERIC;
1430     }
1431
1432     if( fcntl( p_sys->i_handle, F_SETFL, O_NONBLOCK ) == -1 )
1433     {
1434         msg_Warn( p_access, "DVROpen: couldn't set non-blocking mode (%m)" );
1435     }
1436
1437     return VLC_SUCCESS;
1438 }
1439
1440 /*****************************************************************************
1441  * DVRClose :
1442  *****************************************************************************/
1443 void DVRClose( access_t * p_access )
1444 {
1445     access_sys_t *p_sys = p_access->p_sys;
1446
1447     close( p_sys->i_handle );
1448 }
1449
1450
1451 /*
1452  * CAM device
1453  */
1454
1455 /*****************************************************************************
1456  * CAMOpen :
1457  *****************************************************************************/
1458 int CAMOpen( access_t *p_access )
1459 {
1460     access_sys_t *p_sys = p_access->p_sys;
1461     char ca[128];
1462     int i_adapter, i_device;
1463     ca_caps_t caps;
1464
1465     i_adapter = var_GetInteger( p_access, "dvb-adapter" );
1466     i_device = var_GetInteger( p_access, "dvb-device" );
1467
1468     if( snprintf( ca, sizeof(ca), CA, i_adapter, i_device ) >= (int)sizeof(ca) )
1469     {
1470         msg_Err( p_access, "snprintf() truncated string for CA" );
1471         ca[sizeof(ca) - 1] = '\0';
1472     }
1473     memset( &caps, 0, sizeof( ca_caps_t ));
1474
1475     msg_Dbg( p_access, "Opening device %s", ca );
1476     if( (p_sys->i_ca_handle = vlc_open(ca, O_RDWR | O_NONBLOCK)) < 0 )
1477     {
1478         msg_Warn( p_access, "CAMInit: opening CAM device failed (%m)" );
1479         p_sys->i_ca_handle = 0;
1480         return VLC_EGENERIC;
1481     }
1482
1483     if ( ioctl( p_sys->i_ca_handle, CA_GET_CAP, &caps ) != 0 )
1484     {
1485         msg_Err( p_access, "CAMInit: ioctl() error getting CAM capabilities" );
1486         close( p_sys->i_ca_handle );
1487         p_sys->i_ca_handle = 0;
1488         return VLC_EGENERIC;
1489     }
1490
1491     /* Output CA capabilities */
1492     msg_Dbg( p_access, "CAMInit: CA interface with %d %s", caps.slot_num,
1493         caps.slot_num == 1 ? "slot" : "slots" );
1494     if ( caps.slot_type & CA_CI )
1495         msg_Dbg( p_access, "CAMInit: CI high level interface type" );
1496     if ( caps.slot_type & CA_CI_LINK )
1497         msg_Dbg( p_access, "CAMInit: CI link layer level interface type" );
1498     if ( caps.slot_type & CA_CI_PHYS )
1499         msg_Dbg( p_access, "CAMInit: CI physical layer level interface type (not supported) " );
1500     if ( caps.slot_type & CA_DESCR )
1501         msg_Dbg( p_access, "CAMInit: built-in descrambler detected" );
1502     if ( caps.slot_type & CA_SC )
1503         msg_Dbg( p_access, "CAMInit: simple smart card interface" );
1504
1505     msg_Dbg( p_access, "CAMInit: %d available %s", caps.descr_num,
1506         caps.descr_num == 1 ? "descrambler (key)" : "descramblers (keys)" );
1507     if ( caps.descr_type & CA_ECD )
1508         msg_Dbg( p_access, "CAMInit: ECD scrambling system supported" );
1509     if ( caps.descr_type & CA_NDS )
1510         msg_Dbg( p_access, "CAMInit: NDS scrambling system supported" );
1511     if ( caps.descr_type & CA_DSS )
1512         msg_Dbg( p_access, "CAMInit: DSS scrambling system supported" );
1513  
1514     if ( caps.slot_num == 0 )
1515     {
1516         msg_Err( p_access, "CAMInit: CAM module with no slots" );
1517         close( p_sys->i_ca_handle );
1518         p_sys->i_ca_handle = 0;
1519         return VLC_EGENERIC;
1520     }
1521
1522     if( caps.slot_type & CA_CI_LINK )
1523     {
1524         p_sys->i_ca_type = CA_CI_LINK;
1525     }
1526     else if( caps.slot_type & CA_CI )
1527     {
1528         p_sys->i_ca_type = CA_CI;
1529     }
1530     else
1531     {
1532         p_sys->i_ca_type = -1;
1533         msg_Err( p_access, "CAMInit: incompatible CAM interface" );
1534         close( p_sys->i_ca_handle );
1535         p_sys->i_ca_handle = 0;
1536         return VLC_EGENERIC;
1537     }
1538
1539     p_sys->i_nb_slots = caps.slot_num;
1540     memset( p_sys->pb_active_slot, 0, sizeof(bool) * MAX_CI_SLOTS );
1541     memset( p_sys->pb_slot_mmi_expected, 0, sizeof(bool) * MAX_CI_SLOTS );
1542     memset( p_sys->pb_slot_mmi_undisplayed, 0,
1543             sizeof(bool) * MAX_CI_SLOTS );
1544
1545     return en50221_Init( p_access );
1546 }
1547
1548 /*****************************************************************************
1549  * CAMPoll :
1550  *****************************************************************************/
1551 int CAMPoll( access_t * p_access )
1552 {
1553     access_sys_t *p_sys = p_access->p_sys;
1554     int i_ret = VLC_EGENERIC;
1555
1556     if ( p_sys->i_ca_handle == 0 )
1557     {
1558         return VLC_EGENERIC;
1559     }
1560
1561     switch( p_sys->i_ca_type )
1562     {
1563     case CA_CI_LINK:
1564         i_ret = en50221_Poll( p_access );
1565         break;
1566     case CA_CI:
1567         i_ret = VLC_SUCCESS;
1568         break;
1569     default:
1570         msg_Err( p_access, "CAMPoll: This should not happen" );
1571         break;
1572     }
1573
1574     return i_ret;
1575 }
1576
1577 #ifdef ENABLE_HTTPD
1578 /*****************************************************************************
1579  * CAMStatus :
1580  *****************************************************************************/
1581 void CAMStatus( access_t * p_access )
1582 {
1583     access_sys_t *p_sys = p_access->p_sys;
1584     char *p;
1585     ca_caps_t caps;
1586     int i_slot, i;
1587
1588     if ( p_sys->psz_request != NULL && *p_sys->psz_request )
1589     {
1590         /* Check if we have an undisplayed MMI message : in that case we ignore
1591          * the user input to avoid confusing the CAM. */
1592         for ( i_slot = 0; i_slot < p_sys->i_nb_slots; i_slot++ )
1593         {
1594             if ( p_sys->pb_slot_mmi_undisplayed[i_slot] == true )
1595             {
1596                 p_sys->psz_request = NULL;
1597                 msg_Dbg( p_access,
1598                          "ignoring user request because of a new MMI object" );
1599                 break;
1600             }
1601         }
1602     }
1603
1604     if ( p_sys->psz_request != NULL && *p_sys->psz_request )
1605     {
1606         /* We have a mission to accomplish. */
1607         en50221_mmi_object_t mmi_object;
1608         char *psz_request = p_sys->psz_request;
1609         char psz_value[255];
1610         int i_slot;
1611         bool b_ok = false;
1612
1613         p_sys->psz_request = NULL;
1614
1615         if ( HTTPExtractValue( psz_request, "slot", psz_value,
1616                                    sizeof(psz_value) ) == NULL )
1617         {
1618             p_sys->psz_mmi_info = strdup( "invalid request parameter\n" );
1619             goto out;
1620         }
1621         i_slot = atoi(psz_value);
1622
1623         if ( HTTPExtractValue( psz_request, "open", psz_value,
1624                                    sizeof(psz_value) ) != NULL )
1625         {
1626             en50221_OpenMMI( p_access, i_slot );
1627             return;
1628         }
1629
1630         if ( HTTPExtractValue( psz_request, "close", psz_value,
1631                                    sizeof(psz_value) ) != NULL )
1632         {
1633             en50221_CloseMMI( p_access, i_slot );
1634             return;
1635         }
1636
1637         if ( HTTPExtractValue( psz_request, "cancel", psz_value,
1638                                    sizeof(psz_value) ) == NULL )
1639         {
1640             b_ok = true;
1641         }
1642
1643         if ( HTTPExtractValue( psz_request, "type", psz_value,
1644                                    sizeof(psz_value) ) == NULL )
1645         {
1646             p_sys->psz_mmi_info = strdup( "invalid request parameter\n" );
1647             goto out;
1648         }
1649
1650         if ( !strcmp( psz_value, "enq" ) )
1651         {
1652             mmi_object.i_object_type = EN50221_MMI_ANSW;
1653             mmi_object.u.answ.b_ok = b_ok;
1654             if ( b_ok == false )
1655             {
1656                 mmi_object.u.answ.psz_answ = strdup("");
1657             }
1658             else
1659             {
1660                 if ( HTTPExtractValue( psz_request, "answ", psz_value,
1661                                            sizeof(psz_value) ) == NULL )
1662                 {
1663                     p_sys->psz_mmi_info = strdup( "invalid request parameter\n" );
1664                     goto out;
1665                 }
1666
1667                 mmi_object.u.answ.psz_answ = strdup(psz_value);
1668             }
1669         }
1670         else
1671         {
1672             mmi_object.i_object_type = EN50221_MMI_MENU_ANSW;
1673             if ( b_ok == false )
1674             {
1675                 mmi_object.u.menu_answ.i_choice = 0;
1676             }
1677             else
1678             {
1679                 if ( HTTPExtractValue( psz_request, "choice", psz_value,
1680                                            sizeof(psz_value) ) == NULL )
1681                     mmi_object.u.menu_answ.i_choice = 0;
1682                 else
1683                     mmi_object.u.menu_answ.i_choice = atoi(psz_value);
1684             }
1685         }
1686
1687         en50221_SendMMIObject( p_access, i_slot, &mmi_object );
1688         return;
1689     }
1690
1691     /* Check that we have all necessary MMI information. */
1692     for ( i_slot = 0; i_slot < p_sys->i_nb_slots; i_slot++ )
1693     {
1694         if ( p_sys->pb_slot_mmi_expected[i_slot] == true )
1695             return;
1696     }
1697
1698     p = p_sys->psz_mmi_info = malloc( 10000 );
1699
1700     if ( ioctl( p_sys->i_ca_handle, CA_GET_CAP, &caps ) != 0 )
1701     {
1702         char buf[1000];
1703         strerror_r( errno, buf, sizeof( buf ) );
1704         p += sprintf( p, "ioctl CA_GET_CAP failed (%s)\n", buf );
1705         goto out;
1706     }
1707
1708     /* Output CA capabilities */
1709     p += sprintf( p, "CA interface with %d %s, type:\n<table>", caps.slot_num,
1710                   caps.slot_num == 1 ? "slot" : "slots" );
1711 #define CHECK_CAPS( x, s )                                                  \
1712     if ( caps.slot_type & (CA_##x) )                                        \
1713         p += sprintf( p, "<tr><td>" s "</td></tr>\n" );
1714
1715     CHECK_CAPS( CI, "CI high level interface" );
1716     CHECK_CAPS( CI_LINK, "CI link layer level interface" );
1717     CHECK_CAPS( CI_PHYS, "CI physical layer level interface (not supported)" );
1718     CHECK_CAPS( DESCR, "built-in descrambler" );
1719     CHECK_CAPS( SC, "simple smartcard interface" );
1720 #undef CHECK_CAPS
1721
1722     p += sprintf( p, "</table>%d available %s\n<table>", caps.descr_num,
1723         caps.descr_num == 1 ? "descrambler (key)" : "descramblers (keys)" );
1724 #define CHECK_DESC( x )                                                     \
1725     if ( caps.descr_type & (CA_##x) )                                       \
1726         p += sprintf( p, "<tr><td>" STRINGIFY(x) "</td></tr>\n" );
1727
1728     CHECK_DESC( ECD );
1729     CHECK_DESC( NDS );
1730     CHECK_DESC( DSS );
1731 #undef CHECK_DESC
1732
1733     p += sprintf( p, "</table>" );
1734
1735     for ( i_slot = 0; i_slot < p_sys->i_nb_slots; i_slot++ )
1736     {
1737         ca_slot_info_t sinfo;
1738
1739         p_sys->pb_slot_mmi_undisplayed[i_slot] = false;
1740         p += sprintf( p, "<p>CA slot #%d: ", i_slot );
1741
1742         sinfo.num = i_slot;
1743         if ( ioctl( p_sys->i_ca_handle, CA_GET_SLOT_INFO, &sinfo ) != 0 )
1744         {
1745             char buf[1000];
1746             strerror_r( errno, buf, sizeof( buf ) );
1747             p += sprintf( p, "ioctl CA_GET_SLOT_INFO failed (%s)<br>\n", buf );
1748             continue;
1749         }
1750
1751 #define CHECK_TYPE( x, s )                                                  \
1752         if ( sinfo.type & (CA_##x) )                                        \
1753             p += sprintf( p, "%s", s );
1754
1755         CHECK_TYPE( CI, "high level, " );
1756         CHECK_TYPE( CI_LINK, "link layer level, " );
1757         CHECK_TYPE( CI_PHYS, "physical layer level, " );
1758 #undef CHECK_TYPE
1759
1760         if ( sinfo.flags & CA_CI_MODULE_READY )
1761         {
1762             en50221_mmi_object_t *p_object = en50221_GetMMIObject( p_access,
1763                                                                        i_slot );
1764
1765             p += sprintf( p, "module present and ready<p>\n" );
1766             p += sprintf( p, "<form action=index.html method=get>\n" );
1767             p += sprintf( p, "<input type=hidden name=slot value=\"%d\">\n",
1768                           i_slot );
1769
1770             if ( p_object == NULL )
1771             {
1772                 p += sprintf( p, "<input type=submit name=open value=\"Open session\">\n" );
1773             }
1774             else
1775             {
1776                 switch ( p_object->i_object_type )
1777                 {
1778                 case EN50221_MMI_ENQ:
1779                     p += sprintf( p, "<input type=hidden name=type value=enq>\n" );
1780                     p += sprintf( p, "<table border=1><tr><th>%s</th></tr>\n",
1781                                   p_object->u.enq.psz_text );
1782                     if ( p_object->u.enq.b_blind == false )
1783                         p += sprintf( p, "<tr><td><input type=text name=answ></td></tr>\n" );
1784                     else
1785                         p += sprintf( p, "<tr><td><input type=password name=answ></td></tr>\n" );
1786                     break;
1787
1788                 case EN50221_MMI_MENU:
1789                     p += sprintf( p, "<input type=hidden name=type value=menu>\n" );
1790                     p += sprintf( p, "<table border=1><tr><th>%s</th></tr>\n",
1791                                   p_object->u.menu.psz_title );
1792                     p += sprintf( p, "<tr><td>%s</td></tr><tr><td>\n",
1793                                   p_object->u.menu.psz_subtitle );
1794                     for ( i = 0; i < p_object->u.menu.i_choices; i++ )
1795                         p += sprintf( p, "<input type=radio name=choice value=\"%d\">%s<br>\n", i + 1, p_object->u.menu.ppsz_choices[i] );
1796                     p += sprintf( p, "</td></tr><tr><td>%s</td></tr>\n",
1797                                   p_object->u.menu.psz_bottom );
1798                     break;
1799
1800                 case EN50221_MMI_LIST:
1801                     p += sprintf( p, "<input type=hidden name=type value=menu>\n" );
1802                     p += sprintf( p, "<input type=hidden name=choice value=0>\n" );
1803                     p += sprintf( p, "<table border=1><tr><th>%s</th></tr>\n",
1804                                   p_object->u.menu.psz_title );
1805                     p += sprintf( p, "<tr><td>%s</td></tr><tr><td>\n",
1806                                   p_object->u.menu.psz_subtitle );
1807                     for ( i = 0; i < p_object->u.menu.i_choices; i++ )
1808                         p += sprintf( p, "%s<br>\n",
1809                                       p_object->u.menu.ppsz_choices[i] );
1810                     p += sprintf( p, "</td></tr><tr><td>%s</td></tr>\n",
1811                                   p_object->u.menu.psz_bottom );
1812                     break;
1813
1814                 default:
1815                     p += sprintf( p, "<table><tr><th>Unknown MMI object type</th></tr>\n" );
1816                 }
1817
1818                 p += sprintf( p, "</table><p><input type=submit name=ok value=\"OK\">\n" );
1819                 p += sprintf( p, "<input type=submit name=cancel value=\"Cancel\">\n" );
1820                 p += sprintf( p, "<input type=submit name=close value=\"Close Session\">\n" );
1821             }
1822             p += sprintf( p, "</form>\n" );
1823         }
1824         else if ( sinfo.flags & CA_CI_MODULE_PRESENT )
1825             p += sprintf( p, "module present, not ready<br>\n" );
1826         else
1827             p += sprintf( p, "module not present<br>\n" );
1828     }
1829
1830 out:
1831     vlc_mutex_lock( &p_sys->httpd_mutex );
1832     p_sys->b_request_mmi_info = false;
1833     vlc_cond_signal( &p_sys->httpd_cond );
1834     vlc_mutex_unlock( &p_sys->httpd_mutex );
1835 }
1836 #endif
1837
1838 /*****************************************************************************
1839  * CAMSet :
1840  *****************************************************************************/
1841 int CAMSet( access_t * p_access, dvbpsi_pmt_t *p_pmt )
1842 {
1843     access_sys_t *p_sys = p_access->p_sys;
1844
1845     if( p_sys->i_ca_handle == 0 )
1846     {
1847         dvbpsi_DeletePMT( p_pmt );
1848         return VLC_EGENERIC;
1849     }
1850
1851     en50221_SetCAPMT( p_access, p_pmt );
1852
1853     return VLC_SUCCESS;
1854 }
1855
1856 /*****************************************************************************
1857  * CAMClose :
1858  *****************************************************************************/
1859 void CAMClose( access_t * p_access )
1860 {
1861     access_sys_t *p_sys = p_access->p_sys;
1862
1863     en50221_End( p_access );
1864
1865     if ( p_sys->i_ca_handle )
1866     {
1867         close( p_sys->i_ca_handle );
1868     }
1869 }
1870