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