linux_dvb.c
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:39k
源码类别:

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * linux_dvb.c : functions to control a DVB card under Linux with v4l2
  3.  *****************************************************************************
  4.  * Copyright (C) 1998-2004 VideoLAN
  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. #include <vlc/vlc.h>
  27. #include <vlc/input.h>
  28. #include <sys/ioctl.h>
  29. #include <errno.h>
  30. #include <sys/types.h>
  31. #include <sys/stat.h>
  32. #include <fcntl.h>
  33. #include <time.h>
  34. #include <unistd.h>
  35. #include <sys/stat.h>
  36. #include <sys/poll.h>
  37. /* DVB Card Drivers */
  38. #include <linux/dvb/version.h>
  39. #include <linux/dvb/dmx.h>
  40. #include <linux/dvb/frontend.h>
  41. #include <linux/dvb/ca.h>
  42. #include "dvb.h"
  43. #define DMX_BUFFER_SIZE (1024 * 1024)
  44. /*
  45.  * Frontends
  46.  */
  47. struct frontend_t
  48. {
  49.     int i_handle;
  50.     struct dvb_frontend_info info;
  51. };
  52. /* Local prototypes */
  53. static int FrontendInfo( access_t * );
  54. static int FrontendSetQPSK( access_t * );
  55. static int FrontendSetQAM( access_t * );
  56. static int FrontendSetOFDM( access_t * );
  57. static int FrontendCheck( access_t * );
  58. /*****************************************************************************
  59.  * FrontendOpen : Determine frontend device information and capabilities
  60.  *****************************************************************************/
  61. int E_(FrontendOpen)( access_t *p_access )
  62. {
  63.     access_sys_t *p_sys = p_access->p_sys;
  64.     frontend_t * p_frontend;
  65.     unsigned int i_adapter, i_device;
  66.     vlc_bool_t b_probe;
  67.     char frontend[128];
  68.     i_adapter = var_GetInteger( p_access, "dvb-adapter" );
  69.     i_device = var_GetInteger( p_access, "dvb-device" );
  70.     b_probe = var_GetBool( p_access, "dvb-probe" );
  71.     if( snprintf( frontend, sizeof(frontend), FRONTEND, i_adapter, i_device ) >= (int)sizeof(frontend) )
  72.     {
  73.         msg_Err( p_access, "snprintf() truncated string for FRONTEND" );
  74.         frontend[sizeof(frontend) - 1] = '';
  75.     }
  76.     p_sys->p_frontend = p_frontend = malloc( sizeof(frontend_t) );
  77.     msg_Dbg( p_access, "Opening device %s", frontend );
  78.     if( (p_frontend->i_handle = open(frontend, O_RDWR | O_NONBLOCK)) < 0 )
  79.     {
  80.         msg_Err( p_access, "FrontEndOpen: opening device failed (%s)",
  81.                  strerror(errno) );
  82.         free( p_frontend );
  83.         return VLC_EGENERIC;
  84.     }
  85.     if( b_probe )
  86.     {
  87.         char * psz_expected = NULL;
  88.         char * psz_real;
  89.         if( FrontendInfo( p_access ) < 0 )
  90.         {
  91.             close( p_frontend->i_handle );
  92.             free( p_frontend );
  93.             return VLC_EGENERIC;
  94.         }
  95.         switch( p_frontend->info.type )
  96.         {
  97.         case FE_OFDM:
  98.             psz_real = "DVB-T";
  99.             break;
  100.         case FE_QAM:
  101.             psz_real = "DVB-C";
  102.             break;
  103.         case FE_QPSK:
  104.             psz_real = "DVB-S";
  105.             break;
  106.         default:
  107.             psz_real = "unknown";
  108.         }
  109.         /* Sanity checks */
  110.         if( (!strncmp( p_access->psz_access, "qpsk", 4 ) ||
  111.              !strncmp( p_access->psz_access, "dvb-s", 5 ) ||
  112.              !strncmp( p_access->psz_access, "satellite", 9 ) ) &&
  113.              (p_frontend->info.type != FE_QPSK) )
  114.         {
  115.             psz_expected = "DVB-S";
  116.         }
  117.         if( (!strncmp( p_access->psz_access, "cable", 5 ) ||
  118.              !strncmp( p_access->psz_access, "dvb-c", 5 ) ) &&
  119.              (p_frontend->info.type != FE_QAM) )
  120.         {
  121.             psz_expected = "DVB-C";
  122.         }
  123.         if( (!strncmp( p_access->psz_access, "terrestrial", 11 ) ||
  124.              !strncmp( p_access->psz_access, "dvb-t", 5 ) ) &&
  125.              (p_frontend->info.type != FE_OFDM) )
  126.         {
  127.             psz_expected = "DVB-T";
  128.         }
  129.         if( psz_expected != NULL )
  130.         {
  131.             msg_Err( p_access, "the user asked for %s, and the tuner is %s",
  132.                      psz_expected, psz_real );
  133.             close( p_frontend->i_handle );
  134.             free( p_frontend );
  135.             return VLC_EGENERIC;
  136.         }
  137.     }
  138.     else /* no frontend probing is done so use default border values. */
  139.     {
  140.         msg_Dbg( p_access, "using default values for frontend info" );
  141.         msg_Dbg( p_access, "method of access is %s", p_access->psz_access );
  142.         p_frontend->info.type = FE_QPSK;
  143.         if( !strncmp( p_access->psz_access, "qpsk", 4 ) ||
  144.             !strncmp( p_access->psz_access, "dvb-s", 5 ) )
  145.             p_frontend->info.type = FE_QPSK;
  146.         else if( !strncmp( p_access->psz_access, "cable", 5 ) ||
  147.                  !strncmp( p_access->psz_access, "dvb-c", 5 ) )
  148.             p_frontend->info.type = FE_QAM;
  149.         else if( !strncmp( p_access->psz_access, "terrestrial", 11 ) ||
  150.                  !strncmp( p_access->psz_access, "dvb-t", 5 ) )
  151.             p_frontend->info.type = FE_OFDM;
  152.     }
  153.     return VLC_SUCCESS;
  154. }
  155. /*****************************************************************************
  156.  * FrontendClose : Close the frontend
  157.  *****************************************************************************/
  158. void E_(FrontendClose)( access_t *p_access )
  159. {
  160.     access_sys_t *p_sys = p_access->p_sys;
  161.     if( p_sys->p_frontend )
  162.     {
  163.         close( p_sys->p_frontend->i_handle );
  164.         free( p_sys->p_frontend );
  165.         p_sys->p_frontend = NULL;
  166.     }
  167. }
  168. /*****************************************************************************
  169.  * FrontendSet : Tune !
  170.  *****************************************************************************/
  171. int E_(FrontendSet)( access_t *p_access )
  172. {
  173.     access_sys_t *p_sys = p_access->p_sys;
  174.     switch( p_sys->p_frontend->info.type )
  175.     {
  176.     /* DVB-S: satellite and budget cards (nova) */
  177.     case FE_QPSK:
  178.         if( FrontendSetQPSK( p_access ) < 0 )
  179.         {
  180.             msg_Err( p_access, "DVB-S: tuning failed" );
  181.             return VLC_EGENERIC;
  182.         }
  183.         break;
  184.     /* DVB-C */
  185.     case FE_QAM:
  186.         if( FrontendSetQAM( p_access ) < 0 )
  187.         {
  188.             msg_Err( p_access, "DVB-C: tuning failed" );
  189.             return VLC_EGENERIC;
  190.         }
  191.         break;
  192.     /* DVB-T */
  193.     case FE_OFDM:
  194.         if( FrontendSetOFDM( p_access ) < 0 )
  195.         {
  196.             msg_Err( p_access, "DVB-T: tuning failed" );
  197.             return VLC_EGENERIC;
  198.         }
  199.         break;
  200.     default:
  201.         msg_Err( p_access, "Could not determine frontend type on %s",
  202.                  p_sys->p_frontend->info.name );
  203.         return VLC_EGENERIC;
  204.     }
  205.     return VLC_SUCCESS;
  206. }
  207. /*****************************************************************************
  208.  * FrontendInfo : Return information about given frontend
  209.  *****************************************************************************/
  210. static int FrontendInfo( access_t *p_access )
  211. {
  212.     access_sys_t *p_sys = p_access->p_sys;
  213.     frontend_t *p_frontend = p_sys->p_frontend;
  214.     int i_ret;
  215.     /* Determine type of frontend */
  216.     if( (i_ret = ioctl( p_frontend->i_handle, FE_GET_INFO,
  217.                         &p_frontend->info )) < 0 )
  218.     {
  219.         msg_Err( p_access, "ioctl FE_GET_INFO failed (%d) %s", i_ret,
  220.                  strerror(errno) );
  221.         return VLC_EGENERIC;
  222.     }
  223.     /* Print out frontend capabilities. */
  224.     msg_Dbg(p_access, "Frontend Info:" );
  225.     msg_Dbg(p_access, "  name = %s", p_frontend->info.name );
  226.     switch( p_frontend->info.type )
  227.     {
  228.         case FE_QPSK:
  229.             msg_Dbg( p_access, "  type = QPSK (DVB-S)" );
  230.             break;
  231.         case FE_QAM:
  232.             msg_Dbg( p_access, "  type = QAM (DVB-C)" );
  233.             break;
  234.         case FE_OFDM:
  235.             msg_Dbg( p_access, "  type = OFDM (DVB-T)" );
  236.             break;
  237. #if 0 /* DVB_API_VERSION == 3 */
  238.         case FE_MEMORY:
  239.             msg_Dbg(p_access, "  type = MEMORY" );
  240.             break;
  241.         case FE_NET:
  242.             msg_Dbg(p_access, "  type = NETWORK" );
  243.             break;
  244. #endif
  245.         default:
  246.             msg_Err( p_access, "  unknown frontend type (%d)",
  247.                      p_frontend->info.type );
  248.             return VLC_EGENERIC;
  249.     }
  250.     msg_Dbg(p_access, "  frequency_min = %u (kHz)",
  251.             p_frontend->info.frequency_min);
  252.     msg_Dbg(p_access, "  frequency_max = %u (kHz)",
  253.             p_frontend->info.frequency_max);
  254.     msg_Dbg(p_access, "  frequency_stepsize = %u",
  255.             p_frontend->info.frequency_stepsize);
  256.     msg_Dbg(p_access, "  frequency_tolerance = %u",
  257.             p_frontend->info.frequency_tolerance);
  258.     msg_Dbg(p_access, "  symbol_rate_min = %u (kHz)",
  259.             p_frontend->info.symbol_rate_min);
  260.     msg_Dbg(p_access, "  symbol_rate_max = %u (kHz)",
  261.             p_frontend->info.symbol_rate_max);
  262.     msg_Dbg(p_access, "  symbol_rate_tolerance (ppm) = %u",
  263.             p_frontend->info.symbol_rate_tolerance);
  264.     msg_Dbg(p_access, "  notifier_delay (ms) = %u",
  265.             p_frontend->info.notifier_delay );
  266.     msg_Dbg(p_access, "Frontend Info capability list:");
  267.     if( p_frontend->info.caps & FE_IS_STUPID)
  268.         msg_Dbg(p_access, "  no capabilities - frontend is stupid!");
  269.     if( p_frontend->info.caps & FE_CAN_INVERSION_AUTO)
  270.         msg_Dbg(p_access, "  inversion auto");
  271.     if( p_frontend->info.caps & FE_CAN_FEC_1_2)
  272.         msg_Dbg(p_access, "  forward error correction 1/2");
  273.     if( p_frontend->info.caps & FE_CAN_FEC_2_3)
  274.         msg_Dbg(p_access, "  forward error correction 2/3");
  275.     if( p_frontend->info.caps & FE_CAN_FEC_3_4)
  276.         msg_Dbg(p_access, "  forward error correction 3/4");
  277.     if( p_frontend->info.caps & FE_CAN_FEC_4_5)
  278.         msg_Dbg(p_access, "  forward error correction 4/5");
  279.     if( p_frontend->info.caps & FE_CAN_FEC_5_6)
  280.         msg_Dbg(p_access, "  forward error correction 5/6");
  281.     if( p_frontend->info.caps & FE_CAN_FEC_6_7)
  282.         msg_Dbg(p_access, "  forward error correction 6/7");
  283.     if( p_frontend->info.caps & FE_CAN_FEC_7_8)
  284.         msg_Dbg(p_access, "  forward error correction 7/8");
  285.     if( p_frontend->info.caps & FE_CAN_FEC_8_9)
  286.         msg_Dbg(p_access, "  forward error correction 8/9");
  287.     if( p_frontend->info.caps & FE_CAN_FEC_AUTO)
  288.         msg_Dbg(p_access, "  forward error correction auto");
  289.     if( p_frontend->info.caps & FE_CAN_QPSK)
  290.         msg_Dbg(p_access, "  card can do QPSK");
  291.     if( p_frontend->info.caps & FE_CAN_QAM_16)
  292.         msg_Dbg(p_access, "  card can do QAM 16");
  293.     if( p_frontend->info.caps & FE_CAN_QAM_32)
  294.         msg_Dbg(p_access, "  card can do QAM 32");
  295.     if( p_frontend->info.caps & FE_CAN_QAM_64)
  296.         msg_Dbg(p_access, "  card can do QAM 64");
  297.     if( p_frontend->info.caps & FE_CAN_QAM_128)
  298.         msg_Dbg(p_access, "  card can do QAM 128");
  299.     if( p_frontend->info.caps & FE_CAN_QAM_256)
  300.         msg_Dbg(p_access, "  card can do QAM 256");
  301.     if( p_frontend->info.caps & FE_CAN_QAM_AUTO)
  302.         msg_Dbg(p_access, "  card can do QAM auto");
  303.     if( p_frontend->info.caps & FE_CAN_TRANSMISSION_MODE_AUTO)
  304.         msg_Dbg(p_access, "  transmission mode auto");
  305.     if( p_frontend->info.caps & FE_CAN_BANDWIDTH_AUTO)
  306.         msg_Dbg(p_access, "  bandwidth mode auto");
  307.     if( p_frontend->info.caps & FE_CAN_GUARD_INTERVAL_AUTO)
  308.         msg_Dbg(p_access, "  guard interval mode auto");
  309.     if( p_frontend->info.caps & FE_CAN_HIERARCHY_AUTO)
  310.         msg_Dbg(p_access, "  hierarchy mode auto");
  311.     if( p_frontend->info.caps & FE_CAN_MUTE_TS)
  312.         msg_Dbg(p_access, "  card can mute TS");
  313.     if( p_frontend->info.caps & FE_CAN_RECOVER)
  314.         msg_Dbg(p_access, "  card can recover from a cable unplug");
  315.     msg_Dbg(p_access, "End of capability list");
  316.     return VLC_SUCCESS;
  317. }
  318. /*****************************************************************************
  319.  * Decoding the DVB parameters (common)
  320.  *****************************************************************************/
  321. static fe_spectral_inversion_t DecodeInversion( access_t *p_access )
  322. {
  323.     vlc_value_t         val;
  324.     fe_spectral_inversion_t fe_inversion = 0;
  325.     var_Get( p_access, "dvb-inversion", &val );
  326.     msg_Dbg( p_access, "using inversion=%d", val.i_int );
  327.     switch( val.i_int )
  328.     {
  329.         case 0: fe_inversion = INVERSION_OFF; break;
  330.         case 1: fe_inversion = INVERSION_ON; break;
  331.         case 2: fe_inversion = INVERSION_AUTO; break;
  332.         default:
  333.             msg_Dbg( p_access, "dvb has inversion not set, using auto");
  334.             fe_inversion = INVERSION_AUTO;
  335.             break;
  336.     }
  337.     return fe_inversion;
  338. }
  339. static fe_code_rate_t DecodeFEC( access_t *p_access, int i_val )
  340. {
  341.     fe_code_rate_t      fe_fec = FEC_NONE;
  342.     msg_Dbg( p_access, "using fec=%d", i_val );
  343.     switch( i_val )
  344.     {
  345.         case 0: fe_fec = FEC_NONE; break;
  346.         case 1: fe_fec = FEC_1_2; break;
  347.         case 2: fe_fec = FEC_2_3; break;
  348.         case 3: fe_fec = FEC_3_4; break;
  349.         case 4: fe_fec = FEC_4_5; break;
  350.         case 5: fe_fec = FEC_5_6; break;
  351.         case 6: fe_fec = FEC_6_7; break;
  352.         case 7: fe_fec = FEC_7_8; break;
  353.         case 8: fe_fec = FEC_8_9; break;
  354.         case 9: fe_fec = FEC_AUTO; break;
  355.         default:
  356.             /* cannot happen */
  357.             fe_fec = FEC_NONE;
  358.             msg_Err( p_access, "argument has invalid FEC (%d)", i_val);
  359.             break;
  360.     }
  361.     return fe_fec;
  362. }
  363. static fe_modulation_t DecodeModulation( access_t *p_access )
  364. {
  365.     vlc_value_t         val;
  366.     fe_modulation_t     fe_modulation = 0;
  367.     var_Get( p_access, "dvb-modulation", &val );
  368.     switch( val.i_int )
  369.     {
  370.         case -1: fe_modulation = QPSK; break;
  371.         case 0: fe_modulation = QAM_AUTO; break;
  372.         case 16: fe_modulation = QAM_16; break;
  373.         case 32: fe_modulation = QAM_32; break;
  374.         case 64: fe_modulation = QAM_64; break;
  375.         case 128: fe_modulation = QAM_128; break;
  376.         case 256: fe_modulation = QAM_256; break;
  377.         default:
  378.             msg_Dbg( p_access, "terrestrial/cable dvb has constellation/modulation not set, using auto");
  379.             fe_modulation = QAM_AUTO;
  380.             break;
  381.     }
  382.     return fe_modulation;
  383. }
  384. /*****************************************************************************
  385.  * FrontendSetQPSK : controls the FE device
  386.  *****************************************************************************/
  387. static fe_sec_voltage_t DecodeVoltage( access_t *p_access )
  388. {
  389.     vlc_value_t         val;
  390.     fe_sec_voltage_t    fe_voltage;
  391.     var_Get( p_access, "dvb-voltage", &val );
  392.     msg_Dbg( p_access, "using voltage=%d", val.i_int );
  393.     switch( val.i_int )
  394.     {
  395.         case 0: fe_voltage = SEC_VOLTAGE_OFF; break;
  396.         case 13: fe_voltage = SEC_VOLTAGE_13; break;
  397.         case 18: fe_voltage = SEC_VOLTAGE_18; break;
  398.         default:
  399.             fe_voltage = SEC_VOLTAGE_OFF;
  400.             msg_Err( p_access, "argument has invalid voltage (%d)", val.i_int );
  401.             break;
  402.     }
  403.     return fe_voltage;
  404. }
  405. static fe_sec_tone_mode_t DecodeTone( access_t *p_access )
  406. {
  407.     vlc_value_t         val;
  408.     fe_sec_tone_mode_t  fe_tone;
  409.     var_Get( p_access, "dvb-tone", &val );
  410.     msg_Dbg( p_access, "using tone=%d", val.i_int );
  411.     switch( val.i_int )
  412.     {
  413.         case 0: fe_tone = SEC_TONE_OFF; break;
  414.         case 1: fe_tone = SEC_TONE_ON; break;
  415.         default:
  416.             fe_tone = SEC_TONE_OFF;
  417.             msg_Err( p_access, "argument has invalid tone mode (%d)", val.i_int);
  418.             break;
  419.     }
  420.     return fe_tone;
  421. }
  422. struct diseqc_cmd_t
  423. {
  424.     struct dvb_diseqc_master_cmd cmd;
  425.     uint32_t wait;
  426. };
  427. static int DoDiseqc( access_t *p_access )
  428. {
  429.     access_sys_t *p_sys = p_access->p_sys;
  430.     frontend_t * p_frontend = p_sys->p_frontend;
  431.     vlc_value_t val;
  432.     int i_frequency, i_lnb_slof;
  433.     fe_sec_voltage_t fe_voltage;
  434.     fe_sec_tone_mode_t fe_tone;
  435.     int i_err;
  436.     var_Get( p_access, "dvb-frequency", &val );
  437.     i_frequency = val.i_int;
  438.     var_Get( p_access, "dvb-lnb-slof", &val );
  439.     i_lnb_slof = val.i_int;
  440.     var_Get( p_access, "dvb-tone", &val );
  441.     if( val.i_int == -1 /* auto */ )
  442.     {
  443.         if( i_frequency >= i_lnb_slof )
  444.             val.i_int = 1;
  445.         else
  446.             val.i_int = 0;
  447.         var_Set( p_access, "dvb-tone", val );
  448.     }
  449.     fe_voltage = DecodeVoltage( p_access );
  450.     fe_tone = DecodeTone( p_access );
  451.     if( (i_err = ioctl( p_frontend->i_handle, FE_SET_VOLTAGE, fe_voltage )) < 0 )
  452.     {
  453.         msg_Err( p_access, "ioctl FE_SET_VOLTAGE failed, voltage=%d (%d) %s",
  454.                  fe_voltage, i_err, strerror(errno) );
  455.         return i_err;
  456.     }
  457.     var_Get( p_access, "dvb-satno", &val );
  458.     if( val.i_int != 0 )
  459.     {
  460.         /* digital satellite equipment control,
  461.          * specification is available from http://www.eutelsat.com/
  462.          */
  463.         if( (i_err = ioctl( p_frontend->i_handle, FE_SET_TONE,
  464.                              SEC_TONE_OFF )) < 0 )
  465.         {
  466.             msg_Err( p_access, "ioctl FE_SET_TONE failed, tone=off (%d) %s",
  467.                      i_err, strerror(errno) );
  468.             return i_err;
  469.         }
  470.         msleep( 15000 );
  471.         if( val.i_int >= 1 && val.i_int <= 4 )
  472.         {
  473.             /* 1.x compatible equipment */
  474.             struct diseqc_cmd_t cmd =  { {{0xe0, 0x10, 0x38, 0xf0, 0x00, 0x00}, 4}, 0 };
  475.             /* param: high nibble: reset bits, low nibble set bits,
  476.              * bits are: option, position, polarization, band
  477.              */
  478.             cmd.cmd.msg[3] = 0xf0 /* reset bits */
  479.                               | (((val.i_int - 1) * 4) & 0xc)
  480.                               | (fe_voltage == SEC_VOLTAGE_13 ? 0 : 2)
  481.                               | (fe_tone == SEC_TONE_ON ? 1 : 0);
  482.             if( (i_err = ioctl( p_frontend->i_handle, FE_DISEQC_SEND_MASTER_CMD,
  483.                                &cmd.cmd )) < 0 )
  484.             {
  485.                 msg_Err( p_access, "ioctl FE_SEND_MASTER_CMD failed (%d) %s",
  486.                          i_err, strerror(errno) );
  487.                 return i_err;
  488.             }
  489.             msleep(cmd.wait * 1000);
  490.         }
  491.         else
  492.         {
  493.             /* A or B simple diseqc */
  494.             if( (i_err = ioctl( p_frontend->i_handle, FE_DISEQC_SEND_BURST,
  495.                           val.i_int == -1 ? SEC_MINI_A : SEC_MINI_B )) < 0 )
  496.             {
  497.                 msg_Err( p_access, "ioctl FE_SEND_BURST failed (%d) %s",
  498.                          i_err, strerror(errno) );
  499.                 return i_err;
  500.             }
  501.         }
  502.         msleep(15000);
  503.     }
  504.     if( (i_err = ioctl( p_frontend->i_handle, FE_SET_TONE, fe_tone )) < 0 )
  505.     {
  506.         msg_Err( p_access, "ioctl FE_SET_TONE failed, tone=%s (%d) %s",
  507.                  fe_tone == SEC_TONE_ON ? "on" : "off", i_err,
  508.                  strerror(errno) );
  509.         return i_err;
  510.     }
  511.     msleep(15000);
  512.     return 0;
  513. }
  514. static int FrontendSetQPSK( access_t *p_access )
  515. {
  516.     access_sys_t *p_sys = p_access->p_sys;
  517.     frontend_t * p_frontend = p_sys->p_frontend;
  518.     struct dvb_frontend_parameters fep;
  519.     int i_ret;
  520.     vlc_value_t val;
  521.     int i_frequency, i_lnb_slof;
  522.     /* Prepare the fep structure */
  523.     var_Get( p_access, "dvb-frequency", &val );
  524.     i_frequency = val.i_int;
  525.     var_Get( p_access, "dvb-lnb-slof", &val );
  526.     i_lnb_slof = val.i_int;
  527.     if( i_frequency >= i_lnb_slof )
  528.         var_Get( p_access, "dvb-lnb-lof2", &val );
  529.     else
  530.         var_Get( p_access, "dvb-lnb-lof1", &val );
  531.     fep.frequency = i_frequency - val.i_int;
  532.     fep.inversion = DecodeInversion( p_access );
  533.     var_Get( p_access, "dvb-srate", &val );
  534.     fep.u.qpsk.symbol_rate = val.i_int;
  535.     var_Get( p_access, "dvb-fec", &val );
  536.     fep.u.qpsk.fec_inner = DecodeFEC( p_access, val.i_int );
  537.     if( DoDiseqc( p_access ) < 0 )
  538.     {
  539.         return VLC_EGENERIC;
  540.     }
  541.     msleep(100000);
  542.     /* Empty the event queue */
  543.     for( ; ; )
  544.     {
  545.         struct dvb_frontend_event event;
  546.         if( ioctl( p_frontend->i_handle, FE_GET_EVENT, &event ) < 0 )
  547.             break;
  548.     }
  549.     /* Now send it all to the frontend device */
  550.     if( (i_ret = ioctl( p_frontend->i_handle, FE_SET_FRONTEND, &fep )) < 0 )
  551.     {
  552.         msg_Err( p_access, "DVB-S: setting frontend failed (%d) %s", i_ret,
  553.                  strerror(errno) );
  554.         return VLC_EGENERIC;
  555.     }
  556.     return FrontendCheck( p_access );
  557. }
  558. /*****************************************************************************
  559.  * FrontendSetQAM : controls the FE device
  560.  *****************************************************************************/
  561. static int FrontendSetQAM( access_t *p_access )
  562. {
  563.     access_sys_t *p_sys = p_access->p_sys;
  564.     frontend_t * p_frontend = p_sys->p_frontend;
  565.     struct dvb_frontend_parameters fep;
  566.     vlc_value_t val;
  567.     int i_ret;
  568.     /* Prepare the fep structure */
  569.     var_Get( p_access, "dvb-frequency", &val );
  570.     fep.frequency = val.i_int;
  571.     fep.inversion = DecodeInversion( p_access );
  572.     var_Get( p_access, "dvb-srate", &val );
  573.     fep.u.qam.symbol_rate = val.i_int;
  574.     var_Get( p_access, "dvb-fec", &val );
  575.     fep.u.qam.fec_inner = DecodeFEC( p_access, val.i_int );
  576.     fep.u.qam.modulation = DecodeModulation( p_access );
  577.     /* Empty the event queue */
  578.     for( ; ; )
  579.     {
  580.         struct dvb_frontend_event event;
  581.         if( ioctl( p_frontend->i_handle, FE_GET_EVENT, &event ) < 0 )
  582.             break;
  583.     }
  584.     /* Now send it all to the frontend device */
  585.     if( (i_ret = ioctl( p_frontend->i_handle, FE_SET_FRONTEND, &fep )) < 0 )
  586.     {
  587.         msg_Err( p_access, "DVB-C: setting frontend failed (%d) %s", i_ret,
  588.                  strerror(errno) );
  589.         return VLC_EGENERIC;
  590.     }
  591.     return FrontendCheck( p_access );
  592. }
  593. /*****************************************************************************
  594.  * FrontendSetOFDM : controls the FE device
  595.  *****************************************************************************/
  596. static fe_bandwidth_t DecodeBandwidth( access_t *p_access )
  597. {
  598.     vlc_value_t         val;
  599.     fe_bandwidth_t      fe_bandwidth = 0;
  600.     var_Get( p_access, "dvb-bandwidth", &val );
  601.     msg_Dbg( p_access, "using bandwidth=%d", val.i_int );
  602.     switch( val.i_int )
  603.     {
  604.         case 0: fe_bandwidth = BANDWIDTH_AUTO; break;
  605.         case 6: fe_bandwidth = BANDWIDTH_6_MHZ; break;
  606.         case 7: fe_bandwidth = BANDWIDTH_7_MHZ; break;
  607.         case 8: fe_bandwidth = BANDWIDTH_8_MHZ; break;
  608.         default:
  609.             msg_Dbg( p_access, "terrestrial dvb has bandwidth not set, using auto" );
  610.             fe_bandwidth = BANDWIDTH_AUTO;
  611.             break;
  612.     }
  613.     return fe_bandwidth;
  614. }
  615. static fe_transmit_mode_t DecodeTransmission( access_t *p_access )
  616. {
  617.     vlc_value_t         val;
  618.     fe_transmit_mode_t  fe_transmission = 0;
  619.     var_Get( p_access, "dvb-transmission", &val );
  620.     msg_Dbg( p_access, "using transmission=%d", val.i_int );
  621.     switch( val.i_int )
  622.     {
  623.         case 0: fe_transmission = TRANSMISSION_MODE_AUTO; break;
  624.         case 2: fe_transmission = TRANSMISSION_MODE_2K; break;
  625.         case 8: fe_transmission = TRANSMISSION_MODE_8K; break;
  626.         default:
  627.             msg_Dbg( p_access, "terrestrial dvb has transmission mode not set, using auto");
  628.             fe_transmission = TRANSMISSION_MODE_AUTO;
  629.             break;
  630.     }
  631.     return fe_transmission;
  632. }
  633. static fe_guard_interval_t DecodeGuardInterval( access_t *p_access )
  634. {
  635.     vlc_value_t         val;
  636.     fe_guard_interval_t fe_guard = 0;
  637.     var_Get( p_access, "dvb-guard", &val );
  638.     msg_Dbg( p_access, "using guard=%d", val.i_int );
  639.     switch( val.i_int )
  640.     {
  641.         case 0: fe_guard = GUARD_INTERVAL_AUTO; break;
  642.         case 4: fe_guard = GUARD_INTERVAL_1_4; break;
  643.         case 8: fe_guard = GUARD_INTERVAL_1_8; break;
  644.         case 16: fe_guard = GUARD_INTERVAL_1_16; break;
  645.         case 32: fe_guard = GUARD_INTERVAL_1_32; break;
  646.         default:
  647.             msg_Dbg( p_access, "terrestrial dvb has guard interval not set, using auto");
  648.             fe_guard = GUARD_INTERVAL_AUTO;
  649.             break;
  650.     }
  651.     return fe_guard;
  652. }
  653. static fe_hierarchy_t DecodeHierarchy( access_t *p_access )
  654. {
  655.     vlc_value_t         val;
  656.     fe_hierarchy_t      fe_hierarchy = 0;
  657.     var_Get( p_access, "dvb-hierarchy", &val );
  658.     msg_Dbg( p_access, "using hierarchy=%d", val.i_int );
  659.     switch( val.i_int )
  660.     {
  661.         case -1: fe_hierarchy = HIERARCHY_NONE; break;
  662.         case 0: fe_hierarchy = HIERARCHY_AUTO; break;
  663.         case 1: fe_hierarchy = HIERARCHY_1; break;
  664.         case 2: fe_hierarchy = HIERARCHY_2; break;
  665.         case 4: fe_hierarchy = HIERARCHY_4; break;
  666.         default:
  667.             msg_Dbg( p_access, "terrestrial dvb has hierarchy not set, using auto");
  668.             fe_hierarchy = HIERARCHY_AUTO;
  669.             break;
  670.     }
  671.     return fe_hierarchy;
  672. }
  673. static int FrontendSetOFDM( access_t * p_access )
  674. {
  675.     access_sys_t *p_sys = p_access->p_sys;
  676.     frontend_t * p_frontend = p_sys->p_frontend;
  677.     struct dvb_frontend_parameters fep;
  678.     vlc_value_t val;
  679.     int ret;
  680.     /* Prepare the fep structure */
  681.     var_Get( p_access, "dvb-frequency", &val );
  682.     fep.frequency = val.i_int;
  683.     fep.inversion = DecodeInversion( p_access );
  684.     fep.u.ofdm.bandwidth = DecodeBandwidth( p_access );
  685.     var_Get( p_access, "dvb-code-rate-hp", &val );
  686.     fep.u.ofdm.code_rate_HP = DecodeFEC( p_access, val.i_int );
  687.     var_Get( p_access, "dvb-code-rate-lp", &val );
  688.     fep.u.ofdm.code_rate_LP = DecodeFEC( p_access, val.i_int );
  689.     fep.u.ofdm.constellation = DecodeModulation( p_access );
  690.     fep.u.ofdm.transmission_mode = DecodeTransmission( p_access );
  691.     fep.u.ofdm.guard_interval = DecodeGuardInterval( p_access );
  692.     fep.u.ofdm.hierarchy_information = DecodeHierarchy( p_access );
  693.     /* Empty the event queue */
  694.     for( ; ; )
  695.     {
  696.         struct dvb_frontend_event event;
  697.         if( ioctl( p_frontend->i_handle, FE_GET_EVENT, &event ) < 0 )
  698.             break;
  699.     }
  700.     /* Now send it all to the frontend device */
  701.     if( (ret = ioctl( p_frontend->i_handle, FE_SET_FRONTEND, &fep )) < 0 )
  702.     {
  703.         msg_Err( p_access, "DVB-T: setting frontend failed (%d) %s", ret,
  704.                  strerror(errno) );
  705.         return -1;
  706.     }
  707.     return FrontendCheck( p_access );
  708. }
  709. /******************************************************************
  710.  * FrontendCheck: Check completion of the frontend control sequence
  711.  ******************************************************************/
  712. static int FrontendCheck( access_t * p_access )
  713. {
  714.     access_sys_t *p_sys = p_access->p_sys;
  715.     frontend_t * p_frontend = p_sys->p_frontend;
  716.     int i_ret;
  717.     while ( !p_access->b_die && !p_access->b_error )
  718.     {
  719.         fe_status_t status;
  720.         if( (i_ret = ioctl( p_frontend->i_handle, FE_READ_STATUS,
  721.                              &status )) < 0 )
  722.         {
  723.             msg_Err( p_access, "reading frontend status failed (%d) %s",
  724.                      i_ret, strerror(errno) );
  725.             return i_ret;
  726.         }
  727.         if(status & FE_HAS_SIGNAL) /* found something above the noise level */
  728.             msg_Dbg(p_access, "check frontend ... has signal");
  729.         if(status & FE_HAS_CARRIER) /* found a DVB signal  */
  730.             msg_Dbg(p_access, "check frontend ... has carrier");
  731.         if(status & FE_HAS_VITERBI) /* FEC is stable  */
  732.             msg_Dbg(p_access, "check frontend ... has stable forward error correction");
  733.         if(status & FE_HAS_SYNC)    /* found sync bytes  */
  734.             msg_Dbg(p_access, "check frontend ... has sync");
  735.         if(status & FE_HAS_LOCK)    /* everything's working... */
  736.         {
  737.             int32_t value;
  738.             msg_Dbg(p_access, "check frontend ... has lock");
  739.             msg_Dbg(p_access, "tuning succeeded");
  740.             /* Read some statistics */
  741.             value = 0;
  742.             if( ioctl( p_frontend->i_handle, FE_READ_BER, &value ) >= 0 )
  743.                 msg_Dbg( p_access, "Bit error rate: %d", value );
  744.             value = 0;
  745.             if( ioctl( p_frontend->i_handle, FE_READ_SIGNAL_STRENGTH, &value ) >= 0 )
  746.                 msg_Dbg( p_access, "Signal strength: %d", value );
  747.             value = 0;
  748.             if( ioctl( p_frontend->i_handle, FE_READ_SNR, &value ) >= 0 )
  749.                 msg_Dbg( p_access, "SNR: %d", value );
  750.             return 0;
  751.         }
  752.         if(status & FE_TIMEDOUT)    /*  no lock within the last ~2 seconds */
  753.         {
  754.             msg_Err(p_access, "tuning failed ... timed out");
  755.             return -2;
  756.         }
  757.         if(status & FE_REINIT)
  758.         {
  759.             /*  frontend was reinitialized,  */
  760.             /*  application is recommended to reset */
  761.             /*  DiSEqC, tone and parameters */
  762.             msg_Err(p_access, "tuning failed ... resend frontend parameters");
  763.             return -3;
  764.         }
  765.         msleep(500000);
  766.     }
  767.     return -1;
  768. }
  769. /*
  770.  * Demux
  771.  */
  772. /*****************************************************************************
  773.  * DMXSetFilter : controls the demux to add a filter
  774.  *****************************************************************************/
  775. int E_(DMXSetFilter)( access_t * p_access, int i_pid, int * pi_fd, int i_type )
  776. {
  777.     struct dmx_pes_filter_params s_filter_params;
  778.     int i_ret;
  779.     unsigned int i_adapter, i_device;
  780.     char dmx[128];
  781.     vlc_value_t val;
  782.     var_Get( p_access, "dvb-adapter", &val );
  783.     i_adapter = val.i_int;
  784.     var_Get( p_access, "dvb-device", &val );
  785.     i_device = val.i_int;
  786.     if( snprintf( dmx, sizeof(dmx), DMX, i_adapter, i_device )
  787.             >= (int)sizeof(dmx) )
  788.     {
  789.         msg_Err( p_access, "snprintf() truncated string for DMX" );
  790.         dmx[sizeof(dmx) - 1] = '';
  791.     }
  792.     msg_Dbg( p_access, "Opening device %s", dmx );
  793.     if( (*pi_fd = open(dmx, O_RDWR)) < 0 )
  794.     {
  795.         msg_Err( p_access, "DMXSetFilter: opening device failed (%s)",
  796.                  strerror(errno) );
  797.         return VLC_EGENERIC;
  798.     }
  799.     /* We fill the DEMUX structure : */
  800.     s_filter_params.pid     =   i_pid;
  801.     s_filter_params.input   =   DMX_IN_FRONTEND;
  802.     s_filter_params.output  =   DMX_OUT_TS_TAP;
  803.     s_filter_params.flags   =   DMX_IMMEDIATE_START;
  804.     switch ( i_type )
  805.     {   /* First device */
  806.         case 1:
  807.             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_VIDEO0 for PID %d", i_pid);
  808.             s_filter_params.pes_type = DMX_PES_VIDEO0;
  809.             break;
  810.         case 2:
  811.             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_AUDIO0 for PID %d", i_pid);
  812.             s_filter_params.pes_type = DMX_PES_AUDIO0;
  813.             break;
  814.         case 3:
  815.             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_TELETEXT0 for PID %d", i_pid);
  816.             s_filter_params.pes_type = DMX_PES_TELETEXT0;
  817.             break;
  818.         case 4:
  819.             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_SUBTITLE0 for PID %d", i_pid);
  820.             s_filter_params.pes_type = DMX_PES_SUBTITLE0;
  821.             break;
  822.         case 5:
  823.             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_PCR0 for PID %d", i_pid);
  824.             s_filter_params.pes_type = DMX_PES_PCR0;
  825.             break;
  826.         /* Second device */
  827.         case 6:
  828.             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_VIDEO1 for PID %d", i_pid);
  829.             s_filter_params.pes_type = DMX_PES_VIDEO1;
  830.             break;
  831.         case 7:
  832.             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_AUDIO1 for PID %d", i_pid);
  833.             s_filter_params.pes_type = DMX_PES_AUDIO1;
  834.             break;
  835.         case 8:
  836.             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_TELETEXT1 for PID %d", i_pid);
  837.             s_filter_params.pes_type = DMX_PES_TELETEXT1;
  838.             break;
  839.         case 9:
  840.             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_SUBTITLE1 for PID %d", i_pid);
  841.             s_filter_params.pes_type = DMX_PES_SUBTITLE1;
  842.             break;
  843.         case 10:
  844.             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_PCR1 for PID %d", i_pid);
  845.             s_filter_params.pes_type = DMX_PES_PCR1;
  846.             break;
  847.         /* Third device */
  848.         case 11:
  849.             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_VIDEO2 for PID %d", i_pid);
  850.             s_filter_params.pes_type = DMX_PES_VIDEO2;
  851.             break;
  852.         case 12:
  853.             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_AUDIO2 for PID %d", i_pid);
  854.             s_filter_params.pes_type = DMX_PES_AUDIO2;
  855.             break;
  856.         case 13:
  857.             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_TELETEXT2 for PID %d", i_pid);
  858.             s_filter_params.pes_type = DMX_PES_TELETEXT2;
  859.             break;
  860.         case 14:
  861.             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_SUBTITLE2 for PID %d", i_pid);
  862.             s_filter_params.pes_type = DMX_PES_SUBTITLE2;
  863.             break;
  864.         case 15:
  865.             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_PCR2 for PID %d", i_pid);
  866.             s_filter_params.pes_type = DMX_PES_PCR2;
  867.             break;
  868.         /* Forth device */
  869.         case 16:
  870.             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_VIDEO3 for PID %d", i_pid);
  871.             s_filter_params.pes_type = DMX_PES_VIDEO3;
  872.             break;
  873.         case 17:
  874.             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_AUDIO3 for PID %d", i_pid);
  875.             s_filter_params.pes_type = DMX_PES_AUDIO3;
  876.             break;
  877.         case 18:
  878.             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_TELETEXT3 for PID %d", i_pid);
  879.             s_filter_params.pes_type = DMX_PES_TELETEXT3;
  880.             break;
  881.         case 19:
  882.             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_SUBTITLE3 for PID %d", i_pid);
  883.             s_filter_params.pes_type = DMX_PES_SUBTITLE3;
  884.             break;
  885.         case 20:
  886.             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_PCR3 for PID %d", i_pid);
  887.             s_filter_params.pes_type = DMX_PES_PCR3;
  888.             break;
  889.         /* Usually used by Nova cards */
  890.         case 21:
  891.         default:
  892.             msg_Dbg(p_access, "DMXSetFilter: DMX_PES_OTHER for PID %d", i_pid);
  893.             s_filter_params.pes_type = DMX_PES_OTHER;
  894.             break;
  895.     }
  896.     /* We then give the order to the device : */
  897.     if( (i_ret = ioctl( *pi_fd, DMX_SET_PES_FILTER, &s_filter_params )) < 0 )
  898.     {
  899.         msg_Err( p_access, "DMXSetFilter: failed with %d (%s)", i_ret,
  900.                  strerror(errno) );
  901.         return VLC_EGENERIC;
  902.     }
  903.     return VLC_SUCCESS;
  904. }
  905. /*****************************************************************************
  906.  * DMXUnsetFilter : removes a filter
  907.  *****************************************************************************/
  908. int E_(DMXUnsetFilter)( access_t * p_access, int i_fd )
  909. {
  910.     int i_ret;
  911.     if( (i_ret = ioctl( i_fd, DMX_STOP )) < 0 )
  912.     {
  913.         msg_Err( p_access, "DMX_STOP failed for demux (%d) %s",
  914.                  i_ret, strerror(errno) );
  915.         return i_ret;
  916.     }
  917.     msg_Dbg( p_access, "DMXUnsetFilter: closing demux %d", i_fd );
  918.     close( i_fd );
  919.     return VLC_SUCCESS;
  920. }
  921. /*
  922.  * DVR device
  923.  */
  924. /*****************************************************************************
  925.  * DVROpen :
  926.  *****************************************************************************/
  927. int E_(DVROpen)( access_t * p_access )
  928. {
  929.     access_sys_t *p_sys = p_access->p_sys;
  930.     unsigned int i_adapter, i_device;
  931.     char dvr[128];
  932.     vlc_value_t val;
  933.     var_Get( p_access, "dvb-adapter", &val );
  934.     i_adapter = val.i_int;
  935.     var_Get( p_access, "dvb-device", &val );
  936.     i_device = val.i_int;
  937.     if( snprintf( dvr, sizeof(dvr), DVR, i_adapter, i_device )
  938.             >= (int)sizeof(dvr) )
  939.     {
  940.         msg_Err( p_access, "snprintf() truncated string for DVR" );
  941.         dvr[sizeof(dvr) - 1] = '';
  942.     }
  943.     msg_Dbg( p_access, "Opening device %s", dvr );
  944.     if( (p_sys->i_handle = open(dvr, O_RDONLY)) < 0 )
  945.     {
  946.         msg_Err( p_access, "DVROpen: opening device failed (%s)",
  947.                  strerror(errno) );
  948.         return VLC_EGENERIC;
  949.     }
  950.     if ( ioctl( p_sys->i_handle, DMX_SET_BUFFER_SIZE, DMX_BUFFER_SIZE ) < 0 )
  951.     {
  952.         msg_Warn( p_access, "couldn't set DMX_BUFFER_SIZE (%s)",
  953.                   strerror(errno) );
  954.     }
  955.     return VLC_SUCCESS;
  956. }
  957. /*****************************************************************************
  958.  * DVRClose :
  959.  *****************************************************************************/
  960. void E_(DVRClose)( access_t * p_access )
  961. {
  962.     access_sys_t *p_sys = p_access->p_sys;
  963.     close( p_sys->i_handle );
  964. }
  965. /*
  966.  * CAM device
  967.  */
  968. /*****************************************************************************
  969.  * CAMOpen :
  970.  *****************************************************************************/
  971. int E_(CAMOpen)( access_t *p_access )
  972. {
  973.     access_sys_t *p_sys = p_access->p_sys;
  974.     char ca[128];
  975.     int i_adapter, i_device, i_slot;
  976.     ca_caps_t caps;
  977.     i_adapter = var_GetInteger( p_access, "dvb-adapter" );
  978.     i_device = var_GetInteger( p_access, "dvb-device" );
  979.     if( snprintf( ca, sizeof(ca), CA, i_adapter, i_device ) >= (int)sizeof(ca) )
  980.     {
  981.         msg_Err( p_access, "snprintf() truncated string for CA" );
  982.         ca[sizeof(ca) - 1] = '';
  983.     }
  984.     msg_Dbg( p_access, "Opening device %s", ca );
  985.     if( (p_sys->i_ca_handle = open(ca, O_RDWR | O_NONBLOCK)) < 0 )
  986.     {
  987.         msg_Err( p_access, "CAMInit: opening device failed (%s)",
  988.                  strerror(errno) );
  989.         p_sys->i_ca_handle = 0;
  990.         return VLC_EGENERIC;
  991.     }
  992.     if ( ioctl( p_sys->i_ca_handle, CA_GET_CAP, &caps ) != 0
  993.           || caps.slot_num == 0 || caps.slot_type != CA_CI_LINK )
  994.     {
  995.         msg_Err( p_access, "CAMInit: no compatible CAM module" );
  996.         close( p_sys->i_ca_handle );
  997.         p_sys->i_ca_handle = 0;
  998.         return VLC_EGENERIC;
  999.     }
  1000.     p_sys->i_nb_slots = caps.slot_num;
  1001.     memset( p_sys->pb_active_slot, 0, sizeof(vlc_bool_t) * MAX_CI_SLOTS );
  1002.     for ( i_slot = 0; i_slot < p_sys->i_nb_slots; i_slot++ )
  1003.     {
  1004.         if ( ioctl( p_sys->i_ca_handle, CA_RESET, 1 << i_slot) != 0 )
  1005.         {
  1006.             msg_Err( p_access, "CAMInit: couldn't reset slot %d", i_slot );
  1007.         }
  1008.     }
  1009.     msg_Dbg( p_access, "CAMInit: found a CI handler with %d slots",
  1010.              p_sys->i_nb_slots );
  1011.     p_sys->i_ca_timeout = 100000;
  1012.     /* Wait a bit otherwise it doesn't initialize properly... */
  1013.     msleep( 1000000 );
  1014.     return VLC_SUCCESS;
  1015. }
  1016. /*****************************************************************************
  1017.  * CAMPoll :
  1018.  *****************************************************************************/
  1019. int E_(CAMPoll)( access_t * p_access )
  1020. {
  1021.     access_sys_t *p_sys = p_access->p_sys;
  1022.     if ( p_sys->i_ca_handle == 0 )
  1023.     {
  1024.         return VLC_EGENERIC;
  1025.     }
  1026.     return E_(en50221_Poll)( p_access );
  1027. }
  1028. /*****************************************************************************
  1029.  * CAMSet :
  1030.  *****************************************************************************/
  1031. int E_(CAMSet)( access_t * p_access, uint8_t **pp_capmts, int i_nb_capmts )
  1032. {
  1033.     access_sys_t *p_sys = p_access->p_sys;
  1034.     if ( p_sys->i_ca_handle == 0 )
  1035.     {
  1036.         return VLC_EGENERIC;
  1037.     }
  1038.     E_(en50221_SetCAPMT)( p_access, pp_capmts, i_nb_capmts );
  1039.     return VLC_SUCCESS;
  1040. }
  1041. /*****************************************************************************
  1042.  * CAMClose :
  1043.  *****************************************************************************/
  1044. void E_(CAMClose)( access_t * p_access )
  1045. {
  1046.     access_sys_t *p_sys = p_access->p_sys;
  1047.     E_(en50221_End)( p_access );
  1048.     if ( p_sys->i_ca_handle )
  1049.     {
  1050.         close( p_sys->i_ca_handle );
  1051.     }
  1052. }