Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

linux_dvb.c

00001 /*****************************************************************************
00002  * linux_dvb.c : functions to control a DVB card under Linux with v4l2
00003  *****************************************************************************
00004  * Copyright (C) 1998-2004 the VideoLAN team
00005  *
00006  * Authors: Damien Lucas <[email protected]>
00007  *          Johan Bilien <[email protected]>
00008  *          Jean-Paul Saman <[email protected]>
00009  *          Christopher Ross <[email protected]>
00010  *          Christophe Massiot <[email protected]>
00011  *
00012  * This program is free software; you can redistribute it and/or modify
00013  * it under the terms of the GNU General Public License as published by
00014  * the Free Software Foundation; either version 2 of the License, or
00015  * (at your option) any later version.
00016  *
00017  * This program is distributed in the hope that it will be useful,
00018  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00019  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.    See the
00020  * GNU General Public License for more details.
00021  *
00022  * You should have received a copy of the GNU General Public License
00023  * along with this program; if not, write to the Free Software
00024  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA    02111, USA.
00025  *****************************************************************************/
00026 
00027 #include <vlc/vlc.h>
00028 #include <vlc/input.h>
00029 
00030 #include <sys/ioctl.h>
00031 #include <errno.h>
00032 
00033 #include <sys/types.h>
00034 #include <sys/stat.h>
00035 #include <fcntl.h>
00036 #include <time.h>
00037 #include <unistd.h>
00038 #include <sys/stat.h>
00039 #include <sys/poll.h>
00040 
00041 /* DVB Card Drivers */
00042 #include <linux/dvb/version.h>
00043 #include <linux/dvb/dmx.h>
00044 #include <linux/dvb/frontend.h>
00045 #include <linux/dvb/ca.h>
00046 
00047 /* Include dvbpsi headers */
00048 #ifdef HAVE_DVBPSI_DR_H
00049 #   include <dvbpsi/dvbpsi.h>
00050 #   include <dvbpsi/descriptor.h>
00051 #   include <dvbpsi/pat.h>
00052 #   include <dvbpsi/pmt.h>
00053 #   include <dvbpsi/dr.h>
00054 #   include <dvbpsi/psi.h>
00055 #else
00056 #   include "dvbpsi.h"
00057 #   include "descriptor.h"
00058 #   include "tables/pat.h"
00059 #   include "tables/pmt.h"
00060 #   include "descriptors/dr.h"
00061 #   include "psi.h"
00062 #endif
00063 
00064 #include "dvb.h"
00065 
00066 /*
00067  * Frontends
00068  */
00069 struct frontend_t
00070 {
00071     fe_status_t i_last_status;
00072     struct dvb_frontend_info info;
00073 };
00074 
00075 #define FRONTEND_LOCK_TIMEOUT 10000000 /* 10 s */
00076 
00077 /* Local prototypes */
00078 static int FrontendInfo( access_t * );
00079 static int FrontendSetQPSK( access_t * );
00080 static int FrontendSetQAM( access_t * );
00081 static int FrontendSetOFDM( access_t * );
00082 
00083 /*****************************************************************************
00084  * FrontendOpen : Determine frontend device information and capabilities
00085  *****************************************************************************/
00086 int E_(FrontendOpen)( access_t *p_access )
00087 {
00088     access_sys_t *p_sys = p_access->p_sys;
00089     frontend_t * p_frontend;
00090     unsigned int i_adapter, i_device;
00091     vlc_bool_t b_probe;
00092     char frontend[128];
00093 
00094     i_adapter = var_GetInteger( p_access, "dvb-adapter" );
00095     i_device = var_GetInteger( p_access, "dvb-device" );
00096     b_probe = var_GetBool( p_access, "dvb-probe" );
00097 
00098     if( snprintf( frontend, sizeof(frontend), FRONTEND, i_adapter, i_device ) >= (int)sizeof(frontend) )
00099     {
00100         msg_Err( p_access, "snprintf() truncated string for FRONTEND" );
00101         frontend[sizeof(frontend) - 1] = '\0';
00102     }
00103 
00104     p_sys->p_frontend = p_frontend = malloc( sizeof(frontend_t) );
00105 
00106     msg_Dbg( p_access, "Opening device %s", frontend );
00107     if( (p_sys->i_frontend_handle = open(frontend, O_RDWR | O_NONBLOCK)) < 0 )
00108     {
00109         msg_Err( p_access, "FrontEndOpen: opening device failed (%s)",
00110                  strerror(errno) );
00111         free( p_frontend );
00112         return VLC_EGENERIC;
00113     }
00114 
00115     if( b_probe )
00116     {
00117         char * psz_expected = NULL;
00118         char * psz_real;
00119 
00120         if( FrontendInfo( p_access ) < 0 )
00121         {
00122             close( p_sys->i_frontend_handle );
00123             free( p_frontend );
00124             return VLC_EGENERIC;
00125         }
00126 
00127         switch( p_frontend->info.type )
00128         {
00129         case FE_OFDM:
00130             psz_real = "DVB-T";
00131             break;
00132         case FE_QAM:
00133             psz_real = "DVB-C";
00134             break;
00135         case FE_QPSK:
00136             psz_real = "DVB-S";
00137             break;
00138         default:
00139             psz_real = "unknown";
00140         }
00141 
00142         /* Sanity checks */
00143         if( (!strncmp( p_access->psz_access, "qpsk", 4 ) ||
00144              !strncmp( p_access->psz_access, "dvb-s", 5 ) ||
00145              !strncmp( p_access->psz_access, "satellite", 9 ) ) &&
00146              (p_frontend->info.type != FE_QPSK) )
00147         {
00148             psz_expected = "DVB-S";
00149         }
00150         if( (!strncmp( p_access->psz_access, "cable", 5 ) ||
00151              !strncmp( p_access->psz_access, "dvb-c", 5 ) ) &&
00152              (p_frontend->info.type != FE_QAM) )
00153         {
00154             psz_expected = "DVB-C";
00155         }
00156         if( (!strncmp( p_access->psz_access, "terrestrial", 11 ) ||
00157              !strncmp( p_access->psz_access, "dvb-t", 5 ) ) &&
00158              (p_frontend->info.type != FE_OFDM) )
00159         {
00160             psz_expected = "DVB-T";
00161         }
00162 
00163         if( psz_expected != NULL )
00164         {
00165             msg_Err( p_access, "the user asked for %s, and the tuner is %s",
00166                      psz_expected, psz_real );
00167             close( p_sys->i_frontend_handle );
00168             free( p_frontend );
00169             return VLC_EGENERIC;
00170         }
00171     }
00172     else /* no frontend probing is done so use default border values. */
00173     {
00174         msg_Dbg( p_access, "using default values for frontend info" );
00175 
00176         msg_Dbg( p_access, "method of access is %s", p_access->psz_access );
00177         p_frontend->info.type = FE_QPSK;
00178         if( !strncmp( p_access->psz_access, "qpsk", 4 ) ||
00179             !strncmp( p_access->psz_access, "dvb-s", 5 ) )
00180             p_frontend->info.type = FE_QPSK;
00181         else if( !strncmp( p_access->psz_access, "cable", 5 ) ||
00182                  !strncmp( p_access->psz_access, "dvb-c", 5 ) )
00183             p_frontend->info.type = FE_QAM;
00184         else if( !strncmp( p_access->psz_access, "terrestrial", 11 ) ||
00185                  !strncmp( p_access->psz_access, "dvb-t", 5 ) )
00186             p_frontend->info.type = FE_OFDM;
00187     }
00188 
00189     return VLC_SUCCESS;
00190 }
00191 
00192 /*****************************************************************************
00193  * FrontendClose : Close the frontend
00194  *****************************************************************************/
00195 void E_(FrontendClose)( access_t *p_access )
00196 {
00197     access_sys_t *p_sys = p_access->p_sys;
00198 
00199     if( p_sys->p_frontend )
00200     {
00201         close( p_sys->i_frontend_handle );
00202         free( p_sys->p_frontend );
00203 
00204         p_sys->p_frontend = NULL;
00205     }
00206 }
00207 
00208 /*****************************************************************************
00209  * FrontendSet : Tune !
00210  *****************************************************************************/
00211 int E_(FrontendSet)( access_t *p_access )
00212 {
00213     access_sys_t *p_sys = p_access->p_sys;
00214 
00215     switch( p_sys->p_frontend->info.type )
00216     {
00217     /* DVB-S */
00218     case FE_QPSK:
00219         if( FrontendSetQPSK( p_access ) < 0 )
00220         {
00221             msg_Err( p_access, "DVB-S: tuning failed" );
00222             return VLC_EGENERIC;
00223         }
00224         break;
00225 
00226     /* DVB-C */
00227     case FE_QAM:
00228         if( FrontendSetQAM( p_access ) < 0 )
00229         {
00230             msg_Err( p_access, "DVB-C: tuning failed" );
00231             return VLC_EGENERIC;
00232         }
00233         break;
00234 
00235     /* DVB-T */
00236     case FE_OFDM:
00237         if( FrontendSetOFDM( p_access ) < 0 )
00238         {
00239             msg_Err( p_access, "DVB-T: tuning failed" );
00240             return VLC_EGENERIC;
00241         }
00242         break;
00243 
00244     default:
00245         msg_Err( p_access, "Could not determine frontend type on %s",
00246                  p_sys->p_frontend->info.name );
00247         return VLC_EGENERIC;
00248     }
00249     p_sys->p_frontend->i_last_status = 0;
00250     p_sys->i_frontend_timeout = mdate() + FRONTEND_LOCK_TIMEOUT;
00251     return VLC_SUCCESS;
00252 }
00253 
00254 /*****************************************************************************
00255  * FrontendPoll : Poll for frontend events
00256  *****************************************************************************/
00257 void E_(FrontendPoll)( access_t *p_access )
00258 {
00259     access_sys_t *p_sys = p_access->p_sys;
00260     frontend_t * p_frontend = p_sys->p_frontend;
00261     struct dvb_frontend_event event;
00262     fe_status_t i_status, i_diff;
00263 
00264     for( ;; )
00265     {
00266         int i_ret = ioctl( p_sys->i_frontend_handle, FE_GET_EVENT, &event );
00267 
00268         if( i_ret < 0 )
00269         {
00270             if( errno == EWOULDBLOCK )
00271                 return;
00272 
00273             msg_Err( p_access, "reading frontend status failed (%d) %s",
00274                      i_ret, strerror(errno) );
00275             continue;
00276         }
00277 
00278         i_status = event.status;
00279         i_diff = i_status ^ p_frontend->i_last_status;
00280         p_frontend->i_last_status = i_status;
00281 
00282 #define IF_UP( x )                                                          \
00283     }                                                                       \
00284     if ( i_diff & (x) )                                                     \
00285     {                                                                       \
00286         if ( i_status & (x) )
00287 
00288         {
00289             IF_UP( FE_HAS_SIGNAL )
00290                 msg_Dbg( p_access, "frontend has acquired signal" );
00291             else
00292                 msg_Dbg( p_access, "frontend has lost signal" );
00293 
00294             IF_UP( FE_HAS_CARRIER )
00295                 msg_Dbg( p_access, "frontend has acquired carrier" );
00296             else
00297                 msg_Dbg( p_access, "frontend has lost carrier" );
00298 
00299             IF_UP( FE_HAS_VITERBI )
00300                 msg_Dbg( p_access, "frontend has acquired stable FEC" );
00301             else
00302                 msg_Dbg( p_access, "frontend has lost FEC" );
00303 
00304             IF_UP( FE_HAS_SYNC )
00305                 msg_Dbg( p_access, "frontend has acquired sync" );
00306             else
00307                 msg_Dbg( p_access, "frontend has lost sync" );
00308 
00309             IF_UP( FE_HAS_LOCK )
00310             {
00311                 int32_t i_value;
00312                 msg_Dbg( p_access, "frontend has acquired lock" );
00313                 p_sys->i_frontend_timeout = 0;
00314 
00315                 /* Read some statistics */
00316                 if( ioctl( p_sys->i_frontend_handle, FE_READ_BER, &i_value ) >= 0 )
00317                     msg_Dbg( p_access, "- Bit error rate: %d", i_value );
00318                 if( ioctl( p_sys->i_frontend_handle, FE_READ_SIGNAL_STRENGTH, &i_value ) >= 0 )
00319                     msg_Dbg( p_access, "- Signal strength: %d", i_value );
00320                 if( ioctl( p_sys->i_frontend_handle, FE_READ_SNR, &i_value ) >= 0 )
00321                     msg_Dbg( p_access, "- SNR: %d", i_value );
00322             }
00323             else
00324             {
00325                 msg_Dbg( p_access, "frontend has lost lock" );
00326                 p_sys->i_frontend_timeout = mdate() + FRONTEND_LOCK_TIMEOUT;
00327             }
00328 
00329             IF_UP( FE_REINIT )
00330             {
00331                 /* The frontend was reinited. */
00332                 msg_Warn( p_access, "reiniting frontend");
00333                 E_(FrontendSet)( p_access );
00334             }
00335         }
00336     }
00337 }
00338 /*****************************************************************************
00339  * FrontendInfo : Return information about given frontend
00340  *****************************************************************************/
00341 static int FrontendInfo( access_t *p_access )
00342 {
00343     access_sys_t *p_sys = p_access->p_sys;
00344     frontend_t *p_frontend = p_sys->p_frontend;
00345     int i_ret;
00346 
00347     /* Determine type of frontend */
00348     if( (i_ret = ioctl( p_sys->i_frontend_handle, FE_GET_INFO,
00349                         &p_frontend->info )) < 0 )
00350     {
00351         msg_Err( p_access, "ioctl FE_GET_INFO failed (%d) %s", i_ret,
00352                  strerror(errno) );
00353         return VLC_EGENERIC;
00354     }
00355 
00356     /* Print out frontend capabilities. */
00357     msg_Dbg(p_access, "Frontend Info:" );
00358     msg_Dbg(p_access, "  name = %s", p_frontend->info.name );
00359     switch( p_frontend->info.type )
00360     {
00361         case FE_QPSK:
00362             msg_Dbg( p_access, "  type = QPSK (DVB-S)" );
00363             break;
00364         case FE_QAM:
00365             msg_Dbg( p_access, "  type = QAM (DVB-C)" );
00366             break;
00367         case FE_OFDM:
00368             msg_Dbg( p_access, "  type = OFDM (DVB-T)" );
00369             break;
00370 #if 0 /* DVB_API_VERSION == 3 */
00371         case FE_MEMORY:
00372             msg_Dbg(p_access, "  type = MEMORY" );
00373             break;
00374         case FE_NET:
00375             msg_Dbg(p_access, "  type = NETWORK" );
00376             break;
00377 #endif
00378         default:
00379             msg_Err( p_access, "  unknown frontend type (%d)",
00380                      p_frontend->info.type );
00381             return VLC_EGENERIC;
00382     }
00383     msg_Dbg(p_access, "  frequency_min = %u (kHz)",
00384             p_frontend->info.frequency_min);
00385     msg_Dbg(p_access, "  frequency_max = %u (kHz)",
00386             p_frontend->info.frequency_max);
00387     msg_Dbg(p_access, "  frequency_stepsize = %u",
00388             p_frontend->info.frequency_stepsize);
00389     msg_Dbg(p_access, "  frequency_tolerance = %u",
00390             p_frontend->info.frequency_tolerance);
00391     msg_Dbg(p_access, "  symbol_rate_min = %u (kHz)",
00392             p_frontend->info.symbol_rate_min);
00393     msg_Dbg(p_access, "  symbol_rate_max = %u (kHz)",
00394             p_frontend->info.symbol_rate_max);
00395     msg_Dbg(p_access, "  symbol_rate_tolerance (ppm) = %u",
00396             p_frontend->info.symbol_rate_tolerance);
00397     msg_Dbg(p_access, "  notifier_delay (ms) = %u",
00398             p_frontend->info.notifier_delay );
00399 
00400     msg_Dbg(p_access, "Frontend Info capability list:");
00401     if( p_frontend->info.caps & FE_IS_STUPID)
00402         msg_Dbg(p_access, "  no capabilities - frontend is stupid!");
00403     if( p_frontend->info.caps & FE_CAN_INVERSION_AUTO)
00404         msg_Dbg(p_access, "  inversion auto");
00405     if( p_frontend->info.caps & FE_CAN_FEC_1_2)
00406         msg_Dbg(p_access, "  forward error correction 1/2");
00407     if( p_frontend->info.caps & FE_CAN_FEC_2_3)
00408         msg_Dbg(p_access, "  forward error correction 2/3");
00409     if( p_frontend->info.caps & FE_CAN_FEC_3_4)
00410         msg_Dbg(p_access, "  forward error correction 3/4");
00411     if( p_frontend->info.caps & FE_CAN_FEC_4_5)
00412         msg_Dbg(p_access, "  forward error correction 4/5");
00413     if( p_frontend->info.caps & FE_CAN_FEC_5_6)
00414         msg_Dbg(p_access, "  forward error correction 5/6");
00415     if( p_frontend->info.caps & FE_CAN_FEC_6_7)
00416         msg_Dbg(p_access, "  forward error correction 6/7");
00417     if( p_frontend->info.caps & FE_CAN_FEC_7_8)
00418         msg_Dbg(p_access, "  forward error correction 7/8");
00419     if( p_frontend->info.caps & FE_CAN_FEC_8_9)
00420         msg_Dbg(p_access, "  forward error correction 8/9");
00421     if( p_frontend->info.caps & FE_CAN_FEC_AUTO)
00422         msg_Dbg(p_access, "  forward error correction auto");
00423     if( p_frontend->info.caps & FE_CAN_QPSK)
00424         msg_Dbg(p_access, "  card can do QPSK");
00425     if( p_frontend->info.caps & FE_CAN_QAM_16)
00426         msg_Dbg(p_access, "  card can do QAM 16");
00427     if( p_frontend->info.caps & FE_CAN_QAM_32)
00428         msg_Dbg(p_access, "  card can do QAM 32");
00429     if( p_frontend->info.caps & FE_CAN_QAM_64)
00430         msg_Dbg(p_access, "  card can do QAM 64");
00431     if( p_frontend->info.caps & FE_CAN_QAM_128)
00432         msg_Dbg(p_access, "  card can do QAM 128");
00433     if( p_frontend->info.caps & FE_CAN_QAM_256)
00434         msg_Dbg(p_access, "  card can do QAM 256");
00435     if( p_frontend->info.caps & FE_CAN_QAM_AUTO)
00436         msg_Dbg(p_access, "  card can do QAM auto");
00437     if( p_frontend->info.caps & FE_CAN_TRANSMISSION_MODE_AUTO)
00438         msg_Dbg(p_access, "  transmission mode auto");
00439     if( p_frontend->info.caps & FE_CAN_BANDWIDTH_AUTO)
00440         msg_Dbg(p_access, "  bandwidth mode auto");
00441     if( p_frontend->info.caps & FE_CAN_GUARD_INTERVAL_AUTO)
00442         msg_Dbg(p_access, "  guard interval mode auto");
00443     if( p_frontend->info.caps & FE_CAN_HIERARCHY_AUTO)
00444         msg_Dbg(p_access, "  hierarchy mode auto");
00445     if( p_frontend->info.caps & FE_CAN_MUTE_TS)
00446         msg_Dbg(p_access, "  card can mute TS");
00447     if( p_frontend->info.caps & FE_CAN_RECOVER)
00448         msg_Dbg(p_access, "  card can recover from a cable unplug");
00449     msg_Dbg(p_access, "End of capability list");
00450 
00451     return VLC_SUCCESS;
00452 }
00453 
00454 /*****************************************************************************
00455  * Decoding the DVB parameters (common)
00456  *****************************************************************************/
00457 static fe_spectral_inversion_t DecodeInversion( access_t *p_access )
00458 {
00459     vlc_value_t         val;
00460     fe_spectral_inversion_t fe_inversion = 0;
00461 
00462     var_Get( p_access, "dvb-inversion", &val );
00463     msg_Dbg( p_access, "using inversion=%d", val.i_int );
00464 
00465     switch( val.i_int )
00466     {
00467         case 0: fe_inversion = INVERSION_OFF; break;
00468         case 1: fe_inversion = INVERSION_ON; break;
00469         case 2: fe_inversion = INVERSION_AUTO; break;
00470         default:
00471             msg_Dbg( p_access, "dvb has inversion not set, using auto");
00472             fe_inversion = INVERSION_AUTO;
00473             break;
00474     }
00475     return fe_inversion;
00476 }
00477 
00478 static fe_code_rate_t DecodeFEC( access_t *p_access, int i_val )
00479 {
00480     fe_code_rate_t      fe_fec = FEC_NONE;
00481 
00482     msg_Dbg( p_access, "using fec=%d", i_val );
00483 
00484     switch( i_val )
00485     {
00486         case 0: fe_fec = FEC_NONE; break;
00487         case 1: fe_fec = FEC_1_2; break;
00488         case 2: fe_fec = FEC_2_3; break;
00489         case 3: fe_fec = FEC_3_4; break;
00490         case 4: fe_fec = FEC_4_5; break;
00491         case 5: fe_fec = FEC_5_6; break;
00492         case 6: fe_fec = FEC_6_7; break;
00493         case 7: fe_fec = FEC_7_8; break;
00494         case 8: fe_fec = FEC_8_9; break;
00495         case 9: fe_fec = FEC_AUTO; break;
00496         default:
00497             /* cannot happen */
00498             fe_fec = FEC_NONE;
00499             msg_Err( p_access, "argument has invalid FEC (%d)", i_val);
00500             break;
00501     }
00502     return fe_fec;
00503 }
00504 
00505 static fe_modulation_t DecodeModulation( access_t *p_access )
00506 {
00507     vlc_value_t         val;
00508     fe_modulation_t     fe_modulation = 0;
00509 
00510     var_Get( p_access, "dvb-modulation", &val );
00511 
00512     switch( val.i_int )
00513     {
00514         case -1: fe_modulation = QPSK; break;
00515         case 0: fe_modulation = QAM_AUTO; break;
00516         case 16: fe_modulation = QAM_16; break;
00517         case 32: fe_modulation = QAM_32; break;
00518         case 64: fe_modulation = QAM_64; break;
00519         case 128: fe_modulation = QAM_128; break;
00520         case 256: fe_modulation = QAM_256; break;
00521         default:
00522             msg_Dbg( p_access, "terrestrial/cable dvb has constellation/modulation not set, using auto");
00523             fe_modulation = QAM_AUTO;
00524             break;
00525     }
00526     return fe_modulation;
00527 }
00528 
00529 /*****************************************************************************
00530  * FrontendSetQPSK : controls the FE device
00531  *****************************************************************************/
00532 static fe_sec_voltage_t DecodeVoltage( access_t *p_access )
00533 {
00534     vlc_value_t         val;
00535     fe_sec_voltage_t    fe_voltage;
00536 
00537     var_Get( p_access, "dvb-voltage", &val );
00538     msg_Dbg( p_access, "using voltage=%d", val.i_int );
00539 
00540     switch( val.i_int )
00541     {
00542         case 0: fe_voltage = SEC_VOLTAGE_OFF; break;
00543         case 13: fe_voltage = SEC_VOLTAGE_13; break;
00544         case 18: fe_voltage = SEC_VOLTAGE_18; break;
00545         default:
00546             fe_voltage = SEC_VOLTAGE_OFF;
00547             msg_Err( p_access, "argument has invalid voltage (%d)", val.i_int );
00548             break;
00549     }
00550     return fe_voltage;
00551 }
00552 
00553 static fe_sec_tone_mode_t DecodeTone( access_t *p_access )
00554 {
00555     vlc_value_t         val;
00556     fe_sec_tone_mode_t  fe_tone;
00557 
00558     var_Get( p_access, "dvb-tone", &val );
00559     msg_Dbg( p_access, "using tone=%d", val.i_int );
00560 
00561     switch( val.i_int )
00562     {
00563         case 0: fe_tone = SEC_TONE_OFF; break;
00564         case 1: fe_tone = SEC_TONE_ON; break;
00565         default:
00566             fe_tone = SEC_TONE_OFF;
00567             msg_Err( p_access, "argument has invalid tone mode (%d)", val.i_int);
00568             break;
00569     }
00570     return fe_tone;
00571 }
00572 
00573 struct diseqc_cmd_t
00574 {
00575     struct dvb_diseqc_master_cmd cmd;
00576     uint32_t wait;
00577 };
00578 
00579 static int DoDiseqc( access_t *p_access )
00580 {
00581     access_sys_t *p_sys = p_access->p_sys;
00582     vlc_value_t val;
00583     int i_frequency, i_lnb_slof;
00584     fe_sec_voltage_t fe_voltage;
00585     fe_sec_tone_mode_t fe_tone;
00586     int i_err;
00587 
00588     var_Get( p_access, "dvb-frequency", &val );
00589     i_frequency = val.i_int;
00590     var_Get( p_access, "dvb-lnb-slof", &val );
00591     i_lnb_slof = val.i_int;
00592 
00593     var_Get( p_access, "dvb-tone", &val );
00594     if( val.i_int == -1 /* auto */ )
00595     {
00596         if( i_frequency >= i_lnb_slof )
00597             val.i_int = 1;
00598         else
00599             val.i_int = 0;
00600         var_Set( p_access, "dvb-tone", val );
00601     }
00602 
00603     fe_voltage = DecodeVoltage( p_access );
00604     fe_tone = DecodeTone( p_access );
00605 
00606     /* Switch off continuous tone. */
00607     if( (i_err = ioctl( p_sys->i_frontend_handle, FE_SET_TONE, SEC_TONE_OFF )) < 0 )
00608     {
00609         msg_Err( p_access, "ioctl FE_SET_TONE failed, tone=%s (%d) %s",
00610                  fe_tone == SEC_TONE_ON ? "on" : "off", i_err,
00611                  strerror(errno) );
00612         return i_err;
00613     }
00614 
00615     /* Configure LNB voltage. */
00616     if( (i_err = ioctl( p_sys->i_frontend_handle, FE_SET_VOLTAGE, fe_voltage )) < 0 )
00617     {
00618         msg_Err( p_access, "ioctl FE_SET_VOLTAGE failed, voltage=%d (%d) %s",
00619                  fe_voltage, i_err, strerror(errno) );
00620         return i_err;
00621     }
00622 
00623     var_Get( p_access, "dvb-high-voltage", &val );
00624     if( (i_err = ioctl( p_sys->i_frontend_handle, FE_ENABLE_HIGH_LNB_VOLTAGE,
00625                         val.b_bool )) < 0 && val.b_bool )
00626     {
00627         msg_Err( p_access,
00628                  "ioctl FE_ENABLE_HIGH_LNB_VOLTAGE failed, val=%d (%d) %s",
00629                  val.b_bool, i_err, strerror(errno) );
00630     }
00631 
00632     /* Wait for at least 15 ms. */
00633     msleep(15000);
00634 
00635     var_Get( p_access, "dvb-satno", &val );
00636     if( val.i_int > 0 && val.i_int < 5 )
00637     {
00638         /* digital satellite equipment control,
00639          * specification is available from http://www.eutelsat.com/
00640          */
00641 
00642         /* 1.x compatible equipment */
00643         struct diseqc_cmd_t cmd =  { {{0xe0, 0x10, 0x38, 0xf0, 0x00, 0x00}, 4}, 0 };
00644 
00645         /* param: high nibble: reset bits, low nibble set bits,
00646          * bits are: option, position, polarization, band
00647          */
00648         cmd.cmd.msg[3] = 0xf0 /* reset bits */
00649                           | (((val.i_int - 1) * 4) & 0xc)
00650                           | (fe_voltage == SEC_VOLTAGE_13 ? 0 : 2)
00651                           | (fe_tone == SEC_TONE_ON ? 1 : 0);
00652 
00653         if( (i_err = ioctl( p_sys->i_frontend_handle, FE_DISEQC_SEND_MASTER_CMD,
00654                            &cmd.cmd )) < 0 )
00655         {
00656             msg_Err( p_access, "ioctl FE_SEND_MASTER_CMD failed (%d) %s",
00657                      i_err, strerror(errno) );
00658             return i_err;
00659         }
00660 
00661         msleep(15000 + cmd.wait * 1000);
00662 
00663         /* A or B simple diseqc ("diseqc-compatible") */
00664         if( (i_err = ioctl( p_sys->i_frontend_handle, FE_DISEQC_SEND_BURST,
00665                       ((val.i_int - 1) % 2) ? SEC_MINI_B : SEC_MINI_A )) < 0 )
00666         {
00667             msg_Err( p_access, "ioctl FE_SEND_BURST failed (%d) %s",
00668                      i_err, strerror(errno) );
00669             return i_err;
00670         }
00671 
00672         msleep(15000);
00673     }
00674 
00675     if( (i_err = ioctl( p_sys->i_frontend_handle, FE_SET_TONE, fe_tone )) < 0 )
00676     {
00677         msg_Err( p_access, "ioctl FE_SET_TONE failed, tone=%s (%d) %s",
00678                  fe_tone == SEC_TONE_ON ? "on" : "off", i_err,
00679                  strerror(errno) );
00680         return i_err;
00681     }
00682 
00683     msleep(50000);
00684     return 0;
00685 }
00686 
00687 static int FrontendSetQPSK( access_t *p_access )
00688 {
00689     access_sys_t *p_sys = p_access->p_sys;
00690     struct dvb_frontend_parameters fep;
00691     int i_ret;
00692     vlc_value_t val;
00693     int i_frequency, i_lnb_slof = 0, i_lnb_lof1, i_lnb_lof2 = 0;
00694 
00695     /* Prepare the fep structure */
00696     var_Get( p_access, "dvb-frequency", &val );
00697     i_frequency = val.i_int;
00698 
00699     var_Get( p_access, "dvb-lnb-lof1", &val );
00700     if ( val.i_int == 0 )
00701     {
00702         /* Automatic mode. */
00703         if ( i_frequency >= 950000 && i_frequency <= 2150000 )
00704         {
00705             msg_Dbg( p_access, "frequency %d is in IF-band", i_frequency );
00706             i_lnb_lof1 = 0;
00707         }
00708         else if ( i_frequency >= 2500000 && i_frequency <= 2700000 )
00709         {
00710             msg_Dbg( p_access, "frequency %d is in S-band", i_frequency );
00711             i_lnb_lof1 = 3650000;
00712         }
00713         else if ( i_frequency >= 3400000 && i_frequency <= 4200000 )
00714         {
00715             msg_Dbg( p_access, "frequency %d is in C-band (lower)",
00716                      i_frequency );
00717             i_lnb_lof1 = 5150000;
00718         }
00719         else if ( i_frequency >= 4500000 && i_frequency <= 4800000 )
00720         {
00721             msg_Dbg( p_access, "frequency %d is in C-band (higher)",
00722                      i_frequency );
00723             i_lnb_lof1 = 5950000;
00724         }
00725         else if ( i_frequency >= 10700000 && i_frequency <= 13250000 )
00726         {
00727             msg_Dbg( p_access, "frequency %d is in Ku-band",
00728                      i_frequency );
00729             i_lnb_lof1 = 9750000;
00730             i_lnb_lof2 = 10600000;
00731             i_lnb_slof = 11700000;
00732         }
00733         else
00734         {
00735             msg_Err( p_access, "frequency %d is out of any known band",
00736                      i_frequency );
00737             msg_Err( p_access, "specify dvb-lnb-lof1 manually for the local "
00738                      "oscillator frequency" );
00739             return VLC_EGENERIC;
00740         }
00741         val.i_int = i_lnb_lof1;
00742         var_Set( p_access, "dvb-lnb-lof1", val );
00743         val.i_int = i_lnb_lof2;
00744         var_Set( p_access, "dvb-lnb-lof2", val );
00745         val.i_int = i_lnb_slof;
00746         var_Set( p_access, "dvb-lnb-slof", val );
00747     }
00748     else
00749     {
00750         i_lnb_lof1 = val.i_int;
00751         var_Get( p_access, "dvb-lnb-lof2", &val );
00752         i_lnb_lof2 = val.i_int;
00753         var_Get( p_access, "dvb-lnb-slof", &val );
00754         i_lnb_slof = val.i_int;
00755     }
00756 
00757     if( i_lnb_slof && i_frequency >= i_lnb_slof )
00758     {
00759         i_frequency -= i_lnb_lof2;
00760     }
00761     else
00762     {
00763         i_frequency -= i_lnb_lof1;
00764     }
00765     fep.frequency = i_frequency >= 0 ? i_frequency : -i_frequency;
00766 
00767     fep.inversion = DecodeInversion( p_access );
00768 
00769     var_Get( p_access, "dvb-srate", &val );
00770     fep.u.qpsk.symbol_rate = val.i_int;
00771 
00772     var_Get( p_access, "dvb-fec", &val );
00773     fep.u.qpsk.fec_inner = DecodeFEC( p_access, val.i_int );
00774 
00775     if( DoDiseqc( p_access ) < 0 )
00776     {
00777         return VLC_EGENERIC;
00778     }
00779 
00780     /* Empty the event queue */
00781     for( ; ; )
00782     {
00783         struct dvb_frontend_event event;
00784         if ( ioctl( p_sys->i_frontend_handle, FE_GET_EVENT, &event ) < 0
00785               && errno == EWOULDBLOCK )
00786             break;
00787     }
00788 
00789     /* Now send it all to the frontend device */
00790     if( (i_ret = ioctl( p_sys->i_frontend_handle, FE_SET_FRONTEND, &fep )) < 0 )
00791     {
00792         msg_Err( p_access, "DVB-S: setting frontend failed (%d) %s", i_ret,
00793                  strerror(errno) );
00794         return VLC_EGENERIC;
00795     }
00796 
00797     return VLC_SUCCESS;
00798 }
00799 
00800 /*****************************************************************************
00801  * FrontendSetQAM : controls the FE device
00802  *****************************************************************************/
00803 static int FrontendSetQAM( access_t *p_access )
00804 {
00805     access_sys_t *p_sys = p_access->p_sys;
00806     struct dvb_frontend_parameters fep;
00807     vlc_value_t val;
00808     int i_ret;
00809 
00810     /* Prepare the fep structure */
00811 
00812     var_Get( p_access, "dvb-frequency", &val );
00813     fep.frequency = val.i_int;
00814 
00815     fep.inversion = DecodeInversion( p_access );
00816 
00817     var_Get( p_access, "dvb-srate", &val );
00818     fep.u.qam.symbol_rate = val.i_int;
00819 
00820     var_Get( p_access, "dvb-fec", &val );
00821     fep.u.qam.fec_inner = DecodeFEC( p_access, val.i_int );
00822 
00823     fep.u.qam.modulation = DecodeModulation( p_access );
00824 
00825     /* Empty the event queue */
00826     for( ; ; )
00827     {
00828         struct dvb_frontend_event event;
00829         if ( ioctl( p_sys->i_frontend_handle, FE_GET_EVENT, &event ) < 0
00830               && errno == EWOULDBLOCK )
00831             break;
00832     }
00833 
00834     /* Now send it all to the frontend device */
00835     if( (i_ret = ioctl( p_sys->i_frontend_handle, FE_SET_FRONTEND, &fep )) < 0 )
00836     {
00837         msg_Err( p_access, "DVB-C: setting frontend failed (%d) %s", i_ret,
00838                  strerror(errno) );
00839         return VLC_EGENERIC;
00840     }
00841 
00842     return VLC_SUCCESS;
00843 }
00844 
00845 /*****************************************************************************
00846  * FrontendSetOFDM : controls the FE device
00847  *****************************************************************************/
00848 static fe_bandwidth_t DecodeBandwidth( access_t *p_access )
00849 {
00850     vlc_value_t         val;
00851     fe_bandwidth_t      fe_bandwidth = 0;
00852 
00853     var_Get( p_access, "dvb-bandwidth", &val );
00854     msg_Dbg( p_access, "using bandwidth=%d", val.i_int );
00855 
00856     switch( val.i_int )
00857     {
00858         case 0: fe_bandwidth = BANDWIDTH_AUTO; break;
00859         case 6: fe_bandwidth = BANDWIDTH_6_MHZ; break;
00860         case 7: fe_bandwidth = BANDWIDTH_7_MHZ; break;
00861         case 8: fe_bandwidth = BANDWIDTH_8_MHZ; break;
00862         default:
00863             msg_Dbg( p_access, "terrestrial dvb has bandwidth not set, using auto" );
00864             fe_bandwidth = BANDWIDTH_AUTO;
00865             break;
00866     }
00867     return fe_bandwidth;
00868 }
00869 
00870 static fe_transmit_mode_t DecodeTransmission( access_t *p_access )
00871 {
00872     vlc_value_t         val;
00873     fe_transmit_mode_t  fe_transmission = 0;
00874 
00875     var_Get( p_access, "dvb-transmission", &val );
00876     msg_Dbg( p_access, "using transmission=%d", val.i_int );
00877 
00878     switch( val.i_int )
00879     {
00880         case 0: fe_transmission = TRANSMISSION_MODE_AUTO; break;
00881         case 2: fe_transmission = TRANSMISSION_MODE_2K; break;
00882         case 8: fe_transmission = TRANSMISSION_MODE_8K; break;
00883         default:
00884             msg_Dbg( p_access, "terrestrial dvb has transmission mode not set, using auto");
00885             fe_transmission = TRANSMISSION_MODE_AUTO;
00886             break;
00887     }
00888     return fe_transmission;
00889 }
00890 
00891 static fe_guard_interval_t DecodeGuardInterval( access_t *p_access )
00892 {
00893     vlc_value_t         val;
00894     fe_guard_interval_t fe_guard = 0;
00895 
00896     var_Get( p_access, "dvb-guard", &val );
00897     msg_Dbg( p_access, "using guard=%d", val.i_int );
00898 
00899     switch( val.i_int )
00900     {
00901         case 0: fe_guard = GUARD_INTERVAL_AUTO; break;
00902         case 4: fe_guard = GUARD_INTERVAL_1_4; break;
00903         case 8: fe_guard = GUARD_INTERVAL_1_8; break;
00904         case 16: fe_guard = GUARD_INTERVAL_1_16; break;
00905         case 32: fe_guard = GUARD_INTERVAL_1_32; break;
00906         default:
00907             msg_Dbg( p_access, "terrestrial dvb has guard interval not set, using auto");
00908             fe_guard = GUARD_INTERVAL_AUTO;
00909             break;
00910     }
00911     return fe_guard;
00912 }
00913 
00914 static fe_hierarchy_t DecodeHierarchy( access_t *p_access )
00915 {
00916     vlc_value_t         val;
00917     fe_hierarchy_t      fe_hierarchy = 0;
00918 
00919     var_Get( p_access, "dvb-hierarchy", &val );
00920     msg_Dbg( p_access, "using hierarchy=%d", val.i_int );
00921 
00922     switch( val.i_int )
00923     {
00924         case -1: fe_hierarchy = HIERARCHY_NONE; break;
00925         case 0: fe_hierarchy = HIERARCHY_AUTO; break;
00926         case 1: fe_hierarchy = HIERARCHY_1; break;
00927         case 2: fe_hierarchy = HIERARCHY_2; break;
00928         case 4: fe_hierarchy = HIERARCHY_4; break;
00929         default:
00930             msg_Dbg( p_access, "terrestrial dvb has hierarchy not set, using auto");
00931             fe_hierarchy = HIERARCHY_AUTO;
00932             break;
00933     }
00934     return fe_hierarchy;
00935 }
00936 
00937 static int FrontendSetOFDM( access_t * p_access )
00938 {
00939     access_sys_t *p_sys = p_access->p_sys;
00940     struct dvb_frontend_parameters fep;
00941     vlc_value_t val;
00942     int ret;
00943 
00944     /* Prepare the fep structure */
00945 
00946     var_Get( p_access, "dvb-frequency", &val );
00947     fep.frequency = val.i_int;
00948 
00949     fep.inversion = DecodeInversion( p_access );
00950 
00951     fep.u.ofdm.bandwidth = DecodeBandwidth( p_access );
00952     var_Get( p_access, "dvb-code-rate-hp", &val );
00953     fep.u.ofdm.code_rate_HP = DecodeFEC( p_access, val.i_int );
00954     var_Get( p_access, "dvb-code-rate-lp", &val );
00955     fep.u.ofdm.code_rate_LP = DecodeFEC( p_access, val.i_int );
00956     fep.u.ofdm.constellation = DecodeModulation( p_access );
00957     fep.u.ofdm.transmission_mode = DecodeTransmission( p_access );
00958     fep.u.ofdm.guard_interval = DecodeGuardInterval( p_access );
00959     fep.u.ofdm.hierarchy_information = DecodeHierarchy( p_access );
00960 
00961     /* Empty the event queue */
00962     for( ; ; )
00963     {
00964         struct dvb_frontend_event event;
00965         if ( ioctl( p_sys->i_frontend_handle, FE_GET_EVENT, &event ) < 0
00966               && errno == EWOULDBLOCK )
00967             break;
00968     }
00969 
00970     /* Now send it all to the frontend device */
00971     if( (ret = ioctl( p_sys->i_frontend_handle, FE_SET_FRONTEND, &fep )) < 0 )
00972     {
00973         msg_Err( p_access, "DVB-T: setting frontend failed (%d) %s", ret,
00974                  strerror(errno) );
00975         return -1;
00976     }
00977 
00978     return VLC_SUCCESS;
00979 }
00980 
00981 
00982 /*
00983  * Demux
00984  */
00985 
00986 /*****************************************************************************
00987  * DMXSetFilter : controls the demux to add a filter
00988  *****************************************************************************/
00989 int E_(DMXSetFilter)( access_t * p_access, int i_pid, int * pi_fd, int i_type )
00990 {
00991     struct dmx_pes_filter_params s_filter_params;
00992     int i_ret;
00993     unsigned int i_adapter, i_device;
00994     char dmx[128];
00995     vlc_value_t val;
00996 
00997     var_Get( p_access, "dvb-adapter", &val );
00998     i_adapter = val.i_int;
00999     var_Get( p_access, "dvb-device", &val );
01000     i_device = val.i_int;
01001 
01002     if( snprintf( dmx, sizeof(dmx), DMX, i_adapter, i_device )
01003             >= (int)sizeof(dmx) )
01004     {
01005         msg_Err( p_access, "snprintf() truncated string for DMX" );
01006         dmx[sizeof(dmx) - 1] = '\0';
01007     }
01008 
01009     msg_Dbg( p_access, "Opening device %s", dmx );
01010     if( (*pi_fd = open(dmx, O_RDWR)) < 0 )
01011     {
01012         msg_Err( p_access, "DMXSetFilter: opening device failed (%s)",
01013                  strerror(errno) );
01014         return VLC_EGENERIC;
01015     }
01016 
01017     /* We fill the DEMUX structure : */
01018     s_filter_params.pid     =   i_pid;
01019     s_filter_params.input   =   DMX_IN_FRONTEND;
01020     s_filter_params.output  =   DMX_OUT_TS_TAP;
01021     s_filter_params.flags   =   DMX_IMMEDIATE_START;
01022 
01023     switch ( i_type )
01024     {   /* First device */
01025         case 1:
01026             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_VIDEO0 for PID %d", i_pid);
01027             s_filter_params.pes_type = DMX_PES_VIDEO0;
01028             break;
01029         case 2:
01030             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_AUDIO0 for PID %d", i_pid);
01031             s_filter_params.pes_type = DMX_PES_AUDIO0;
01032             break;
01033         case 3:
01034             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_TELETEXT0 for PID %d", i_pid);
01035             s_filter_params.pes_type = DMX_PES_TELETEXT0;
01036             break;
01037         case 4:
01038             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_SUBTITLE0 for PID %d", i_pid);
01039             s_filter_params.pes_type = DMX_PES_SUBTITLE0;
01040             break;
01041         case 5:
01042             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_PCR0 for PID %d", i_pid);
01043             s_filter_params.pes_type = DMX_PES_PCR0;
01044             break;
01045         /* Second device */
01046         case 6:
01047             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_VIDEO1 for PID %d", i_pid);
01048             s_filter_params.pes_type = DMX_PES_VIDEO1;
01049             break;
01050         case 7:
01051             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_AUDIO1 for PID %d", i_pid);
01052             s_filter_params.pes_type = DMX_PES_AUDIO1;
01053             break;
01054         case 8:
01055             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_TELETEXT1 for PID %d", i_pid);
01056             s_filter_params.pes_type = DMX_PES_TELETEXT1;
01057             break;
01058         case 9:
01059             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_SUBTITLE1 for PID %d", i_pid);
01060             s_filter_params.pes_type = DMX_PES_SUBTITLE1;
01061             break;
01062         case 10:
01063             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_PCR1 for PID %d", i_pid);
01064             s_filter_params.pes_type = DMX_PES_PCR1;
01065             break;
01066         /* Third device */
01067         case 11:
01068             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_VIDEO2 for PID %d", i_pid);
01069             s_filter_params.pes_type = DMX_PES_VIDEO2;
01070             break;
01071         case 12:
01072             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_AUDIO2 for PID %d", i_pid);
01073             s_filter_params.pes_type = DMX_PES_AUDIO2;
01074             break;
01075         case 13:
01076             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_TELETEXT2 for PID %d", i_pid);
01077             s_filter_params.pes_type = DMX_PES_TELETEXT2;
01078             break;
01079         case 14:
01080             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_SUBTITLE2 for PID %d", i_pid);
01081             s_filter_params.pes_type = DMX_PES_SUBTITLE2;
01082             break;
01083         case 15:
01084             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_PCR2 for PID %d", i_pid);
01085             s_filter_params.pes_type = DMX_PES_PCR2;
01086             break;
01087         /* Forth device */
01088         case 16:
01089             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_VIDEO3 for PID %d", i_pid);
01090             s_filter_params.pes_type = DMX_PES_VIDEO3;
01091             break;
01092         case 17:
01093             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_AUDIO3 for PID %d", i_pid);
01094             s_filter_params.pes_type = DMX_PES_AUDIO3;
01095             break;
01096         case 18:
01097             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_TELETEXT3 for PID %d", i_pid);
01098             s_filter_params.pes_type = DMX_PES_TELETEXT3;
01099             break;
01100         case 19:
01101             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_SUBTITLE3 for PID %d", i_pid);
01102             s_filter_params.pes_type = DMX_PES_SUBTITLE3;
01103             break;
01104         case 20:
01105             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_PCR3 for PID %d", i_pid);
01106             s_filter_params.pes_type = DMX_PES_PCR3;
01107             break;
01108         /* Usually used by Nova cards */
01109         case 21:
01110         default:
01111             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_OTHER for PID %d", i_pid);
01112             s_filter_params.pes_type = DMX_PES_OTHER;
01113             break;
01114     }
01115 
01116     /* We then give the order to the device : */
01117     if( (i_ret = ioctl( *pi_fd, DMX_SET_PES_FILTER, &s_filter_params )) < 0 )
01118     {
01119         msg_Err( p_access, "DMXSetFilter: failed with %d (%s)", i_ret,
01120                  strerror(errno) );
01121         return VLC_EGENERIC;
01122     }
01123     return VLC_SUCCESS;
01124 }
01125 
01126 /*****************************************************************************
01127  * DMXUnsetFilter : removes a filter
01128  *****************************************************************************/
01129 int E_(DMXUnsetFilter)( access_t * p_access, int i_fd )
01130 {
01131     int i_ret;
01132 
01133     if( (i_ret = ioctl( i_fd, DMX_STOP )) < 0 )
01134     {
01135         msg_Err( p_access, "DMX_STOP failed for demux (%d) %s",
01136                  i_ret, strerror(errno) );
01137         return i_ret;
01138     }
01139 
01140     msg_Dbg( p_access, "DMXUnsetFilter: closing demux %d", i_fd );
01141     close( i_fd );
01142     return VLC_SUCCESS;
01143 }
01144 
01145 
01146 /*
01147  * DVR device
01148  */
01149 
01150 /*****************************************************************************
01151  * DVROpen :
01152  *****************************************************************************/
01153 int E_(DVROpen)( access_t * p_access )
01154 {
01155     access_sys_t *p_sys = p_access->p_sys;
01156     unsigned int i_adapter, i_device;
01157     char dvr[128];
01158     vlc_value_t val;
01159 
01160     var_Get( p_access, "dvb-adapter", &val );
01161     i_adapter = val.i_int;
01162     var_Get( p_access, "dvb-device", &val );
01163     i_device = val.i_int;
01164 
01165     if( snprintf( dvr, sizeof(dvr), DVR, i_adapter, i_device )
01166             >= (int)sizeof(dvr) )
01167     {
01168         msg_Err( p_access, "snprintf() truncated string for DVR" );
01169         dvr[sizeof(dvr) - 1] = '\0';
01170     }
01171 
01172     msg_Dbg( p_access, "Opening device %s", dvr );
01173     if( (p_sys->i_handle = open(dvr, O_RDONLY)) < 0 )
01174     {
01175         msg_Err( p_access, "DVROpen: opening device failed (%s)",
01176                  strerror(errno) );
01177         return VLC_EGENERIC;
01178     }
01179 
01180     if( fcntl( p_sys->i_handle, F_SETFL, O_NONBLOCK ) == -1 )
01181     {
01182         msg_Warn( p_access, "DVROpen: couldn't set non-blocking mode (%s)",
01183                   strerror(errno) );
01184     }
01185 
01186     return VLC_SUCCESS;
01187 }
01188 
01189 /*****************************************************************************
01190  * DVRClose :
01191  *****************************************************************************/
01192 void E_(DVRClose)( access_t * p_access )
01193 {
01194     access_sys_t *p_sys = p_access->p_sys;
01195 
01196     close( p_sys->i_handle );
01197 }
01198 
01199 
01200 /*
01201  * CAM device
01202  */
01203 
01204 /*****************************************************************************
01205  * CAMOpen :
01206  *****************************************************************************/
01207 int E_(CAMOpen)( access_t *p_access )
01208 {
01209     access_sys_t *p_sys = p_access->p_sys;
01210     char ca[128];
01211     int i_adapter, i_device, i_slot;
01212     ca_caps_t caps;
01213 
01214     i_adapter = var_GetInteger( p_access, "dvb-adapter" );
01215     i_device = var_GetInteger( p_access, "dvb-device" );
01216 
01217     if( snprintf( ca, sizeof(ca), CA, i_adapter, i_device ) >= (int)sizeof(ca) )
01218     {
01219         msg_Err( p_access, "snprintf() truncated string for CA" );
01220         ca[sizeof(ca) - 1] = '\0';
01221     }
01222 
01223     msg_Dbg( p_access, "Opening device %s", ca );
01224     if( (p_sys->i_ca_handle = open(ca, O_RDWR | O_NONBLOCK)) < 0 )
01225     {
01226         msg_Warn( p_access, "CAMInit: opening CAM device failed (%s)",
01227                   strerror(errno) );
01228         p_sys->i_ca_handle = 0;
01229         return VLC_EGENERIC;
01230     }
01231 
01232     if ( ioctl( p_sys->i_ca_handle, CA_GET_CAP, &caps ) != 0 )
01233     {
01234         msg_Err( p_access, "CAMInit: ioctl() error getting CAM capabilities" );
01235         close( p_sys->i_ca_handle );
01236         p_sys->i_ca_handle = 0;
01237         return VLC_EGENERIC;
01238     }
01239 
01240     /* Output CA capabilities */
01241     msg_Dbg( p_access, "CAMInit: CA interface with %d %s", caps.slot_num, 
01242         caps.slot_num == 1 ? "slot" : "slots" );
01243     if ( caps.slot_type & CA_CI )
01244         msg_Dbg( p_access, "CAMInit: CI high level interface type (not supported)" );
01245     if ( caps.slot_type & CA_CI_LINK )
01246         msg_Dbg( p_access, "CAMInit: CI link layer level interface type" );
01247     if ( caps.slot_type & CA_CI_PHYS )
01248         msg_Dbg( p_access, "CAMInit: CI physical layer level interface type (not supported) " );
01249     if ( caps.slot_type & CA_DESCR )
01250         msg_Dbg( p_access, "CAMInit: built-in descrambler detected" );
01251     if ( caps.slot_type & CA_SC )
01252         msg_Dbg( p_access, "CAMInit: simple smart card interface" );
01253 
01254     msg_Dbg( p_access, "CAMInit: %d available %s", caps.descr_num,
01255         caps.descr_num == 1 ? "descrambler (key)" : "descramblers (keys)" );
01256     if ( caps.descr_type & CA_ECD )
01257         msg_Dbg( p_access, "CAMInit: ECD scrambling system supported" );
01258     if ( caps.descr_type & CA_NDS )
01259         msg_Dbg( p_access, "CAMInit: NDS scrambling system supported" );
01260     if ( caps.descr_type & CA_DSS )
01261         msg_Dbg( p_access, "CAMInit: DSS scrambling system supported" );
01262  
01263     if ( caps.slot_num == 0 )
01264     {
01265         msg_Err( p_access, "CAMInit: CAM module with no slots" );
01266         close( p_sys->i_ca_handle );
01267         p_sys->i_ca_handle = 0;
01268         return VLC_EGENERIC;
01269     }
01270 
01271     if ( !(caps.slot_type & CA_CI_LINK) )
01272     {
01273         msg_Err( p_access, "CAMInit: no compatible CAM module" );
01274         close( p_sys->i_ca_handle );
01275         p_sys->i_ca_handle = 0;
01276         return VLC_EGENERIC;
01277     }
01278 
01279     p_sys->i_nb_slots = caps.slot_num;
01280     memset( p_sys->pb_active_slot, 0, sizeof(vlc_bool_t) * MAX_CI_SLOTS );
01281 
01282     for ( i_slot = 0; i_slot < p_sys->i_nb_slots; i_slot++ )
01283     {
01284         if ( ioctl( p_sys->i_ca_handle, CA_RESET, 1 << i_slot) != 0 )
01285         {
01286             msg_Err( p_access, "CAMInit: couldn't reset slot %d", i_slot );
01287         }
01288     }
01289 
01290     p_sys->i_ca_timeout = 100000;
01291     /* Wait a bit otherwise it doesn't initialize properly... */
01292     msleep( 1000000 );
01293 
01294     return VLC_SUCCESS;
01295 }
01296 
01297 /*****************************************************************************
01298  * CAMPoll :
01299  *****************************************************************************/
01300 int E_(CAMPoll)( access_t * p_access )
01301 {
01302     access_sys_t *p_sys = p_access->p_sys;
01303 
01304     if ( p_sys->i_ca_handle == 0 )
01305     {
01306         return VLC_EGENERIC;
01307     }
01308 
01309     return E_(en50221_Poll)( p_access );
01310 }
01311 
01312 /*****************************************************************************
01313  * CAMSet :
01314  *****************************************************************************/
01315 int E_(CAMSet)( access_t * p_access, dvbpsi_pmt_t *p_pmt )
01316 {
01317     access_sys_t *p_sys = p_access->p_sys;
01318 
01319     if ( p_sys->i_ca_handle == 0 )
01320     {
01321         return VLC_EGENERIC;
01322     }
01323 
01324     E_(en50221_SetCAPMT)( p_access, p_pmt );
01325 
01326     return VLC_SUCCESS;
01327 }
01328 
01329 /*****************************************************************************
01330  * CAMClose :
01331  *****************************************************************************/
01332 void E_(CAMClose)( access_t * p_access )
01333 {
01334     access_sys_t *p_sys = p_access->p_sys;
01335 
01336     E_(en50221_End)( p_access );
01337 
01338     if ( p_sys->i_ca_handle )
01339     {
01340         close( p_sys->i_ca_handle );
01341     }
01342 }
01343 

Generated on Tue Dec 20 10:14:24 2005 for vlc-0.8.4a by  doxygen 1.4.2