unicap.c
Upload User: shyika
Upload Date: 2017-11-25
Package Size: 1227k
Code Size: 28k
Category:

Video Capture

Development Platform:

Unix_Linux

  1. /*
  2.   unicap
  3.   Copyright (C) 2004  Arne Caspari
  4.   This program is free software; you can redistribute it and/or modify
  5.   it under the terms of the GNU General Public License as published by
  6.   the Free Software Foundation; either version 2 of the License, or
  7.   (at your option) any later version.
  8.   This program is distributed in the hope that it will be useful,
  9.   but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11.   GNU General Public License for more details.
  12.   You should have received a copy of the GNU General Public License
  13.   along with this program; if not, write to the Free Software
  14.   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  15. */
  16. #include "config.h"
  17. #include <errno.h>
  18. #include <stdlib.h>
  19. #include <stdio.h>
  20. #include <string.h>
  21. #include <stdarg.h>
  22. #include <sys/types.h>
  23. #include <sys/ipc.h>
  24. #include <sys/sem.h>
  25. #include <sys/mman.h>
  26. #include <sys/stat.h>
  27. #include <sys/file.h>
  28. #include <fcntl.h>
  29. #include <dirent.h>
  30. #include <math.h>
  31. #if !ENABLE_STATIC_CPI
  32. #include <dlfcn.h> // dynamic loader
  33. #else
  34. #include "static_cpi.h"
  35. #endif
  36. #include "unicap.h"
  37. #include "unicap_version.h"
  38. #include "unicap_private.h"
  39. #include "unicap_cpi.h"
  40. #include "unicap_helpers.h"
  41. #include "check_match.h"
  42. #include <unicap_status.h>
  43. #if UNICAP_DEBUG
  44. #define DEBUG
  45. #endif
  46. #include "debug.h"
  47. union semun_linux {
  48.       int              val;    /* Value for SETVAL */
  49.       struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
  50.       unsigned short  *array;  /* Array for GETALL, SETALL */
  51.       struct seminfo  *__buf;  /* Buffer for IPC_INFO
  52.   (Linux specific) */
  53. };
  54. static unicap_handle_t unicap_copy_handle( unicap_handle_t handle );
  55. const unsigned int unicap_major_version=UNICAP_MAJOR_VERSION;
  56. const unsigned int unicap_minor_version=UNICAP_MINOR_VERSION;
  57. const unsigned int unicap_micro_version=UNICAP_MICRO_VERSION;
  58. static int g_device_count = 0;
  59. static unicap_device_t g_devices[128];
  60. static int g_filter_remote = 0;
  61. #if ENABLE_STATIC_CPI
  62. static int g_static_cpi_initialized = 0;
  63. static void initialize_static_cpis()
  64. {
  65.    if( !g_static_cpi_initialized )
  66.    {
  67.       int i;
  68. #if BUILD_DCAM
  69.       unicap_dcam_register_static_cpi( &static_cpis_s[UNICAP_STATIC_CPI_DCAM] );
  70. #endif
  71. #if BUILD_VID21394
  72.       unicap_vid21394_register_static_cpi( &static_cpis_s[UNICAP_STATIC_CPI_VID21394] );
  73. #endif
  74. #if BUILD_V4L
  75.       unicap_v4l_register_static_cpi( &static_cpis_s[UNICAP_STATIC_CPI_V4L] );
  76. #endif
  77. #if BUILD_V4L2
  78.       unicap_v4l2_register_static_cpi( &static_cpis_s[UNICAP_STATIC_CPI_V4L2] );
  79. #endif
  80.       static_cpis_s[UNICAP_STATIC_CPI_COUNT] = 0;
  81.    }
  82.    g_static_cpi_initialized = 1;
  83. }
  84. #endif
  85. unicap_status_t unicap_set_filter_remote( int do_filter )
  86. {
  87.    if( do_filter )
  88.    {
  89.       g_filter_remote = 1;
  90.    }
  91.    else
  92.    {
  93.       g_filter_remote = 0;
  94.    }
  95.    return STATUS_SUCCESS;
  96. }
  97. static unicap_status_t _unicap_acquire_cpi_lock( int sem_id )
  98. {
  99. #ifdef UNICAP_THREAD_LOCKING
  100.    if( sem_id != -1 )
  101.    {
  102.       struct sembuf sops;
  103.       sops.sem_num = 0;
  104.       sops.sem_op = -1;
  105.       sops.sem_flg = SEM_UNDO;
  106.       if( semop( sem_id, &sops, 1 ) < 0 )
  107.       {
  108.  return STATUS_FAILURE;
  109.       }
  110.    }
  111. #endif
  112.    return STATUS_SUCCESS;
  113. }
  114. static unicap_status_t _unicap_release_cpi_lock( int sem_id )
  115. {
  116. #ifdef UNICAP_THREAD_LOCKING
  117.    if( sem_id != -1 )
  118.    {
  119.       struct sembuf sops;
  120.       sops.sem_num = 0;
  121.       sops.sem_op = 1;
  122.       sops.sem_flg = SEM_UNDO;
  123.       if( semop( sem_id, &sops, 1 ) < 0 )
  124.       {
  125.  return STATUS_FAILURE;
  126.       }
  127.    }
  128. #endif
  129.    return STATUS_SUCCESS;
  130. }
  131. static void unicap_event_callback( unicap_handle_t handle, unicap_event_t event, ... )
  132. {
  133.    if( !handle->cb_info[event].func )
  134.    {
  135.       return;
  136.    }
  137.    
  138.    switch( event )
  139.    {
  140.       case UNICAP_EVENT_DEVICE_REMOVED:
  141.       {
  142.  handle->cb_info[event].func( event, handle, handle->cb_info[event].user_ptr );
  143.       }
  144.       break;
  145.       
  146.       case UNICAP_EVENT_NEW_FRAME:
  147.       {
  148.  va_list ap;
  149.  unicap_data_buffer_t *buffer;
  150.  
  151.  va_start( ap, event );
  152.  buffer = va_arg(ap, unicap_data_buffer_t *);
  153.  va_end( ap );
  154.  
  155.  handle->cb_info[event].func( event, handle, buffer, handle->cb_info[event].user_ptr );
  156.       }
  157.       break;
  158.       
  159.       default:
  160.       {
  161.  handle->cb_info[event].func( event, handle, handle->cb_info[event].user_ptr );
  162.       }
  163.       break;
  164.    }
  165. }
  166. unicap_status_t unicap_check_version( unsigned int major, unsigned int minor, unsigned int micro )
  167. {
  168.    unicap_status_t status = STATUS_SUCCESS;
  169.    
  170.    if( UNICAP_MAJOR_VERSION < major )
  171.    {
  172.       status = STATUS_INCOMPATIBLE_MAJOR_VERSION;
  173.    }
  174.    else if( major == UNICAP_MAJOR_VERSION )
  175.    {
  176.       if( UNICAP_MINOR_VERSION < minor )
  177.       {
  178.  status = STATUS_INCOMPATIBLE_MINOR_VERSION;
  179.       }
  180.       else if( minor == UNICAP_MINOR_VERSION )
  181.       {
  182.  if( UNICAP_MICRO_VERSION < micro )
  183.  {
  184.     status = STATUS_INCOMPATIBLE_MICRO_VERSION;
  185.  }
  186.       }
  187.    }
  188.    
  189.    return status;
  190. }
  191. unicap_status_t unicap_reenumerate_devices( int *_pcount )
  192. {
  193.    int count = 128;
  194.    unicap_real_enumerate_devices( &count );
  195.    g_device_count = count;
  196.    if( _pcount )
  197.    {
  198.       *_pcount = count;
  199.    }
  200.    return g_device_count ? STATUS_SUCCESS : STATUS_NO_DEVICE;
  201. }
  202. unicap_status_t unicap_enumerate_devices( unicap_device_t *specifier, unicap_device_t *device, int index )
  203. {
  204.    int current_index = -1;
  205.    if( g_device_count != 0)
  206.    {
  207.       int i;
  208.       if( index >= g_device_count )
  209.       {
  210.  return STATUS_NO_MATCH;
  211.       }
  212.       for( i = 0; i < g_device_count; i++ )
  213.       {
  214.  if( _check_device_match( specifier, &g_devices[i] ) )
  215.  {
  216.     current_index++;
  217.     if( current_index == index )
  218.     {
  219.        memcpy( device, &g_devices[i], sizeof( unicap_device_t ) );
  220.        return STATUS_SUCCESS;
  221.     }
  222.  }
  223.       }
  224.    } 
  225.    else 
  226.    {
  227.       if( SUCCESS( unicap_reenumerate_devices( &g_device_count ) ) )
  228.       {
  229.  if( g_device_count )
  230.  {
  231.     return unicap_enumerate_devices( specifier, device, index );
  232.  }
  233.       }
  234.    }
  235.    return STATUS_NO_MATCH;
  236. }
  237. #if !ENABLE_STATIC_CPI
  238. static unicap_status_t enumerate_devices( int *count )
  239. {
  240.    void *dlhandle;
  241.    cpi_register_t cpi_register;
  242.    unicap_status_t status = STATUS_SUCCESS;
  243.    struct _unicap_cpi cpi;
  244.    int current_index = 0;
  245.    DIR *cpi_dir;
  246.    struct dirent *cpi_dirent;
  247.    char *dirname;
  248.    char buffer[33000];
  249.    const char suffix[] = ".so";
  250. #ifdef INSTALL_PREFIX
  251.    strcpy( buffer, INSTALL_PREFIX );
  252. #else
  253.    strcpy( buffer, "" );
  254. #endif
  255.    strcat( buffer, "/lib/unicap"PKG_VERSION"/cpi" );
  256.    TRACE( "cpi search path: %s, suffix: %sn", buffer, suffix ); 
  257.    cpi_dir = opendir( buffer );
  258.    if( !cpi_dir )
  259.    {
  260.       return STATUS_FAILURE;
  261.    }
  262.    dirname = buffer;
  263.    while( ( cpi_dirent = readdir( cpi_dir ) ) > 0 )
  264.    {
  265.       char filename[512];
  266.       int tmp_index = 0;
  267.       sprintf( filename, "%s/%s", dirname, cpi_dirent->d_name );
  268.       if( ( !strstr( filename, suffix ) ) ||
  269.   ( strlen( strstr( filename, suffix ) ) != strlen( suffix ) ) )
  270.       {
  271.  continue;
  272.       }
  273.       TRACE( "open cpi: %sn", filename );
  274.       // load the cpi as a .so
  275.       dlhandle = dlopen( filename, RTLD_NOW );
  276.       if( !dlhandle )
  277.       {
  278.  TRACE( "cpi load: %sn", dlerror() );
  279.  continue;
  280.       }
  281.       cpi_register = dlsym( dlhandle, "cpi_register" );
  282.       if( !cpi_register )
  283.       {
  284.  TRACE( "cpi load: %sn", dlerror() );
  285.  dlclose( dlhandle );
  286.  continue;
  287.       }
  288.       memset( &cpi, 0x0, sizeof( struct _unicap_cpi ) );
  289.       cpi_register( &cpi );
  290.       if( g_filter_remote && ( cpi.cpi_flags & UNICAP_CPI_REMOTE ) )
  291.       {
  292.  TRACE( "cpi load: remote cpi filtered outn" );
  293.  dlclose( dlhandle );
  294.  continue;
  295.       }
  296.       if( CPI_VERSION_HI(cpi.cpi_version) > 2 )
  297.       {
  298.  TRACE( "cpi load: unknown versionn" );
  299.  dlclose( dlhandle );
  300.  continue;
  301.       }
  302.       TRACE( "cpi.cpi_enumerate_devices: %pn", cpi.cpi_enumerate_devices );
  303.       // look at all devices supplied by the cpi
  304.       while( ( current_index < *count ) && 
  305.      ( SUCCESS( status = cpi.cpi_enumerate_devices( &g_devices[current_index], tmp_index ) ) ) )
  306.       {
  307.  TRACE( "current_index: %dn", current_index );
  308.  strcpy( g_devices[current_index].cpi_layer, filename );
  309.  current_index++;
  310.  tmp_index++;
  311.       }
  312.       TRACE( "status: %08xn", status );
  313.       dlclose( dlhandle );
  314.    }
  315.    *count = current_index;
  316.    closedir( cpi_dir );
  317.    return status;
  318. }
  319. #else
  320. static unicap_status_t enumerate_devices( int *count )
  321. {
  322.    int idx_cpi = 0;
  323.    int idx_device = 0;
  324.    unicap_status_t status = STATUS_SUCCESS;
  325.    
  326.    initialize_static_cpis();
  327.    while( static_cpis_s[idx_cpi] != 0 )
  328.    {
  329.       struct _unicap_cpi *cpi = static_cpis_s[idx_cpi];
  330.       int idx_tmp = 0;
  331.       
  332.       while( ( idx_device < *count ) &&
  333.      ( SUCCESS( status = cpi->cpi_enumerate_devices( &g_devices[idx_device], idx_tmp++ ) ) ) )
  334.       {
  335.  TRACE( "current index: %dn", idx_device );
  336.  sprintf( g_devices[idx_device].cpi_layer, "%d", idx_cpi );
  337.  idx_device++;
  338.       }
  339.       
  340.       TRACE( "status: %08xn", status );
  341.       
  342.       idx_cpi++;
  343.    }
  344.    *count = idx_device;
  345.    
  346.    return status;
  347. }
  348. #endif //ENABLE_STATIC_CPI
  349. unicap_status_t unicap_real_enumerate_devices( int *count )
  350. {
  351.    return enumerate_devices( count );
  352. }
  353. #if !ENABLE_STATIC_CPI
  354. static unicap_status_t open_cpi( unicap_handle_t *unicap_handle, unicap_device_t *device )
  355. {
  356.    void *dlhandle;
  357.    unicap_handle_t handle;
  358.    unicap_status_t status;
  359.    int i;
  360.    TRACE( "open----------%sn", device->identifier );
  361.    if( !device || !unicap_handle )
  362.    {
  363.       return STATUS_INVALID_PARAMETER;
  364.    }
  365.    *unicap_handle = NULL;
  366.    handle = malloc( sizeof( struct _unicap_handle ) );
  367.    if( !handle )
  368.    {
  369.       return STATUS_NO_MEM;
  370.    }
  371.    // initialize data structure
  372.    memset( handle, 0, sizeof( struct _unicap_handle ) );
  373.    handle->cb_info = malloc( sizeof( struct _unicap_callback_info ) * UNICAP_EVENT_LAST );
  374.    for( i = 0; i < UNICAP_EVENT_LAST; i++ )
  375.    {
  376.       handle->cb_info[ i ].func = NULL;
  377.       handle->cb_info[ i ].user_ptr = NULL;
  378.    }
  379.    sprintf( handle->device_uid, "%s", device->identifier );
  380.    dlhandle = dlopen( device->cpi_layer, RTLD_LAZY );
  381.    if( !dlhandle )
  382.    {
  383.       free( handle );
  384.       return STATUS_CPI_OPEN_FAILED;
  385.    }
  386.    //
  387.    // resolve cpi symbols
  388.    //
  389.    handle->cpi.cpi_register = dlsym( dlhandle, "cpi_register" );
  390.    if( !handle->cpi.cpi_register )
  391.    {
  392.       TRACE( "unicap: cpi %s : INVALID_CPIn", device->cpi_layer );
  393.       free( handle );
  394.       dlclose( dlhandle );
  395.       return STATUS_INVALID_CPI;
  396.    }
  397.    handle->cpi.cpi_register( &handle->cpi );
  398.    if( CPI_VERSION_HI(handle->cpi.cpi_version) > 2 )
  399.    {
  400.       TRACE( "cpi_version hi: %dn", CPI_VERSION_HI(handle->cpi.cpi_version) );
  401.       free( handle );
  402.       dlclose( dlhandle );
  403.       return STATUS_UNSUPPORTED_CPI_VERSION;
  404.    }
  405.    // TODO:: check capabilities
  406.    // if serialized operation is requested, use a semaphore to prevent that more than one thread 
  407.    // could enter a cpi function at the time
  408.    if( handle->cpi.cpi_flags & UNICAP_CPI_SERIALIZED )
  409.    {
  410.       struct semid_ds semid;
  411.       union semun_linux semun;
  412.       // serialize per cpi. TODO: serialize per device optionally
  413.       handle->sem_key = ftok( device->cpi_layer, 'a' );
  414.       if( handle->sem_key == -1 )
  415.       {
  416.  free( handle );
  417.  dlclose( dlhandle );
  418.  return STATUS_FAILURE;
  419.       }
  420.       handle->sem_id = semget( handle->sem_key, 1, IPC_CREAT );
  421.       if( handle->sem_id == -1 )
  422.       {
  423.  free( handle );
  424.  dlclose( dlhandle );
  425.  return STATUS_FAILURE;
  426.       }
  427.       semun.buf = &semid;
  428.       // check if the semaphore is used the first time -> initialize it
  429.       semctl( handle->sem_id, 0, IPC_STAT, semun );
  430.       if( semid.sem_otime == 0 )
  431.       {
  432.  semun.val = 1;
  433.  semctl( handle->sem_id, 0, SETVAL, semun );
  434.       }
  435.    }
  436.    else
  437.    {
  438.       handle->sem_key = -1;
  439.       handle->sem_id = -1;
  440.    }
  441.    _unicap_acquire_cpi_lock( handle->sem_id );
  442.    status = handle->cpi.cpi_open( &handle->cpi_data, device );
  443.    if( !SUCCESS( status ) )
  444.    {
  445.       free( handle );
  446.       dlclose( dlhandle );
  447.       return status;
  448.    }
  449.    _unicap_release_cpi_lock( handle->sem_id );
  450.    handle->dlhandle = dlhandle;
  451.    memcpy( &handle->device, device, sizeof( unicap_device_t ) );
  452.    handle->ref_count = malloc( sizeof( int ) );
  453.    *(handle->ref_count) = 1;
  454.    *unicap_handle = handle;
  455.    if( handle->cpi.cpi_set_event_notify )
  456.    {
  457.       handle->cpi.cpi_set_event_notify( handle->cpi_data, unicap_event_callback, unicap_copy_handle( handle ) );
  458.    }
  459.    return STATUS_SUCCESS;
  460. }
  461. #else
  462. static unicap_status_t open_cpi( unicap_handle_t *unicap_handle, unicap_device_t *device )
  463. {
  464.    unicap_handle_t handle;
  465.    unicap_status_t status;
  466.    int cpi_count;
  467.    int idx_cpi;
  468.    int i;
  469.    TRACE( "open----------%sn", device->identifier );
  470.    initialize_static_cpis();
  471.    if( !device || !unicap_handle )
  472.    {
  473.       return STATUS_INVALID_PARAMETER;
  474.    }
  475.    *unicap_handle = NULL;
  476.    handle = malloc( sizeof( struct _unicap_handle ) );
  477.    if( !handle )
  478.    {
  479.       return STATUS_NO_MEM;
  480.    }
  481.    // initialize data structure
  482.    memset( handle, 0, sizeof( struct _unicap_handle ) );
  483.    handle->cb_info = malloc( sizeof( struct _unicap_callback_info ) * UNICAP_EVENT_LAST );
  484.    for( i = 0; i < UNICAP_EVENT_LAST; i++ )
  485.    {
  486.       handle->cb_info[ i ].func = NULL;
  487.       handle->cb_info[ i ].user_ptr = NULL;
  488.    }
  489.    sprintf( handle->device_uid, "%s", device->identifier );
  490.    sscanf( device->cpi_layer, "%d", &idx_cpi );
  491.    if( ( idx_cpi < 0 ) || ( idx_cpi > UNICAP_STATIC_CPI_COUNT ) )
  492.    {
  493.       free( handle );
  494.       return STATUS_INVALID_PARAMETER;
  495.    }
  496.    
  497.    memcpy( &handle->cpi, static_cpis_s[idx_cpi], sizeof( struct _unicap_cpi ) );
  498.    handle->sem_key = -1;
  499.    handle->sem_id = -1;
  500.    
  501.    status = handle->cpi.cpi_open( &handle->cpi_data, device );
  502.    if( !SUCCESS( status ) )
  503.    {
  504.       free( handle );
  505.       return status;
  506.    }
  507.    
  508.    handle->ref_count = malloc( sizeof( int ) );
  509.    *(handle->ref_count) = 1;
  510.    
  511.    *unicap_handle = handle;
  512.    
  513.    if( handle->cpi.cpi_set_event_notify )
  514.    {
  515.       handle->cpi.cpi_set_event_notify( handle->cpi_data, unicap_event_callback, unicap_copy_handle( handle ) );
  516.    }
  517.    return STATUS_SUCCESS;
  518. }
  519. #endif //ENABLE_STATIC_CPI
  520. unicap_status_t unicap_open( unicap_handle_t *unicap_handle, unicap_device_t *device )
  521. {
  522.    unicap_status_t status = open_cpi( unicap_handle, device );
  523.    return status;
  524. }
  525. void unicap_cpi_register_event_notification( void* _func,
  526.      void *data, unicap_handle_t handle )
  527. {
  528.    cpi_set_event_notify_t func = (cpi_set_event_notify_t)_func;
  529.    
  530.    func( data, unicap_event_callback, unicap_clone_handle( handle ) );
  531. }
  532. /*
  533.   Create a new instance of an unicap handle and increase ref count. 
  534.   Input: handle
  535.   Output: A copy of handle; ref count increased
  536. */
  537. unicap_handle_t unicap_clone_handle( unicap_handle_t handle )
  538. {
  539.    unicap_handle_t cloned_handle;
  540.    if( !handle )
  541.    {
  542.       return NULL;
  543.    }
  544.    cloned_handle = malloc( sizeof( struct _unicap_handle ) );
  545.    if( !cloned_handle )
  546.    {
  547.       return NULL;
  548.    }
  549.    memcpy( cloned_handle, handle, sizeof( struct _unicap_handle ) );
  550.    *(handle->ref_count) = *(handle->ref_count) + 1;
  551.    return cloned_handle;
  552. }
  553. /**
  554.  * Create a new unicap_handle instance WITHOUT incrementing refcount
  555.  * @handle: handle to copy
  556.  *
  557.  * Returns: copy of handle
  558.  */
  559. static unicap_handle_t unicap_copy_handle( unicap_handle_t handle )
  560. {
  561.    unicap_handle_t cloned_handle;
  562.    if( !handle )
  563.    {
  564.       return NULL;
  565.    }
  566.    cloned_handle = malloc( sizeof( struct _unicap_handle ) );
  567.    if( !cloned_handle )
  568.    {
  569.       return NULL;
  570.    }
  571.    memcpy( cloned_handle, handle, sizeof( struct _unicap_handle ) );
  572.    
  573.    return cloned_handle;
  574. }
  575. unicap_status_t unicap_close( unicap_handle_t handle )
  576. {
  577.    if( *(handle->ref_count) == 0 )
  578.    {
  579.       TRACE( "Tried to close a handle with ref_count == 0!n" );
  580.       return STATUS_FAILURE;
  581.    }
  582.    *(handle->ref_count) = *(handle->ref_count) - 1;
  583.    TRACE( "close: new refcount = %dn", *(handle->ref_count ) );
  584.    if( *(handle->ref_count) == 0 )
  585.    {
  586.       unicap_unlock_properties( handle );
  587.       unicap_unlock_stream( handle );
  588.       // free resources
  589.       _unicap_acquire_cpi_lock( handle->sem_id );
  590.       handle->cpi.cpi_capture_stop( handle->cpi_data );
  591.       handle->cpi.cpi_close( handle->cpi_data );
  592.       if( handle->dlhandle )
  593.       {
  594.  dlclose( handle->dlhandle );
  595.       }
  596.       _unicap_release_cpi_lock( handle->sem_id );
  597.       free( handle->ref_count );
  598.    }
  599.    free( handle );
  600.    return STATUS_SUCCESS;
  601. }
  602. unicap_status_t unicap_get_device( unicap_handle_t handle, unicap_device_t *device )
  603. {
  604.    if( !handle || !device )
  605.    {
  606.       return STATUS_INVALID_PARAMETER;
  607.    }
  608.    memcpy( device, &handle->device, sizeof( unicap_device_t ) );
  609.    return STATUS_SUCCESS;
  610. }
  611. unicap_status_t unicap_reenumerate_formats( unicap_handle_t handle, int *count )
  612. {
  613.    unicap_status_t status;
  614.    status = handle->cpi.cpi_reenumerate_formats( handle->cpi_data, count );
  615.    return status;
  616. }
  617. unicap_status_t unicap_enumerate_formats( unicap_handle_t handle, 
  618.   unicap_format_t *specifier, 
  619.   unicap_format_t *format, 
  620.   int index )
  621. {
  622.    int current_index = -1;
  623.    int tmp_index = 0;
  624.    unicap_status_t status;
  625.    if( !handle )
  626.    {
  627.       TRACE( "handle is NULLn" );
  628.       return STATUS_INVALID_PARAMETER;
  629.    }
  630.    TRACE( "unicap_enumerate_formats, index: %dn", index );
  631.    _unicap_acquire_cpi_lock( handle->sem_id );
  632.    while( ( current_index != index ) && 
  633.   ( ( status = handle->cpi.cpi_enumerate_formats( handle->cpi_data, format, tmp_index ) ) 
  634.     == STATUS_SUCCESS ) )
  635.    {
  636.       if( _check_format_match( specifier, format ) )
  637.       {
  638.  current_index++;
  639.       }
  640.       tmp_index++;
  641.    }
  642.    _unicap_release_cpi_lock( handle->sem_id );
  643.    return status;
  644. }
  645. unicap_status_t unicap_set_format( unicap_handle_t handle, 
  646.    unicap_format_t *format )
  647. {
  648.    unicap_status_t status;
  649.    if( !format )
  650.    {
  651.       return STATUS_INVALID_PARAMETER;
  652.    }
  653.    if( !strlen( format->identifier ) )
  654.    {
  655.       return STATUS_INVALID_PARAMETER;
  656.    }
  657.    _unicap_acquire_cpi_lock( handle->sem_id );
  658.    status = handle->cpi.cpi_set_format( handle->cpi_data, format );
  659.    _unicap_release_cpi_lock( handle->sem_id );
  660.    return status;
  661. }
  662. unicap_status_t unicap_get_format( unicap_handle_t handle, 
  663.    unicap_format_t *format )
  664. {
  665.    unicap_status_t status;
  666.    if( !format )
  667.    {
  668.       return STATUS_INVALID_PARAMETER;
  669.    }
  670.    _unicap_acquire_cpi_lock( handle->sem_id );
  671.    status = handle->cpi.cpi_get_format( handle->cpi_data, format );
  672.    _unicap_release_cpi_lock( handle->sem_id );
  673.    return status;
  674. }
  675. unicap_status_t unicap_reenumerate_properties( unicap_handle_t handle, int *_pcount )
  676. {
  677.    unicap_status_t status;
  678.    int count;
  679.    status = handle->cpi.cpi_reenumerate_properties( handle->cpi_data, &count );
  680.    if( _pcount )
  681.    {
  682.       *_pcount = count;
  683.    }
  684.    return status;
  685. }
  686. unicap_status_t unicap_enumerate_properties( unicap_handle_t handle, unicap_property_t *specifier, unicap_property_t *property, int index )
  687. {
  688.    int current_index = -1;
  689.    int tmp_index = 0;
  690.    unicap_status_t status;
  691.    if( !property || !handle || ( index < 0 ) )
  692.    {
  693.       return STATUS_INVALID_PARAMETER;
  694.    }
  695.    TRACE( "enumerate properties: %dn", index );
  696.    _unicap_acquire_cpi_lock( handle->sem_id );
  697.    while( ( current_index != index ) && 
  698.   ( ( status = handle->cpi.cpi_enumerate_properties( handle->cpi_data, property, tmp_index ) ) == STATUS_SUCCESS ) )
  699.    {
  700.       TRACE( "%s <> %s: %dn", specifier->identifier, property->identifier, _check_property_match( specifier, property ) );
  701.       if( _check_property_match( specifier, property ) )
  702.       {
  703.  current_index++;
  704.       }
  705.       tmp_index++;
  706.    }
  707.    _unicap_release_cpi_lock( handle->sem_id );
  708.    return status;
  709. }
  710. unicap_status_t unicap_set_property( unicap_handle_t handle, unicap_property_t *property )
  711. {
  712.    unicap_status_t status;
  713.    if( !handle || ! property )
  714.    {
  715.       TRACE( "invalid paramn" );
  716.       return STATUS_INVALID_PARAMETER;
  717.    }
  718.    _unicap_acquire_cpi_lock( handle->sem_id );
  719.    status = handle->cpi.cpi_set_property( handle->cpi_data, property );
  720.    _unicap_release_cpi_lock( handle->sem_id );
  721.    return status;
  722. }
  723. unicap_status_t unicap_get_property( unicap_handle_t handle, unicap_property_t *property )
  724. {
  725.    unicap_status_t status = STATUS_SUCCESS;
  726.    if( !handle || !property )
  727.    {
  728.       return STATUS_INVALID_PARAMETER;
  729.    }
  730.    _unicap_acquire_cpi_lock( handle->sem_id );
  731.    status = handle->cpi.cpi_get_property( handle->cpi_data, property );
  732.    _unicap_release_cpi_lock( handle->sem_id );
  733.    return status;
  734. }
  735. unicap_status_t unicap_start_capture( unicap_handle_t handle )
  736. {
  737.    unicap_status_t status = STATUS_SUCCESS;
  738.    if( !handle )
  739.    {
  740.       TRACE( "Invalid parametern" );
  741.       return STATUS_INVALID_PARAMETER;
  742.    }
  743.    if( !handle->have_stream_lock )
  744.    {
  745.       status = unicap_lock_stream( handle );
  746.       if( SUCCESS( status ) )
  747.       {
  748.  handle->temporary_stream_lock = 1;
  749.       }
  750.    }
  751.    if( SUCCESS( status ) )
  752.    {
  753.       TRACE( "Capture start...n" );
  754.       _unicap_acquire_cpi_lock( handle->sem_id );
  755.       status = handle->cpi.cpi_capture_start( handle->cpi_data );
  756.       _unicap_release_cpi_lock( handle->sem_id );
  757.    }
  758.    else
  759.    {
  760.       TRACE( "FAILED TO GET STREAM LOCKnnnnnn" );
  761.    }
  762.    return status;
  763. }
  764. unicap_status_t unicap_stop_capture( unicap_handle_t handle )
  765. {
  766.    unicap_status_t status = STATUS_SUCCESS;
  767.    if( !handle )
  768.    {
  769.       return STATUS_INVALID_PARAMETER;
  770.    }
  771.    if( !handle->have_stream_lock )
  772.    {
  773.       status = STATUS_PERMISSION_DENIED;
  774.    }
  775.    else
  776.    {
  777.       if( handle->temporary_stream_lock )
  778.       {
  779.  handle->temporary_stream_lock = 0;
  780.  unicap_unlock_stream( handle );
  781.       }
  782.       _unicap_acquire_cpi_lock( handle->sem_id );
  783.       status = handle->cpi.cpi_capture_stop( handle->cpi_data );
  784.       _unicap_release_cpi_lock( handle->sem_id );
  785.    }
  786.    return status;
  787. }
  788. unicap_status_t unicap_queue_buffer( unicap_handle_t handle, unicap_data_buffer_t *buffer )
  789. {
  790.    unicap_status_t status = STATUS_SUCCESS;
  791.    if( !handle || !buffer )
  792.    {
  793.       TRACE( "Invalid parametern" );
  794.       return STATUS_INVALID_PARAMETER;
  795.    }
  796.    if( !handle->have_stream_lock )
  797.    {
  798.       status = STATUS_PERMISSION_DENIED;
  799.    }
  800.    else
  801.    {
  802.       _unicap_acquire_cpi_lock( handle->sem_id );
  803.       status = handle->cpi.cpi_queue_buffer( handle->cpi_data, buffer );
  804.       _unicap_release_cpi_lock( handle->sem_id );
  805.    }
  806.    return status;
  807. }
  808. unicap_status_t unicap_dequeue_buffer( unicap_handle_t handle, unicap_data_buffer_t **buffer )
  809. {
  810.    unicap_status_t status;
  811.    if( !handle || !buffer )
  812.    {
  813.       return STATUS_INVALID_PARAMETER;
  814.    }
  815.    if( !handle->have_stream_lock )
  816.    {
  817.       status = STATUS_PERMISSION_DENIED;
  818.    }
  819.    else
  820.    {
  821.       _unicap_acquire_cpi_lock( handle->sem_id );
  822.       status = handle->cpi.cpi_dequeue_buffer( handle->cpi_data, buffer );
  823.       _unicap_release_cpi_lock( handle->sem_id );
  824.    }
  825.    return status;
  826. }
  827. unicap_status_t unicap_wait_buffer( unicap_handle_t handle, unicap_data_buffer_t **buffer )
  828. {
  829.    unicap_status_t status = STATUS_SUCCESS;
  830.    if( !handle || !buffer )
  831.    {
  832.       TRACE( "!handle || !buffern" );
  833.       return STATUS_INVALID_PARAMETER;
  834.    }
  835.    if( !handle->have_stream_lock )
  836.    {
  837.       status = STATUS_PERMISSION_DENIED;
  838.    }
  839.    else
  840.    {
  841.       _unicap_acquire_cpi_lock( handle->sem_id );
  842.       status = handle->cpi.cpi_wait_buffer( handle->cpi_data, buffer );
  843.       _unicap_release_cpi_lock( handle->sem_id );
  844.    }
  845.    return status;
  846. }
  847. unicap_status_t unicap_poll_buffer( unicap_handle_t handle, int *count )
  848. {
  849.    unicap_status_t status = STATUS_SUCCESS;
  850.    if( !handle || !count )
  851.    {
  852.       return STATUS_INVALID_PARAMETER;
  853.    }
  854.    _unicap_acquire_cpi_lock( handle->sem_id );
  855.    status = handle->cpi.cpi_poll_buffer( handle->cpi_data, count );
  856.    _unicap_release_cpi_lock( handle->sem_id );
  857.    return status;
  858. }
  859. static key_t uidtok( char *string )
  860. {
  861.    int i;
  862.    key_t key = 0x00345678;
  863.    for( i = 0; string[i] != 0; i++ )
  864.    {
  865.       key = key ^ ( string[i] << ( i%3 ) );
  866.    }
  867.    return key;
  868. }
  869. int unicap_is_stream_locked( unicap_device_t *device )
  870. {
  871.    key_t key;
  872.    int sem_id;
  873.    int val;
  874. #ifndef UNICAP_THREAD_LOCKING
  875.    return 0;
  876. #endif
  877.    key = uidtok( device->identifier );
  878.    sem_id = semget( key, 1, S_IRWXU | S_IRWXG | S_IRWXO );
  879.    if( sem_id == -1 )
  880.    {
  881.       return 0;
  882.    }
  883.    val = semctl( sem_id, 0, GETVAL );
  884.    TRACE( "STREAM IS LOCKED >>>> %d (%d) key + %dn", val == 0, val, key );
  885.    return val == 0;
  886. }
  887. unicap_status_t unicap_lock_stream( unicap_handle_t handle )
  888. {
  889.    unicap_status_t status = STATUS_SUCCESS;
  890.    key_t key;
  891.    int sem_id;
  892.    
  893. #ifndef UNICAP_THREAD_LOCKING
  894.    handle->have_stream_lock = 1;
  895.    return STATUS_SUCCESS;
  896. #endif
  897.    key = uidtok( handle->device_uid );
  898.    if( !handle->have_stream_lock )
  899.    {
  900.       struct semid_ds semds;
  901.       union semun_linux semun;
  902.       sem_id = semget( key, 1, IPC_CREAT | S_IRWXU | S_IRWXG | S_IRWXO);
  903.       if( sem_id == -1 )
  904.       {
  905.  return STATUS_FAILURE;
  906.       }
  907.       // check if the semaphore is used the first time -> initialize it
  908.       semun.buf = &semds;
  909.       semds.sem_otime = 0;
  910.       semctl( sem_id, 0, IPC_STAT, semun );
  911.       if( semds.sem_otime == 0 )
  912.       {
  913.  struct sembuf sops;
  914.  semun.val = 1;
  915.  semctl( sem_id, 0, SETVAL, semun );
  916.  sops.sem_num = 0;
  917.  sops.sem_op = -1;
  918.  sops.sem_flg = SEM_UNDO|IPC_NOWAIT;
  919.  _unicap_acquire_cpi_lock( handle->sem_id );
  920.  if( semop( sem_id, &sops, 1 ) < 0 )
  921.  {
  922.     status = STATUS_PERMISSION_DENIED;
  923.  }
  924.  else
  925.  {
  926.     handle->stream_sem_id = sem_id;
  927.     handle->have_stream_lock = 1;
  928.  }
  929.  _unicap_release_cpi_lock( handle->sem_id );
  930.       }
  931.       else
  932.       {
  933.  struct sembuf sops;
  934.  sops.sem_num = 0;
  935.  sops.sem_op = -1;
  936.  sops.sem_flg = SEM_UNDO|IPC_NOWAIT;
  937.  _unicap_acquire_cpi_lock( handle->sem_id );
  938.  if( semop( sem_id, &sops, 1 ) < 0 )
  939.  {
  940.     status = STATUS_PERMISSION_DENIED;
  941.  }
  942.  else
  943.  {
  944.     handle->stream_sem_id = sem_id;
  945.     handle->have_stream_lock = 1;
  946.  }
  947.  _unicap_release_cpi_lock( handle->sem_id );
  948.       }
  949.    }
  950.    TRACE( "LOCK STREAM >>>> %d key = %dn", handle->have_stream_lock, key );
  951.    return status;
  952. }
  953. unicap_status_t unicap_unlock_stream( unicap_handle_t handle )
  954. {
  955.    unicap_status_t status = STATUS_SUCCESS;
  956. #ifndef UNICAP_THREAD_LOCKING
  957.    handle->have_stream_lock = 0;
  958.    return STATUS_SUCCESS;
  959. #endif
  960.    if( handle->have_stream_lock )
  961.    {
  962.       struct sembuf sops;
  963.       sops.sem_num = 0;
  964.       sops.sem_op = 1;
  965.       sops.sem_flg = SEM_UNDO;
  966.       if( semop( handle->stream_sem_id, &sops, 1 ) < 0 )
  967.       {
  968.  status = STATUS_FAILURE;
  969.       }
  970.       else
  971.       {
  972.  handle->have_stream_lock = 0;
  973.       }
  974.    }
  975.    else
  976.    {
  977.       status = STATUS_PERMISSION_DENIED;
  978.    }
  979.    TRACE( "UNLOCK STREAM >>>> %dn", handle->have_stream_lock );
  980.    return status;
  981. }
  982. unicap_status_t unicap_lock_properties( unicap_handle_t handle )
  983. {
  984.    unicap_status_t status = STATUS_FAILURE;
  985.    return status;
  986. }
  987. unicap_status_t unicap_unlock_properties( unicap_handle_t handle )
  988. {
  989.    unicap_status_t status = STATUS_SUCCESS;
  990.    return status;
  991. }
  992. unicap_status_t unicap_register_callback( unicap_handle_t handle, 
  993.   unicap_event_t event, 
  994.   unicap_callback_t func, 
  995.   void *user_ptr )
  996. {
  997.    unicap_status_t status = STATUS_FAILURE;
  998.    if( ( event < UNICAP_EVENT_FIRST ) || 
  999.        ( event >= UNICAP_EVENT_LAST ) )
  1000.    {
  1001.       return STATUS_INVALID_PARAMETER;
  1002.    }
  1003.    _unicap_acquire_cpi_lock( handle->sem_id );
  1004.    if( handle->cb_info[event].func != NULL )
  1005.    {
  1006.       status = STATUS_FAILURE;
  1007.    }
  1008.    else
  1009.    {
  1010.       handle->cb_info[event].func = func;
  1011.       handle->cb_info[event].user_ptr = user_ptr;
  1012.       status = STATUS_SUCCESS;
  1013.    }
  1014.    _unicap_release_cpi_lock( handle->sem_id );
  1015.    return status;
  1016. }
  1017. unicap_status_t unicap_unregister_callback( unicap_handle_t handle, 
  1018.     unicap_event_t event, 
  1019.     unicap_callback_t func, 
  1020.     void *user_ptr )
  1021. {
  1022.    unicap_status_t status = STATUS_FAILURE;
  1023.    if( ( event < UNICAP_EVENT_FIRST ) || 
  1024.        ( event >= UNICAP_EVENT_LAST ) )
  1025.    {
  1026.       return STATUS_INVALID_PARAMETER;
  1027.    }
  1028.    _unicap_acquire_cpi_lock( handle->sem_id );
  1029.    if( handle->cb_info[event].func == NULL )
  1030.    {
  1031.       status = STATUS_FAILURE;
  1032.    }
  1033.    else
  1034.    {
  1035.       handle->cb_info[event].func = NULL;
  1036.       handle->cb_info[event].user_ptr = NULL;
  1037.       status = STATUS_SUCCESS;
  1038.    }
  1039.    _unicap_release_cpi_lock( handle->sem_id );
  1040.    return status;
  1041. }