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