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