]> git.sesse.net Git - vlc/blob - modules/access/dvb/linux_dvb.c
* modules/access/dvb/linux_dvb.c: Disabled FE_CAN_CLEAN_SETUP check because
[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@wxs.nl>
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;
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 #undef CHECK_STATUS
463
464     if ( i_status & FE_HAS_LOCK )
465     {
466         int32_t i_value;
467         p += sprintf( p, "</table><p>Signal status:\n<table border=1>" );
468         if( ioctl( p_sys->i_frontend_handle, FE_READ_BER, &i_value ) >= 0 )
469             p += sprintf( p, "<tr><th>Bit error rate</th><td>%d</td></tr>\n",
470                           i_value );
471         if( ioctl( p_sys->i_frontend_handle, FE_READ_SIGNAL_STRENGTH,
472                    &i_value ) >= 0 )
473             p += sprintf( p, "<tr><th>Signal strength</th><td>%d</td></tr>\n",
474                           i_value );
475         if( ioctl( p_sys->i_frontend_handle, FE_READ_SNR, &i_value ) >= 0 )
476             p += sprintf( p, "<tr><th>SNR</th><td>%d</td></tr>\n",
477                           i_value );
478     }
479     p += sprintf( p, "</table>" );
480
481 out:
482     vlc_mutex_lock( &p_sys->httpd_mutex );
483     p_sys->b_request_frontend_info = VLC_FALSE;
484     vlc_cond_signal( &p_sys->httpd_cond );
485     vlc_mutex_unlock( &p_sys->httpd_mutex );
486 }
487 #endif
488
489 /*****************************************************************************
490  * FrontendInfo : Return information about given frontend
491  *****************************************************************************/
492 static int FrontendInfo( access_t *p_access )
493 {
494     access_sys_t *p_sys = p_access->p_sys;
495     frontend_t *p_frontend = p_sys->p_frontend;
496     int i_ret;
497
498     /* Determine type of frontend */
499     if( (i_ret = ioctl( p_sys->i_frontend_handle, FE_GET_INFO,
500                         &p_frontend->info )) < 0 )
501     {
502         msg_Err( p_access, "ioctl FE_GET_INFO failed (%d) %s", i_ret,
503                  strerror(errno) );
504         return VLC_EGENERIC;
505     }
506
507     /* Print out frontend capabilities. */
508     msg_Dbg(p_access, "Frontend Info:" );
509     msg_Dbg(p_access, "  name = %s", p_frontend->info.name );
510     switch( p_frontend->info.type )
511     {
512         case FE_QPSK:
513             msg_Dbg( p_access, "  type = QPSK (DVB-S)" );
514             break;
515         case FE_QAM:
516             msg_Dbg( p_access, "  type = QAM (DVB-C)" );
517             break;
518         case FE_OFDM:
519             msg_Dbg( p_access, "  type = OFDM (DVB-T)" );
520             break;
521 #if 0 /* DVB_API_VERSION == 3 */
522         case FE_MEMORY:
523             msg_Dbg(p_access, "  type = MEMORY" );
524             break;
525         case FE_NET:
526             msg_Dbg(p_access, "  type = NETWORK" );
527             break;
528 #endif
529         default:
530             msg_Err( p_access, "  unknown frontend type (%d)",
531                      p_frontend->info.type );
532             return VLC_EGENERIC;
533     }
534     msg_Dbg(p_access, "  frequency_min = %u (kHz)",
535             p_frontend->info.frequency_min);
536     msg_Dbg(p_access, "  frequency_max = %u (kHz)",
537             p_frontend->info.frequency_max);
538     msg_Dbg(p_access, "  frequency_stepsize = %u",
539             p_frontend->info.frequency_stepsize);
540     msg_Dbg(p_access, "  frequency_tolerance = %u",
541             p_frontend->info.frequency_tolerance);
542     msg_Dbg(p_access, "  symbol_rate_min = %u (kHz)",
543             p_frontend->info.symbol_rate_min);
544     msg_Dbg(p_access, "  symbol_rate_max = %u (kHz)",
545             p_frontend->info.symbol_rate_max);
546     msg_Dbg(p_access, "  symbol_rate_tolerance (ppm) = %u",
547             p_frontend->info.symbol_rate_tolerance);
548     msg_Dbg(p_access, "  notifier_delay (ms) = %u",
549             p_frontend->info.notifier_delay );
550
551     msg_Dbg(p_access, "Frontend Info capability list:");
552     if( p_frontend->info.caps & FE_IS_STUPID)
553         msg_Dbg(p_access, "  no capabilities - frontend is stupid!");
554     if( p_frontend->info.caps & FE_CAN_INVERSION_AUTO)
555         msg_Dbg(p_access, "  inversion auto");
556     if( p_frontend->info.caps & FE_CAN_FEC_1_2)
557         msg_Dbg(p_access, "  forward error correction 1/2");
558     if( p_frontend->info.caps & FE_CAN_FEC_2_3)
559         msg_Dbg(p_access, "  forward error correction 2/3");
560     if( p_frontend->info.caps & FE_CAN_FEC_3_4)
561         msg_Dbg(p_access, "  forward error correction 3/4");
562     if( p_frontend->info.caps & FE_CAN_FEC_4_5)
563         msg_Dbg(p_access, "  forward error correction 4/5");
564     if( p_frontend->info.caps & FE_CAN_FEC_5_6)
565         msg_Dbg(p_access, "  forward error correction 5/6");
566     if( p_frontend->info.caps & FE_CAN_FEC_6_7)
567         msg_Dbg(p_access, "  forward error correction 6/7");
568     if( p_frontend->info.caps & FE_CAN_FEC_7_8)
569         msg_Dbg(p_access, "  forward error correction 7/8");
570     if( p_frontend->info.caps & FE_CAN_FEC_8_9)
571         msg_Dbg(p_access, "  forward error correction 8/9");
572     if( p_frontend->info.caps & FE_CAN_FEC_AUTO)
573         msg_Dbg(p_access, "  forward error correction auto");
574     if( p_frontend->info.caps & FE_CAN_QPSK)
575         msg_Dbg(p_access, "  card can do QPSK");
576     if( p_frontend->info.caps & FE_CAN_QAM_16)
577         msg_Dbg(p_access, "  card can do QAM 16");
578     if( p_frontend->info.caps & FE_CAN_QAM_32)
579         msg_Dbg(p_access, "  card can do QAM 32");
580     if( p_frontend->info.caps & FE_CAN_QAM_64)
581         msg_Dbg(p_access, "  card can do QAM 64");
582     if( p_frontend->info.caps & FE_CAN_QAM_128)
583         msg_Dbg(p_access, "  card can do QAM 128");
584     if( p_frontend->info.caps & FE_CAN_QAM_256)
585         msg_Dbg(p_access, "  card can do QAM 256");
586     if( p_frontend->info.caps & FE_CAN_QAM_AUTO)
587         msg_Dbg(p_access, "  card can do QAM auto");
588     if( p_frontend->info.caps & FE_CAN_TRANSMISSION_MODE_AUTO)
589         msg_Dbg(p_access, "  transmission mode auto");
590     if( p_frontend->info.caps & FE_CAN_BANDWIDTH_AUTO)
591         msg_Dbg(p_access, "  bandwidth mode auto");
592     if( p_frontend->info.caps & FE_CAN_GUARD_INTERVAL_AUTO)
593         msg_Dbg(p_access, "  guard interval mode auto");
594     if( p_frontend->info.caps & FE_CAN_HIERARCHY_AUTO)
595         msg_Dbg(p_access, "  hierarchy mode auto");
596     if( p_frontend->info.caps & FE_CAN_MUTE_TS)
597         msg_Dbg(p_access, "  card can mute TS");
598     if( p_frontend->info.caps & FE_CAN_RECOVER)
599         msg_Dbg(p_access, "  card can recover from a cable unplug");
600     msg_Dbg(p_access, "End of capability list");
601
602     return VLC_SUCCESS;
603 }
604
605 /*****************************************************************************
606  * Decoding the DVB parameters (common)
607  *****************************************************************************/
608 static fe_spectral_inversion_t DecodeInversion( access_t *p_access )
609 {
610     vlc_value_t         val;
611     fe_spectral_inversion_t fe_inversion = 0;
612
613     var_Get( p_access, "dvb-inversion", &val );
614     msg_Dbg( p_access, "using inversion=%d", val.i_int );
615
616     switch( val.i_int )
617     {
618         case 0: fe_inversion = INVERSION_OFF; break;
619         case 1: fe_inversion = INVERSION_ON; break;
620         case 2: fe_inversion = INVERSION_AUTO; break;
621         default:
622             msg_Dbg( p_access, "dvb has inversion not set, using auto");
623             fe_inversion = INVERSION_AUTO;
624             break;
625     }
626     return fe_inversion;
627 }
628
629 static fe_code_rate_t DecodeFEC( access_t *p_access, int i_val )
630 {
631     fe_code_rate_t      fe_fec = FEC_NONE;
632
633     msg_Dbg( p_access, "using fec=%d", i_val );
634
635     switch( i_val )
636     {
637         case 0: fe_fec = FEC_NONE; break;
638         case 1: fe_fec = FEC_1_2; break;
639         case 2: fe_fec = FEC_2_3; break;
640         case 3: fe_fec = FEC_3_4; break;
641         case 4: fe_fec = FEC_4_5; break;
642         case 5: fe_fec = FEC_5_6; break;
643         case 6: fe_fec = FEC_6_7; break;
644         case 7: fe_fec = FEC_7_8; break;
645         case 8: fe_fec = FEC_8_9; break;
646         case 9: fe_fec = FEC_AUTO; break;
647         default:
648             /* cannot happen */
649             fe_fec = FEC_NONE;
650             msg_Err( p_access, "argument has invalid FEC (%d)", i_val);
651             break;
652     }
653     return fe_fec;
654 }
655
656 static fe_modulation_t DecodeModulation( access_t *p_access )
657 {
658     vlc_value_t         val;
659     fe_modulation_t     fe_modulation = 0;
660
661     var_Get( p_access, "dvb-modulation", &val );
662
663     switch( val.i_int )
664     {
665         case -1: fe_modulation = QPSK; break;
666         case 0: fe_modulation = QAM_AUTO; break;
667         case 16: fe_modulation = QAM_16; break;
668         case 32: fe_modulation = QAM_32; break;
669         case 64: fe_modulation = QAM_64; break;
670         case 128: fe_modulation = QAM_128; break;
671         case 256: fe_modulation = QAM_256; break;
672         default:
673             msg_Dbg( p_access, "terrestrial/cable dvb has constellation/modulation not set, using auto");
674             fe_modulation = QAM_AUTO;
675             break;
676     }
677     return fe_modulation;
678 }
679
680 /*****************************************************************************
681  * FrontendSetQPSK : controls the FE device
682  *****************************************************************************/
683 static fe_sec_voltage_t DecodeVoltage( access_t *p_access )
684 {
685     vlc_value_t         val;
686     fe_sec_voltage_t    fe_voltage;
687
688     var_Get( p_access, "dvb-voltage", &val );
689     msg_Dbg( p_access, "using voltage=%d", val.i_int );
690
691     switch( val.i_int )
692     {
693         case 0: fe_voltage = SEC_VOLTAGE_OFF; break;
694         case 13: fe_voltage = SEC_VOLTAGE_13; break;
695         case 18: fe_voltage = SEC_VOLTAGE_18; break;
696         default:
697             fe_voltage = SEC_VOLTAGE_OFF;
698             msg_Err( p_access, "argument has invalid voltage (%d)", val.i_int );
699             break;
700     }
701     return fe_voltage;
702 }
703
704 static fe_sec_tone_mode_t DecodeTone( access_t *p_access )
705 {
706     vlc_value_t         val;
707     fe_sec_tone_mode_t  fe_tone;
708
709     var_Get( p_access, "dvb-tone", &val );
710     msg_Dbg( p_access, "using tone=%d", val.i_int );
711
712     switch( val.i_int )
713     {
714         case 0: fe_tone = SEC_TONE_OFF; break;
715         case 1: fe_tone = SEC_TONE_ON; break;
716         default:
717             fe_tone = SEC_TONE_OFF;
718             msg_Err( p_access, "argument has invalid tone mode (%d)", val.i_int);
719             break;
720     }
721     return fe_tone;
722 }
723
724 struct diseqc_cmd_t
725 {
726     struct dvb_diseqc_master_cmd cmd;
727     uint32_t wait;
728 };
729
730 static int DoDiseqc( access_t *p_access )
731 {
732     access_sys_t *p_sys = p_access->p_sys;
733     vlc_value_t val;
734     int i_frequency, i_lnb_slof;
735     fe_sec_voltage_t fe_voltage;
736     fe_sec_tone_mode_t fe_tone;
737     int i_err;
738
739     var_Get( p_access, "dvb-frequency", &val );
740     i_frequency = val.i_int;
741     var_Get( p_access, "dvb-lnb-slof", &val );
742     i_lnb_slof = val.i_int;
743
744     var_Get( p_access, "dvb-tone", &val );
745     if( val.i_int == -1 /* auto */ )
746     {
747         if( i_frequency >= i_lnb_slof )
748             val.i_int = 1;
749         else
750             val.i_int = 0;
751         var_Set( p_access, "dvb-tone", val );
752     }
753
754     fe_voltage = DecodeVoltage( p_access );
755     fe_tone = DecodeTone( p_access );
756
757     /* Switch off continuous tone. */
758     if( (i_err = ioctl( p_sys->i_frontend_handle, FE_SET_TONE, SEC_TONE_OFF )) < 0 )
759     {
760         msg_Err( p_access, "ioctl FE_SET_TONE failed, tone=%s (%d) %s",
761                  fe_tone == SEC_TONE_ON ? "on" : "off", i_err,
762                  strerror(errno) );
763         return i_err;
764     }
765
766     /* Configure LNB voltage. */
767     if( (i_err = ioctl( p_sys->i_frontend_handle, FE_SET_VOLTAGE, fe_voltage )) < 0 )
768     {
769         msg_Err( p_access, "ioctl FE_SET_VOLTAGE failed, voltage=%d (%d) %s",
770                  fe_voltage, i_err, strerror(errno) );
771         return i_err;
772     }
773
774     var_Get( p_access, "dvb-high-voltage", &val );
775     if( (i_err = ioctl( p_sys->i_frontend_handle, FE_ENABLE_HIGH_LNB_VOLTAGE,
776                         val.b_bool )) < 0 && val.b_bool )
777     {
778         msg_Err( p_access,
779                  "ioctl FE_ENABLE_HIGH_LNB_VOLTAGE failed, val=%d (%d) %s",
780                  val.b_bool, i_err, strerror(errno) );
781     }
782
783     /* Wait for at least 15 ms. */
784     msleep(15000);
785
786     var_Get( p_access, "dvb-satno", &val );
787     if( val.i_int > 0 && val.i_int < 5 )
788     {
789         /* digital satellite equipment control,
790          * specification is available from http://www.eutelsat.com/
791          */
792
793         /* 1.x compatible equipment */
794         struct diseqc_cmd_t cmd =  { {{0xe0, 0x10, 0x38, 0xf0, 0x00, 0x00}, 4}, 0 };
795
796         /* param: high nibble: reset bits, low nibble set bits,
797          * bits are: option, position, polarization, band
798          */
799         cmd.cmd.msg[3] = 0xf0 /* reset bits */
800                           | (((val.i_int - 1) * 4) & 0xc)
801                           | (fe_voltage == SEC_VOLTAGE_13 ? 0 : 2)
802                           | (fe_tone == SEC_TONE_ON ? 1 : 0);
803
804         if( (i_err = ioctl( p_sys->i_frontend_handle, FE_DISEQC_SEND_MASTER_CMD,
805                            &cmd.cmd )) < 0 )
806         {
807             msg_Err( p_access, "ioctl FE_SEND_MASTER_CMD failed (%d) %s",
808                      i_err, strerror(errno) );
809             return i_err;
810         }
811
812         msleep(15000 + cmd.wait * 1000);
813
814         /* A or B simple diseqc ("diseqc-compatible") */
815         if( (i_err = ioctl( p_sys->i_frontend_handle, FE_DISEQC_SEND_BURST,
816                       ((val.i_int - 1) % 2) ? SEC_MINI_B : SEC_MINI_A )) < 0 )
817         {
818             msg_Err( p_access, "ioctl FE_SEND_BURST failed (%d) %s",
819                      i_err, strerror(errno) );
820             return i_err;
821         }
822
823         msleep(15000);
824     }
825
826     if( (i_err = ioctl( p_sys->i_frontend_handle, FE_SET_TONE, fe_tone )) < 0 )
827     {
828         msg_Err( p_access, "ioctl FE_SET_TONE failed, tone=%s (%d) %s",
829                  fe_tone == SEC_TONE_ON ? "on" : "off", i_err,
830                  strerror(errno) );
831         return i_err;
832     }
833
834     msleep(50000);
835     return 0;
836 }
837
838 static int FrontendSetQPSK( access_t *p_access )
839 {
840     access_sys_t *p_sys = p_access->p_sys;
841     struct dvb_frontend_parameters fep;
842     int i_ret;
843     vlc_value_t val;
844     int i_frequency, i_lnb_slof = 0, i_lnb_lof1, i_lnb_lof2 = 0;
845
846     /* Prepare the fep structure */
847     var_Get( p_access, "dvb-frequency", &val );
848     i_frequency = val.i_int;
849
850     var_Get( p_access, "dvb-lnb-lof1", &val );
851     if ( val.i_int == 0 )
852     {
853         /* Automatic mode. */
854         if ( i_frequency >= 950000 && i_frequency <= 2150000 )
855         {
856             msg_Dbg( p_access, "frequency %d is in IF-band", i_frequency );
857             i_lnb_lof1 = 0;
858         }
859         else if ( i_frequency >= 2500000 && i_frequency <= 2700000 )
860         {
861             msg_Dbg( p_access, "frequency %d is in S-band", i_frequency );
862             i_lnb_lof1 = 3650000;
863         }
864         else if ( i_frequency >= 3400000 && i_frequency <= 4200000 )
865         {
866             msg_Dbg( p_access, "frequency %d is in C-band (lower)",
867                      i_frequency );
868             i_lnb_lof1 = 5150000;
869         }
870         else if ( i_frequency >= 4500000 && i_frequency <= 4800000 )
871         {
872             msg_Dbg( p_access, "frequency %d is in C-band (higher)",
873                      i_frequency );
874             i_lnb_lof1 = 5950000;
875         }
876         else if ( i_frequency >= 10700000 && i_frequency <= 13250000 )
877         {
878             msg_Dbg( p_access, "frequency %d is in Ku-band",
879                      i_frequency );
880             i_lnb_lof1 = 9750000;
881             i_lnb_lof2 = 10600000;
882             i_lnb_slof = 11700000;
883         }
884         else
885         {
886             msg_Err( p_access, "frequency %d is out of any known band",
887                      i_frequency );
888             msg_Err( p_access, "specify dvb-lnb-lof1 manually for the local "
889                      "oscillator frequency" );
890             return VLC_EGENERIC;
891         }
892         val.i_int = i_lnb_lof1;
893         var_Set( p_access, "dvb-lnb-lof1", val );
894         val.i_int = i_lnb_lof2;
895         var_Set( p_access, "dvb-lnb-lof2", val );
896         val.i_int = i_lnb_slof;
897         var_Set( p_access, "dvb-lnb-slof", val );
898     }
899     else
900     {
901         i_lnb_lof1 = val.i_int;
902         var_Get( p_access, "dvb-lnb-lof2", &val );
903         i_lnb_lof2 = val.i_int;
904         var_Get( p_access, "dvb-lnb-slof", &val );
905         i_lnb_slof = val.i_int;
906     }
907
908     if( i_lnb_slof && i_frequency >= i_lnb_slof )
909     {
910         i_frequency -= i_lnb_lof2;
911     }
912     else
913     {
914         i_frequency -= i_lnb_lof1;
915     }
916     fep.frequency = i_frequency >= 0 ? i_frequency : -i_frequency;
917
918     fep.inversion = DecodeInversion( p_access );
919
920     var_Get( p_access, "dvb-srate", &val );
921     fep.u.qpsk.symbol_rate = val.i_int;
922
923     var_Get( p_access, "dvb-fec", &val );
924     fep.u.qpsk.fec_inner = DecodeFEC( p_access, val.i_int );
925
926     if( DoDiseqc( p_access ) < 0 )
927     {
928         return VLC_EGENERIC;
929     }
930
931     /* Empty the event queue */
932     for( ; ; )
933     {
934         struct dvb_frontend_event event;
935         if ( ioctl( p_sys->i_frontend_handle, FE_GET_EVENT, &event ) < 0
936               && errno == EWOULDBLOCK )
937             break;
938     }
939
940     /* Now send it all to the frontend device */
941     if( (i_ret = ioctl( p_sys->i_frontend_handle, FE_SET_FRONTEND, &fep )) < 0 )
942     {
943         msg_Err( p_access, "DVB-S: setting frontend failed (%d) %s", i_ret,
944                  strerror(errno) );
945         return VLC_EGENERIC;
946     }
947
948     return VLC_SUCCESS;
949 }
950
951 /*****************************************************************************
952  * FrontendSetQAM : controls the FE device
953  *****************************************************************************/
954 static int FrontendSetQAM( access_t *p_access )
955 {
956     access_sys_t *p_sys = p_access->p_sys;
957     struct dvb_frontend_parameters fep;
958     vlc_value_t val;
959     int i_ret;
960
961     /* Prepare the fep structure */
962
963     var_Get( p_access, "dvb-frequency", &val );
964     fep.frequency = val.i_int;
965
966     fep.inversion = DecodeInversion( p_access );
967
968     var_Get( p_access, "dvb-srate", &val );
969     fep.u.qam.symbol_rate = val.i_int;
970
971     var_Get( p_access, "dvb-fec", &val );
972     fep.u.qam.fec_inner = DecodeFEC( p_access, val.i_int );
973
974     fep.u.qam.modulation = DecodeModulation( p_access );
975
976     /* Empty the event queue */
977     for( ; ; )
978     {
979         struct dvb_frontend_event event;
980         if ( ioctl( p_sys->i_frontend_handle, FE_GET_EVENT, &event ) < 0
981               && errno == EWOULDBLOCK )
982             break;
983     }
984
985     /* Now send it all to the frontend device */
986     if( (i_ret = ioctl( p_sys->i_frontend_handle, FE_SET_FRONTEND, &fep )) < 0 )
987     {
988         msg_Err( p_access, "DVB-C: setting frontend failed (%d) %s", i_ret,
989                  strerror(errno) );
990         return VLC_EGENERIC;
991     }
992
993     return VLC_SUCCESS;
994 }
995
996 /*****************************************************************************
997  * FrontendSetOFDM : controls the FE device
998  *****************************************************************************/
999 static fe_bandwidth_t DecodeBandwidth( access_t *p_access )
1000 {
1001     vlc_value_t         val;
1002     fe_bandwidth_t      fe_bandwidth = 0;
1003
1004     var_Get( p_access, "dvb-bandwidth", &val );
1005     msg_Dbg( p_access, "using bandwidth=%d", val.i_int );
1006
1007     switch( val.i_int )
1008     {
1009         case 0: fe_bandwidth = BANDWIDTH_AUTO; break;
1010         case 6: fe_bandwidth = BANDWIDTH_6_MHZ; break;
1011         case 7: fe_bandwidth = BANDWIDTH_7_MHZ; break;
1012         case 8: fe_bandwidth = BANDWIDTH_8_MHZ; break;
1013         default:
1014             msg_Dbg( p_access, "terrestrial dvb has bandwidth not set, using auto" );
1015             fe_bandwidth = BANDWIDTH_AUTO;
1016             break;
1017     }
1018     return fe_bandwidth;
1019 }
1020
1021 static fe_transmit_mode_t DecodeTransmission( access_t *p_access )
1022 {
1023     vlc_value_t         val;
1024     fe_transmit_mode_t  fe_transmission = 0;
1025
1026     var_Get( p_access, "dvb-transmission", &val );
1027     msg_Dbg( p_access, "using transmission=%d", val.i_int );
1028
1029     switch( val.i_int )
1030     {
1031         case 0: fe_transmission = TRANSMISSION_MODE_AUTO; break;
1032         case 2: fe_transmission = TRANSMISSION_MODE_2K; break;
1033         case 8: fe_transmission = TRANSMISSION_MODE_8K; break;
1034         default:
1035             msg_Dbg( p_access, "terrestrial dvb has transmission mode not set, using auto");
1036             fe_transmission = TRANSMISSION_MODE_AUTO;
1037             break;
1038     }
1039     return fe_transmission;
1040 }
1041
1042 static fe_guard_interval_t DecodeGuardInterval( access_t *p_access )
1043 {
1044     vlc_value_t         val;
1045     fe_guard_interval_t fe_guard = 0;
1046
1047     var_Get( p_access, "dvb-guard", &val );
1048     msg_Dbg( p_access, "using guard=%d", val.i_int );
1049
1050     switch( val.i_int )
1051     {
1052         case 0: fe_guard = GUARD_INTERVAL_AUTO; break;
1053         case 4: fe_guard = GUARD_INTERVAL_1_4; break;
1054         case 8: fe_guard = GUARD_INTERVAL_1_8; break;
1055         case 16: fe_guard = GUARD_INTERVAL_1_16; break;
1056         case 32: fe_guard = GUARD_INTERVAL_1_32; break;
1057         default:
1058             msg_Dbg( p_access, "terrestrial dvb has guard interval not set, using auto");
1059             fe_guard = GUARD_INTERVAL_AUTO;
1060             break;
1061     }
1062     return fe_guard;
1063 }
1064
1065 static fe_hierarchy_t DecodeHierarchy( access_t *p_access )
1066 {
1067     vlc_value_t         val;
1068     fe_hierarchy_t      fe_hierarchy = 0;
1069
1070     var_Get( p_access, "dvb-hierarchy", &val );
1071     msg_Dbg( p_access, "using hierarchy=%d", val.i_int );
1072
1073     switch( val.i_int )
1074     {
1075         case -1: fe_hierarchy = HIERARCHY_NONE; break;
1076         case 0: fe_hierarchy = HIERARCHY_AUTO; break;
1077         case 1: fe_hierarchy = HIERARCHY_1; break;
1078         case 2: fe_hierarchy = HIERARCHY_2; break;
1079         case 4: fe_hierarchy = HIERARCHY_4; break;
1080         default:
1081             msg_Dbg( p_access, "terrestrial dvb has hierarchy not set, using auto");
1082             fe_hierarchy = HIERARCHY_AUTO;
1083             break;
1084     }
1085     return fe_hierarchy;
1086 }
1087
1088 static int FrontendSetOFDM( access_t * p_access )
1089 {
1090     access_sys_t *p_sys = p_access->p_sys;
1091     struct dvb_frontend_parameters fep;
1092     vlc_value_t val;
1093     int ret;
1094
1095     /* Prepare the fep structure */
1096
1097     var_Get( p_access, "dvb-frequency", &val );
1098     fep.frequency = val.i_int;
1099
1100     fep.inversion = DecodeInversion( p_access );
1101
1102     fep.u.ofdm.bandwidth = DecodeBandwidth( p_access );
1103     var_Get( p_access, "dvb-code-rate-hp", &val );
1104     fep.u.ofdm.code_rate_HP = DecodeFEC( p_access, val.i_int );
1105     var_Get( p_access, "dvb-code-rate-lp", &val );
1106     fep.u.ofdm.code_rate_LP = DecodeFEC( p_access, val.i_int );
1107     fep.u.ofdm.constellation = DecodeModulation( p_access );
1108     fep.u.ofdm.transmission_mode = DecodeTransmission( p_access );
1109     fep.u.ofdm.guard_interval = DecodeGuardInterval( p_access );
1110     fep.u.ofdm.hierarchy_information = DecodeHierarchy( p_access );
1111
1112     /* Empty the event queue */
1113     for( ; ; )
1114     {
1115         struct dvb_frontend_event event;
1116         if ( ioctl( p_sys->i_frontend_handle, FE_GET_EVENT, &event ) < 0
1117               && errno == EWOULDBLOCK )
1118             break;
1119     }
1120
1121     /* Now send it all to the frontend device */
1122     if( (ret = ioctl( p_sys->i_frontend_handle, FE_SET_FRONTEND, &fep )) < 0 )
1123     {
1124         msg_Err( p_access, "DVB-T: setting frontend failed (%d) %s", ret,
1125                  strerror(errno) );
1126         return -1;
1127     }
1128
1129     return VLC_SUCCESS;
1130 }
1131
1132
1133 /*
1134  * Demux
1135  */
1136
1137 /*****************************************************************************
1138  * DMXSetFilter : controls the demux to add a filter
1139  *****************************************************************************/
1140 int E_(DMXSetFilter)( access_t * p_access, int i_pid, int * pi_fd, int i_type )
1141 {
1142     struct dmx_pes_filter_params s_filter_params;
1143     int i_ret;
1144     unsigned int i_adapter, i_device;
1145     char dmx[128];
1146     vlc_value_t val;
1147
1148     var_Get( p_access, "dvb-adapter", &val );
1149     i_adapter = val.i_int;
1150     var_Get( p_access, "dvb-device", &val );
1151     i_device = val.i_int;
1152
1153     if( snprintf( dmx, sizeof(dmx), DMX, i_adapter, i_device )
1154             >= (int)sizeof(dmx) )
1155     {
1156         msg_Err( p_access, "snprintf() truncated string for DMX" );
1157         dmx[sizeof(dmx) - 1] = '\0';
1158     }
1159
1160     msg_Dbg( p_access, "Opening device %s", dmx );
1161     if( (*pi_fd = open(dmx, O_RDWR)) < 0 )
1162     {
1163         msg_Err( p_access, "DMXSetFilter: opening device failed (%s)",
1164                  strerror(errno) );
1165         return VLC_EGENERIC;
1166     }
1167
1168     /* We fill the DEMUX structure : */
1169     s_filter_params.pid     =   i_pid;
1170     s_filter_params.input   =   DMX_IN_FRONTEND;
1171     s_filter_params.output  =   DMX_OUT_TS_TAP;
1172     s_filter_params.flags   =   DMX_IMMEDIATE_START;
1173
1174     switch ( i_type )
1175     {   /* First device */
1176         case 1:
1177             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_VIDEO0 for PID %d", i_pid);
1178             s_filter_params.pes_type = DMX_PES_VIDEO0;
1179             break;
1180         case 2:
1181             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_AUDIO0 for PID %d", i_pid);
1182             s_filter_params.pes_type = DMX_PES_AUDIO0;
1183             break;
1184         case 3:
1185             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_TELETEXT0 for PID %d", i_pid);
1186             s_filter_params.pes_type = DMX_PES_TELETEXT0;
1187             break;
1188         case 4:
1189             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_SUBTITLE0 for PID %d", i_pid);
1190             s_filter_params.pes_type = DMX_PES_SUBTITLE0;
1191             break;
1192         case 5:
1193             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_PCR0 for PID %d", i_pid);
1194             s_filter_params.pes_type = DMX_PES_PCR0;
1195             break;
1196         /* Second device */
1197         case 6:
1198             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_VIDEO1 for PID %d", i_pid);
1199             s_filter_params.pes_type = DMX_PES_VIDEO1;
1200             break;
1201         case 7:
1202             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_AUDIO1 for PID %d", i_pid);
1203             s_filter_params.pes_type = DMX_PES_AUDIO1;
1204             break;
1205         case 8:
1206             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_TELETEXT1 for PID %d", i_pid);
1207             s_filter_params.pes_type = DMX_PES_TELETEXT1;
1208             break;
1209         case 9:
1210             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_SUBTITLE1 for PID %d", i_pid);
1211             s_filter_params.pes_type = DMX_PES_SUBTITLE1;
1212             break;
1213         case 10:
1214             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_PCR1 for PID %d", i_pid);
1215             s_filter_params.pes_type = DMX_PES_PCR1;
1216             break;
1217         /* Third device */
1218         case 11:
1219             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_VIDEO2 for PID %d", i_pid);
1220             s_filter_params.pes_type = DMX_PES_VIDEO2;
1221             break;
1222         case 12:
1223             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_AUDIO2 for PID %d", i_pid);
1224             s_filter_params.pes_type = DMX_PES_AUDIO2;
1225             break;
1226         case 13:
1227             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_TELETEXT2 for PID %d", i_pid);
1228             s_filter_params.pes_type = DMX_PES_TELETEXT2;
1229             break;
1230         case 14:
1231             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_SUBTITLE2 for PID %d", i_pid);
1232             s_filter_params.pes_type = DMX_PES_SUBTITLE2;
1233             break;
1234         case 15:
1235             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_PCR2 for PID %d", i_pid);
1236             s_filter_params.pes_type = DMX_PES_PCR2;
1237             break;
1238         /* Forth device */
1239         case 16:
1240             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_VIDEO3 for PID %d", i_pid);
1241             s_filter_params.pes_type = DMX_PES_VIDEO3;
1242             break;
1243         case 17:
1244             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_AUDIO3 for PID %d", i_pid);
1245             s_filter_params.pes_type = DMX_PES_AUDIO3;
1246             break;
1247         case 18:
1248             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_TELETEXT3 for PID %d", i_pid);
1249             s_filter_params.pes_type = DMX_PES_TELETEXT3;
1250             break;
1251         case 19:
1252             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_SUBTITLE3 for PID %d", i_pid);
1253             s_filter_params.pes_type = DMX_PES_SUBTITLE3;
1254             break;
1255         case 20:
1256             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_PCR3 for PID %d", i_pid);
1257             s_filter_params.pes_type = DMX_PES_PCR3;
1258             break;
1259         /* Usually used by Nova cards */
1260         case 21:
1261         default:
1262             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_OTHER for PID %d", i_pid);
1263             s_filter_params.pes_type = DMX_PES_OTHER;
1264             break;
1265     }
1266
1267     /* We then give the order to the device : */
1268     if( (i_ret = ioctl( *pi_fd, DMX_SET_PES_FILTER, &s_filter_params )) < 0 )
1269     {
1270         msg_Err( p_access, "DMXSetFilter: failed with %d (%s)", i_ret,
1271                  strerror(errno) );
1272         return VLC_EGENERIC;
1273     }
1274     return VLC_SUCCESS;
1275 }
1276
1277 /*****************************************************************************
1278  * DMXUnsetFilter : removes a filter
1279  *****************************************************************************/
1280 int E_(DMXUnsetFilter)( access_t * p_access, int i_fd )
1281 {
1282     int i_ret;
1283
1284     if( (i_ret = ioctl( i_fd, DMX_STOP )) < 0 )
1285     {
1286         msg_Err( p_access, "DMX_STOP failed for demux (%d) %s",
1287                  i_ret, strerror(errno) );
1288         return i_ret;
1289     }
1290
1291     msg_Dbg( p_access, "DMXUnsetFilter: closing demux %d", i_fd );
1292     close( i_fd );
1293     return VLC_SUCCESS;
1294 }
1295
1296
1297 /*
1298  * DVR device
1299  */
1300
1301 /*****************************************************************************
1302  * DVROpen :
1303  *****************************************************************************/
1304 int E_(DVROpen)( access_t * p_access )
1305 {
1306     access_sys_t *p_sys = p_access->p_sys;
1307     unsigned int i_adapter, i_device;
1308     char dvr[128];
1309     vlc_value_t val;
1310
1311     var_Get( p_access, "dvb-adapter", &val );
1312     i_adapter = val.i_int;
1313     var_Get( p_access, "dvb-device", &val );
1314     i_device = val.i_int;
1315
1316     if( snprintf( dvr, sizeof(dvr), DVR, i_adapter, i_device )
1317             >= (int)sizeof(dvr) )
1318     {
1319         msg_Err( p_access, "snprintf() truncated string for DVR" );
1320         dvr[sizeof(dvr) - 1] = '\0';
1321     }
1322
1323     msg_Dbg( p_access, "Opening device %s", dvr );
1324     if( (p_sys->i_handle = open(dvr, O_RDONLY)) < 0 )
1325     {
1326         msg_Err( p_access, "DVROpen: opening device failed (%s)",
1327                  strerror(errno) );
1328         return VLC_EGENERIC;
1329     }
1330
1331     if( fcntl( p_sys->i_handle, F_SETFL, O_NONBLOCK ) == -1 )
1332     {
1333         msg_Warn( p_access, "DVROpen: couldn't set non-blocking mode (%s)",
1334                   strerror(errno) );
1335     }
1336
1337     return VLC_SUCCESS;
1338 }
1339
1340 /*****************************************************************************
1341  * DVRClose :
1342  *****************************************************************************/
1343 void E_(DVRClose)( access_t * p_access )
1344 {
1345     access_sys_t *p_sys = p_access->p_sys;
1346
1347     close( p_sys->i_handle );
1348 }
1349
1350
1351 /*
1352  * CAM device
1353  */
1354
1355 /*****************************************************************************
1356  * CAMOpen :
1357  *****************************************************************************/
1358 int E_(CAMOpen)( access_t *p_access )
1359 {
1360     access_sys_t *p_sys = p_access->p_sys;
1361     char ca[128];
1362     int i_adapter, i_device;
1363     ca_caps_t caps;
1364
1365     i_adapter = var_GetInteger( p_access, "dvb-adapter" );
1366     i_device = var_GetInteger( p_access, "dvb-device" );
1367
1368     if( snprintf( ca, sizeof(ca), CA, i_adapter, i_device ) >= (int)sizeof(ca) )
1369     {
1370         msg_Err( p_access, "snprintf() truncated string for CA" );
1371         ca[sizeof(ca) - 1] = '\0';
1372     }
1373     memset( &caps, 0, sizeof( ca_caps_t ));
1374
1375     msg_Dbg( p_access, "Opening device %s", ca );
1376     if( (p_sys->i_ca_handle = open(ca, O_RDWR | O_NONBLOCK)) < 0 )
1377     {
1378         msg_Warn( p_access, "CAMInit: opening CAM device failed (%s)",
1379                   strerror(errno) );
1380         p_sys->i_ca_handle = 0;
1381         return VLC_EGENERIC;
1382     }
1383
1384     if ( ioctl( p_sys->i_ca_handle, CA_GET_CAP, &caps ) != 0 )
1385     {
1386         msg_Err( p_access, "CAMInit: ioctl() error getting CAM capabilities" );
1387         close( p_sys->i_ca_handle );
1388         p_sys->i_ca_handle = 0;
1389         return VLC_EGENERIC;
1390     }
1391
1392     /* Output CA capabilities */
1393     msg_Dbg( p_access, "CAMInit: CA interface with %d %s", caps.slot_num, 
1394         caps.slot_num == 1 ? "slot" : "slots" );
1395     if ( caps.slot_type & CA_CI )
1396         msg_Dbg( p_access, "CAMInit: CI high level interface type" );
1397     if ( caps.slot_type & CA_CI_LINK )
1398         msg_Dbg( p_access, "CAMInit: CI link layer level interface type" );
1399     if ( caps.slot_type & CA_CI_PHYS )
1400         msg_Dbg( p_access, "CAMInit: CI physical layer level interface type (not supported) " );
1401     if ( caps.slot_type & CA_DESCR )
1402         msg_Dbg( p_access, "CAMInit: built-in descrambler detected" );
1403     if ( caps.slot_type & CA_SC )
1404         msg_Dbg( p_access, "CAMInit: simple smart card interface" );
1405
1406     msg_Dbg( p_access, "CAMInit: %d available %s", caps.descr_num,
1407         caps.descr_num == 1 ? "descrambler (key)" : "descramblers (keys)" );
1408     if ( caps.descr_type & CA_ECD )
1409         msg_Dbg( p_access, "CAMInit: ECD scrambling system supported" );
1410     if ( caps.descr_type & CA_NDS )
1411         msg_Dbg( p_access, "CAMInit: NDS scrambling system supported" );
1412     if ( caps.descr_type & CA_DSS )
1413         msg_Dbg( p_access, "CAMInit: DSS scrambling system supported" );
1414  
1415     if ( caps.slot_num == 0 )
1416     {
1417         msg_Err( p_access, "CAMInit: CAM module with no slots" );
1418         close( p_sys->i_ca_handle );
1419         p_sys->i_ca_handle = 0;
1420         return VLC_EGENERIC;
1421     }
1422
1423     p_sys->i_ca_type = caps.slot_type;
1424     if ( !(caps.slot_type & CA_CI_LINK) &&
1425          !(caps.slot_type & CA_CI) )
1426     {
1427         msg_Err( p_access, "CAMInit: incompatible CAM interface" );
1428         close( p_sys->i_ca_handle );
1429         p_sys->i_ca_handle = 0;
1430         return VLC_EGENERIC;
1431     }
1432
1433     p_sys->i_nb_slots = caps.slot_num;
1434     memset( p_sys->pb_active_slot, 0, sizeof(vlc_bool_t) * MAX_CI_SLOTS );
1435
1436     return E_(en50221_Init)( p_access );
1437 }
1438
1439 /*****************************************************************************
1440  * CAMPoll :
1441  *****************************************************************************/
1442 int E_(CAMPoll)( access_t * p_access )
1443 {
1444     access_sys_t *p_sys = p_access->p_sys;
1445     int i_ret = VLC_EGENERIC;
1446
1447     if ( p_sys->i_ca_handle == 0 )
1448     {
1449         return VLC_EGENERIC;
1450     }
1451
1452     switch( p_sys->i_ca_type )
1453     {
1454     case CA_CI_LINK:
1455         i_ret = E_(en50221_Poll)( p_access );
1456         break;
1457     case CA_CI:
1458         i_ret = VLC_SUCCESS;
1459         break;
1460     default:
1461         msg_Err( p_access, "CAMPoll: This should not happen" );
1462         break;
1463     }
1464
1465     return i_ret;
1466 }
1467
1468 #ifdef ENABLE_HTTPD
1469 /*****************************************************************************
1470  * CAMStatus :
1471  *****************************************************************************/
1472 void E_(CAMStatus)( access_t * p_access )
1473 {
1474     access_sys_t *p_sys = p_access->p_sys;
1475     char *p;
1476     ca_caps_t caps;
1477     int i_slot, i;
1478
1479     if ( p_sys->psz_request != NULL && *p_sys->psz_request )
1480     {
1481         /* Check if we have an undisplayed MMI message : in that case we ignore
1482          * the user input to avoid confusing the CAM. */
1483         for ( i_slot = 0; i_slot < p_sys->i_nb_slots; i_slot++ )
1484         {
1485             if ( p_sys->pb_slot_mmi_undisplayed[i_slot] == VLC_TRUE )
1486             {
1487                 p_sys->psz_request = NULL;
1488                 msg_Dbg( p_access,
1489                          "ignoring user request because of a new MMI object" );
1490                 break;
1491             }
1492         }
1493     }
1494
1495     if ( p_sys->psz_request != NULL && *p_sys->psz_request )
1496     {
1497         /* We have a mission to accomplish. */
1498         en50221_mmi_object_t mmi_object;
1499         char *psz_request = p_sys->psz_request;
1500         char psz_value[255];
1501         int i_slot;
1502         vlc_bool_t b_ok = VLC_FALSE;
1503
1504         p_sys->psz_request = NULL;
1505
1506         if ( E_(HTTPExtractValue)( psz_request, "slot", psz_value,
1507                                    sizeof(psz_value) ) == NULL )
1508         {
1509             p_sys->psz_mmi_info = strdup( "invalid request parameter\n" );
1510             goto out;
1511         }
1512         i_slot = atoi(psz_value);
1513
1514         if ( E_(HTTPExtractValue)( psz_request, "open", psz_value,
1515                                    sizeof(psz_value) ) != NULL )
1516         {
1517             E_(en50221_OpenMMI)( p_access, i_slot );
1518             return;
1519         }
1520
1521         if ( E_(HTTPExtractValue)( psz_request, "close", psz_value,
1522                                    sizeof(psz_value) ) != NULL )
1523         {
1524             E_(en50221_CloseMMI)( p_access, i_slot );
1525             return;
1526         }
1527
1528         if ( E_(HTTPExtractValue)( psz_request, "cancel", psz_value,
1529                                    sizeof(psz_value) ) == NULL )
1530         {
1531             b_ok = VLC_TRUE;
1532         }
1533
1534         if ( E_(HTTPExtractValue)( psz_request, "type", psz_value,
1535                                    sizeof(psz_value) ) == NULL )
1536         {
1537             p_sys->psz_mmi_info = strdup( "invalid request parameter\n" );
1538             goto out;
1539         }
1540
1541         if ( !strcmp( psz_value, "enq" ) )
1542         {
1543             mmi_object.i_object_type = EN50221_MMI_ANSW;
1544             mmi_object.u.answ.b_ok = b_ok;
1545             if ( b_ok == VLC_FALSE )
1546             {
1547                 mmi_object.u.answ.psz_answ = strdup("");
1548             }
1549             else
1550             {
1551                 if ( E_(HTTPExtractValue)( psz_request, "answ", psz_value,
1552                                            sizeof(psz_value) ) == NULL )
1553                 {
1554                     p_sys->psz_mmi_info = strdup( "invalid request parameter\n" );
1555                     goto out;
1556                 }
1557
1558                 mmi_object.u.answ.psz_answ = strdup(psz_value);
1559             }
1560         }
1561         else
1562         {
1563             mmi_object.i_object_type = EN50221_MMI_MENU_ANSW;
1564             if ( b_ok == VLC_FALSE )
1565             {
1566                 mmi_object.u.menu_answ.i_choice = 0;
1567             }
1568             else
1569             {
1570                 if ( E_(HTTPExtractValue)( psz_request, "choice", psz_value,
1571                                            sizeof(psz_value) ) == NULL )
1572                     mmi_object.u.menu_answ.i_choice = 0;
1573                 else
1574                     mmi_object.u.menu_answ.i_choice = atoi(psz_value);
1575             }
1576         }
1577
1578         E_(en50221_SendMMIObject)( p_access, i_slot, &mmi_object );
1579         return;
1580     }
1581
1582     /* Check that we have all necessary MMI information. */
1583     for ( i_slot = 0; i_slot < p_sys->i_nb_slots; i_slot++ )
1584     {
1585         if ( p_sys->pb_slot_mmi_expected[i_slot] == VLC_TRUE )
1586             return;
1587     }
1588
1589     p = p_sys->psz_mmi_info = malloc( 10000 );
1590
1591     if ( ioctl( p_sys->i_ca_handle, CA_GET_CAP, &caps ) != 0 )
1592     {
1593         p += sprintf( p, "ioctl CA_GET_CAP failed (%s)\n",
1594                       strerror(errno) );
1595         goto out;
1596     }
1597
1598     /* Output CA capabilities */
1599     p += sprintf( p, "CA interface with %d %s, type:\n<table>", caps.slot_num,
1600                   caps.slot_num == 1 ? "slot" : "slots" );
1601 #define CHECK_CAPS( x, s )                                                  \
1602     if ( caps.slot_type & (CA_##x) )                                        \
1603         p += sprintf( p, "<tr><td>" s "</td></tr>\n" );
1604
1605     CHECK_CAPS( CI, "CI high level interface" );
1606     CHECK_CAPS( CI_LINK, "CI link layer level interface" );
1607     CHECK_CAPS( CI_PHYS, "CI physical layer level interface (not supported)" );
1608     CHECK_CAPS( DESCR, "built-in descrambler" );
1609     CHECK_CAPS( SC, "simple smartcard interface" );
1610 #undef CHECK_CAPS
1611
1612     p += sprintf( p, "</table>%d available %s\n<table>", caps.descr_num,
1613         caps.descr_num == 1 ? "descrambler (key)" : "descramblers (keys)" );
1614 #define CHECK_DESC( x )                                                     \
1615     if ( caps.descr_type & (CA_##x) )                                       \
1616         p += sprintf( p, "<tr><td>" STRINGIFY(x) "</td></tr>\n" );
1617
1618     CHECK_DESC( ECD );
1619     CHECK_DESC( NDS );
1620     CHECK_DESC( DSS );
1621 #undef CHECK_DESC
1622
1623     p += sprintf( p, "</table>" );
1624
1625     for ( i_slot = 0; i_slot < p_sys->i_nb_slots; i_slot++ )
1626     {
1627         ca_slot_info_t sinfo;
1628
1629         p_sys->pb_slot_mmi_undisplayed[i_slot] = VLC_FALSE;
1630         p += sprintf( p, "<p>CA slot #%d: ", i_slot );
1631
1632         sinfo.num = i_slot;
1633         if ( ioctl( p_sys->i_ca_handle, CA_GET_SLOT_INFO, &sinfo ) != 0 )
1634         {
1635             p += sprintf( p, "ioctl CA_GET_SLOT_INFO failed (%s)<br>\n",
1636                           strerror(errno) );
1637             continue;
1638         }
1639
1640 #define CHECK_TYPE( x, s )                                                  \
1641         if ( sinfo.type & (CA_##x) )                                        \
1642             p += sprintf( p, s );
1643
1644         CHECK_TYPE( CI, "high level, " );
1645         CHECK_TYPE( CI_LINK, "link layer level, " );
1646         CHECK_TYPE( CI_PHYS, "physical layer level, " );
1647 #undef CHECK_TYPE
1648
1649         if ( sinfo.flags & CA_CI_MODULE_READY )
1650         {
1651             en50221_mmi_object_t *p_object = E_(en50221_GetMMIObject)( p_access,
1652                                                                        i_slot );
1653
1654             p += sprintf( p, "module present and ready<p>\n" );
1655             p += sprintf( p, "<form action=index.html method=get>\n" );
1656             p += sprintf( p, "<input type=hidden name=slot value=\"%d\">\n",
1657                           i_slot );
1658
1659             if ( p_object == NULL )
1660             {
1661                 p += sprintf( p, "<input type=submit name=open value=\"Open session\">\n" );
1662             }
1663             else
1664             {
1665                 switch ( p_object->i_object_type )
1666                 {
1667                 case EN50221_MMI_ENQ:
1668                     p += sprintf( p, "<input type=hidden name=type value=enq>\n" );
1669                     p += sprintf( p, "<table border=1><tr><th>%s</th></tr>\n",
1670                                   p_object->u.enq.psz_text );
1671                     if ( p_object->u.enq.b_blind == VLC_FALSE )
1672                         p += sprintf( p, "<tr><td><input type=text name=answ></td></tr>\n" );
1673                     else
1674                         p += sprintf( p, "<tr><td><input type=password name=answ></td></tr>\n" );
1675                     break;
1676
1677                 case EN50221_MMI_MENU:
1678                     p += sprintf( p, "<input type=hidden name=type value=menu>\n" );
1679                     p += sprintf( p, "<table border=1><tr><th>%s</th></tr>\n",
1680                                   p_object->u.menu.psz_title );
1681                     p += sprintf( p, "<tr><td>%s</td></tr><tr><td>\n",
1682                                   p_object->u.menu.psz_subtitle );
1683                     for ( i = 0; i < p_object->u.menu.i_choices; i++ )
1684                         p += sprintf( p, "<input type=radio name=choice value=\"%d\">%s<br>\n", i + 1, p_object->u.menu.ppsz_choices[i] );
1685                     p += sprintf( p, "</td></tr><tr><td>%s</td></tr>\n",
1686                                   p_object->u.menu.psz_bottom );
1687                     break;
1688
1689                 case EN50221_MMI_LIST:
1690                     p += sprintf( p, "<input type=hidden name=type value=menu>\n" );
1691                     p += sprintf( p, "<input type=hidden name=choice value=0>\n" );
1692                     p += sprintf( p, "<table border=1><tr><th>%s</th></tr>\n",
1693                                   p_object->u.menu.psz_title );
1694                     p += sprintf( p, "<tr><td>%s</td></tr><tr><td>\n",
1695                                   p_object->u.menu.psz_subtitle );
1696                     for ( i = 0; i < p_object->u.menu.i_choices; i++ )
1697                         p += sprintf( p, "%s<br>\n",
1698                                       p_object->u.menu.ppsz_choices[i] );
1699                     p += sprintf( p, "</td></tr><tr><td>%s</td></tr>\n",
1700                                   p_object->u.menu.psz_bottom );
1701                     break;
1702
1703                 default:
1704                     p += sprintf( p, "<table><tr><th>Unknown MMI object type</th></tr>\n" );
1705                 }
1706
1707                 p += sprintf( p, "</table><p><input type=submit name=ok value=\"OK\">\n" );
1708                 p += sprintf( p, "<input type=submit name=cancel value=\"Cancel\">\n" );
1709                 p += sprintf( p, "<input type=submit name=close value=\"Close Session\">\n" );
1710             }
1711             p += sprintf( p, "</form>\n" );
1712         }
1713         else if ( sinfo.flags & CA_CI_MODULE_PRESENT )
1714             p += sprintf( p, "module present, not ready<br>\n" );
1715         else
1716             p += sprintf( p, "module not present<br>\n" );
1717     }
1718
1719 out:
1720     vlc_mutex_lock( &p_sys->httpd_mutex );
1721     p_sys->b_request_mmi_info = VLC_FALSE;
1722     vlc_cond_signal( &p_sys->httpd_cond );
1723     vlc_mutex_unlock( &p_sys->httpd_mutex );
1724 }
1725 #endif
1726
1727 /*****************************************************************************
1728  * CAMSet :
1729  *****************************************************************************/
1730 int E_(CAMSet)( access_t * p_access, dvbpsi_pmt_t *p_pmt )
1731 {
1732     access_sys_t *p_sys = p_access->p_sys;
1733
1734     if ( p_sys->i_ca_handle == 0 )
1735     {
1736         return VLC_EGENERIC;
1737     }
1738
1739     E_(en50221_SetCAPMT)( p_access, p_pmt );
1740
1741     return VLC_SUCCESS;
1742 }
1743
1744 /*****************************************************************************
1745  * CAMClose :
1746  *****************************************************************************/
1747 void E_(CAMClose)( access_t * p_access )
1748 {
1749     access_sys_t *p_sys = p_access->p_sys;
1750
1751     E_(en50221_End)( p_access );
1752
1753     if ( p_sys->i_ca_handle )
1754     {
1755         close( p_sys->i_ca_handle );
1756     }
1757 }
1758