Beispiel #1
0
/* ----------------------------------------------------------------------
 * initialise host-side OpenMAX IL component service
 * -------------------------------------------------------------------- */
void
vc_vchi_ilcs_init( VCHI_INSTANCE_T initialise_instance,
                   VCHI_CONNECTION_T **connections,
                   uint32_t num_connections )
{
   int32_t success;

   SERVICE_CREATION_T parameters = { MAKE_FOURCC("ILCS"),   // 4cc service code
                                     connections[0],        // passed in fn ptrs
                                     0,                     // tx fifo size (unused)
                                     0,                     // tx fifo size (unused)
                                     0,                     // service callback
                                     0 };                   // callback parameter

   memset( &vc_ilcsg, 0, sizeof(VC_ILCS_GLOBALS_T) );

   // create thread semaphore for blocking
   os_semaphore_create( &vc_ilcsg.component_lock, OS_SEMAPHORE_TYPE_SUSPEND );

   // create semaphore for protecting wait/xid structures
   os_semaphore_create( &vc_ilcsg.wait_sem, OS_SEMAPHORE_TYPE_SUSPEND );
   
   // create semaphore for correct ordering of control+bulk pairs
   os_semaphore_create( &vc_ilcsg.send_sem, OS_SEMAPHORE_TYPE_SUSPEND );

   // open 'ILCS' service
   success = vchi_service_open( initialise_instance, &parameters, &vc_ilcsg.vchi_handle );
   vc_assert( success == 0 );

   success = os_thread_start( &vc_ilcsg.thread, vc_ilcs_task, NULL, 4000, "ILCS_HOST" );
   vc_assert( success == 0 );
}
void vc_vchi_gencmd_init (VCHI_INSTANCE_T initialise_instance, VCHI_CONNECTION_T **connections, uint32_t num_connections ) {
   int32_t success;
   int i;

   // record the number of connections
   memset( &gencmd_client, 0, sizeof(GENCMD_SERVICE_T) );
   gencmd_client.num_connections = (int) num_connections;
   success = os_semaphore_create( &gencmd_client.sema, OS_SEMAPHORE_TYPE_SUSPEND );
   assert( success == 0 );
   success = os_semaphore_create( &gencmd_message_available_semaphore, OS_SEMAPHORE_TYPE_BUSY_WAIT );
   assert( success == 0 );
   success = os_semaphore_obtain( &gencmd_message_available_semaphore );
   assert( success == 0 );

   for (i=0; i<gencmd_client.num_connections; i++) {

      // Create a 'LONG' service on the each of the connections
      SERVICE_CREATION_T gencmd_parameters = { MAKE_FOURCC("GCMD"),      // 4cc service code
                                               connections[i],           // passed in fn ptrs
                                               0,                        // tx fifo size (unused)
                                               0,                        // tx fifo size (unused)
                                               &gencmd_callback,         // service callback
                                               &gencmd_message_available_semaphore, // callback parameter
                                               VC_FALSE,                 // want_unaligned_bulk_rx
                                               VC_FALSE,                 // want_unaligned_bulk_tx
                                               VC_FALSE                  // want_crc
                                               };

      success = vchi_service_open( initialise_instance, &gencmd_parameters, &gencmd_client.open_handle[i] );
      assert( success == 0 );
   }

}
Beispiel #3
0
/***********************************************************
 * Name: software_fifo_create
 *
 * Arguments: const uint32_t size            - size of FIFO (in bytes)
 *            int alignment                  - required alignment (bytes)
 *            SOFTWARE_FIFO_HANDLE_T *handle - handle to this FIFO
 *
 * Description: Allocates space for a FIFO and initialises it
 *
 * Returns: 0 if successful, any other value is failure
 *
 ***********************************************************/
int32_t software_fifo_create( const uint32_t size, int alignment, SOFTWARE_FIFO_HANDLE_T *handle )
{
int32_t success = -1;

   // check that the alignment is a power of 2 or 0
   os_assert((OS_COUNT(alignment) == 1) || (alignment == 0));

   // put the alignment into a form we can use (must be power of 2)
   alignment = alignment ? alignment-1 : 0;

   // check we have a valid pointer
   if(handle)
   {
      memset(handle,0,sizeof(SOFTWARE_FIFO_HANDLE_T));
      // allocate slightly more space than we need so that we can get the required alignment
      handle->malloc_address = (uint8_t *)os_malloc(size+alignment, OS_ALIGN_DEFAULT, "");
      if(handle->malloc_address)
      {
         handle->base_address = (uint8_t *)(((uint32_t)handle->malloc_address + alignment) & ~alignment);
         handle->read_ptr = handle->base_address;
         handle->write_ptr = handle->base_address;
         handle->size = size;
         handle->bytes_read = 0;
         handle->bytes_written = 0;
         success = os_semaphore_create(&handle->software_fifo_semaphore,OS_SEMAPHORE_TYPE_SUSPEND);
         // oops, unable to create the semaphore
         os_assert(success == 0);
      }
   }

   // oops, looks like you've run out of memory
   os_assert(success == 0);
   return(success);
}
Beispiel #4
0
/* ----------------------------------------------------------------------
 * initialise host-side OpenMAX IL component service
 * -------------------------------------------------------------------- */
void
vc_vchi_ilcs_init( VCHI_INSTANCE_T initialise_instance,
                   VCHI_CONNECTION_T **connections,
                   uint32_t num_connections )
{
   int32_t success;

   memset( &vc_ilcsg, 0, sizeof(VC_ILCS_GLOBALS_T) );

   // 
   sema_init(&vc_ilcsg.msg_prod, 0);
   sema_init(&vc_ilcsg.msg_cons, 1);
   sema_init(&vc_ilcsg.omxlog_lock, 1);
   vc_ilcsg.omxlog_rindex = 0;
   vc_ilcsg.omxlog_windex = 0;
   vc_ilcsg.omxlog = vmalloc(VC03_OMXLOG_MAX);
   memset(vc_ilcsg.omxlog, 0, VC03_OMXLOG_MAX);

   // create thread semaphore for blocking
   os_semaphore_create( &vc_ilcsg.component_lock, OS_SEMAPHORE_TYPE_SUSPEND );
   os_semaphore_create( &vc_ilcsg.rxmsg_sem, OS_SEMAPHORE_TYPE_SUSPEND );
   os_semaphore_obtain( &vc_ilcsg.rxmsg_sem );

   // create semaphore for protecting wait/xid structures
   os_semaphore_create( &vc_ilcsg.wait_sem, OS_SEMAPHORE_TYPE_SUSPEND );

   // open 'ILCS' service
   SERVICE_CREATION_T parameters = { MAKE_FOURCC("ILCS"),   // 4cc service code
                                     connections[0],        // passed in fn ptrs
                                     0,                     // tx fifo size (unused)
                                     0,                     // tx fifo size (unused)
                                     &vc_ilcs_callback,     // service callback
                                     &vc_ilcsg.rxmsg_sem }; // callback parameter

   success = vchi_service_open( initialise_instance, &parameters, &vc_ilcsg.vchi_handle );
   assert( success == 0 );

   success = os_thread_start( &vc_ilcsg.thread, vc_ilcs_task, NULL, 4000, "ILCS_HOST" );
   assert( success == 0 );
}
void vc_vchi_hostreq_init (VCHI_INSTANCE_T initialise_instance, VCHI_CONNECTION_T **connections, uint32_t num_connections ) {
   int success, i;

   // record the number of connections
   memset( &hostreq_client, 0, sizeof(HOSTREQ_SERVICE_T) );
   hostreq_client.num_connections = num_connections;
   success = os_semaphore_create( &hostreq_client.sema, OS_SEMAPHORE_TYPE_SUSPEND );
   assert( success == 0 );
   success = os_semaphore_create( &hostreq_client_message_available, OS_SEMAPHORE_TYPE_BUSY_WAIT );
   assert( success == 0 );
   success = os_semaphore_obtain(&hostreq_client_message_available);
   assert( success == 0 );

   for (i=0; i<hostreq_client.num_connections; i++) {

      // Create a 'Client' service on the each of the connections
      SERVICE_CREATION_T hostreq_parameters = { HOSTREQ_NAME,     // 4cc service code
                                                connections[i],           // passed in fn ptrs
                                                0,                        // tx fifo size (unused)
                                                0,                        // tx fifo size (unused)
                                                &hostreq_client_callback, // service callback
                                                &hostreq_client_message_available }; // callback parameter

      success = vchi_service_open( initialise_instance, &hostreq_parameters, &hostreq_client.client_handle[i] );
      assert( success == 0 );


   }

   success = os_thread_start(&hostreq_client_task, &hostreqclient_func, NULL, 2048, "HOSTREQ task");
   assert(!success);
   if(!success) {
      hostreq_client.initialised = 1;
      //Send a time across immediately
      time_t dummytime = 0; //We need to get the real time on a real host
      success = hostreq_send_command(VC_HOSTREQ_TIME, &dummytime, sizeof(dummytime));
      assert( success == 0 );
   }
}
void miio_app_thread(void* arg)
{
    static bool has_sync_time = false;
    g_mum = mum_create();

//*****************************button init*******************************/
    os_timer_create(&g_reset_prov_timer, "reset-prov-timer", os_msec_to_ticks(4000), reset_prov, NULL,
            OS_TIMER_ONE_SHOT, OS_TIMER_NO_ACTIVATE);

    button_frame_work_init();
    register_button_callback(0, button_1_press_handle);

    if (WM_SUCCESS != os_semaphore_create(&btn_pressed_sem, "btn_pressed_sem")) {
        LOG_ERROR("btn_pressed_sem creation failed\r\n");
    }
    else if (WM_SUCCESS != os_semaphore_get(&btn_pressed_sem, OS_WAIT_FOREVER)) {
        LOG_ERROR("first get btn_pressed_sem failed.\r\n");
    }
//******************************button init end*******************************************/

    local_timer_init();//add by [email protected]

    miio_led_on();
    LOG_INFO("miio_app_thread while loop start.\r\n");

#ifdef MIIO_COMMANDS_DEBUG
    while(!ot_api_is_online())api_os_tick_sleep(100);
    uart_wifi_debug_init();
#endif
    while (1) {
        if (WM_SUCCESS == os_semaphore_get(&btn_pressed_sem, OS_NO_WAIT)) {
                mum_set_property(g_mum,"button_pressed","\"wifi_rst\"");
        }

        if(has_sync_time)//only after sync time, we start check timer
            check_schedule_and_set_timer();
        else if(otn_is_online())
            has_sync_time = true;

        os_thread_sleep(os_msec_to_ticks(PERIOD_CHECK_BUTTON));
    }

    local_timer_deinit();//add by [email protected]

//*****************************button deinit*******************************/
    mum_destroy(&g_mum);
    os_timer_delete(&g_reset_prov_timer);
    os_semaphore_delete(&btn_pressed_sem);
//******************************button deinit end*******************************************/
}
Beispiel #7
0
/***********************************************************
 * Name: os_init
 *
 * Arguments: void
 *
 * Description: Routine to init the local OS stack - called from vchi_init
 *
 * Returns: int32_t - success == 0
 *
 ***********************************************************/
int32_t os_init( void )
{
   int success;

   vcos_init();
   os_cond_init();


   os_assert(!vcos_os_inited++);   /* should only be called once now */
   success = os_semaphore_create(&os_mutex_global, OS_SEMAPHORE_TYPE_SUSPEND);
   os_assert(success == 0);

   return success;
}
/* ----------------------------------------------------------------------
 * allocate space for a new non-wrap fifo, and return pointer to
 * opaque handle.  returns NULL on failure
 * -------------------------------------------------------------------- */
VCHI_NWFIFO_T *
non_wrap_fifo_create( const char *name, const uint32_t size, int alignment, int no_of_slots )
{
   int32_t success = -1;
   NON_WRAP_FIFO_HANDLE_T *fifo;

   // check that the alignment is a power of 2 or 0
#ifndef WIN32
   os_assert((OS_COUNT(alignment) == 1) || (alignment == 0));
#endif

   // put the alignment into a form we can use (must be power of 2)
   alignment = alignment ? alignment - 1 : 0;

   // create new non-wrap fifo struct
   fifo = (NON_WRAP_FIFO_HANDLE_T *)os_malloc( sizeof(NON_WRAP_FIFO_HANDLE_T), OS_ALIGN_DEFAULT, "" );
   os_assert( fifo );
   if (!fifo) return NULL;
   
   memset( fifo, 0, sizeof(NON_WRAP_FIFO_HANDLE_T) );
   fifo->name = name;

   // allocate slightly more space than we need so that we can get the required alignment
   fifo->malloc_address = (uint8_t *)os_malloc(size+alignment, OS_ALIGN_DEFAULT, "");
   if ( fifo->malloc_address ) {
      fifo->base_address = (uint8_t *)(((size_t)fifo->malloc_address + alignment) & ~alignment);
      fifo->read_ptr = fifo->base_address;
      fifo->write_ptr = fifo->base_address;
      // now allocate the space for the slot_info structures
      fifo->slot_info = (NON_WRAP_SLOT_T *)os_malloc(no_of_slots*sizeof(NON_WRAP_SLOT_T), OS_ALIGN_DEFAULT, "");
      memset( fifo->slot_info, 0, no_of_slots * sizeof(NON_WRAP_SLOT_T) );
      fifo->size = size;
      fifo->num_of_slots = no_of_slots;
      success = os_semaphore_create( &fifo->sem, OS_SEMAPHORE_TYPE_SUSPEND );
      os_assert(success == 0);
      success = os_cond_create( &fifo->space_available_cond, &fifo->sem );
      os_assert(success == 0);
   }
   else {
      os_free(fifo);
      fifo = NULL;
   }

   return (VCHI_NWFIFO_T *)fifo;
}
Beispiel #9
0
void ThreadCheck()
{
   VCOS_THREAD_T thread;

   // First create a sync semaphore   
   TEST_OK("os_semaphore_create", os_semaphore_create(&sem1, OS_SEMAPHORE_TYPE_SUSPEND));

   // and grab it   
   TEST_OK("os_semaphore_obtain", os_semaphore_obtain(&sem1));
   
   // Start the thread which shuold stall on the semaphore
   TEST_OK("os_thread_start", os_thread_start( &thread, &ThreadOne, NULL, 1000, "ThreadOne"));

   // Wait for thread to start for 1000 - should stall on semaphore and not change flag
   TEST_OK("os_delay", os_delay(1000));

   // Check global data is unchanged
   TEST_OK("Flag = 0", flag);

   // release semaphore
   TEST_OK("os_semaphore_release", os_semaphore_release(&sem1));
   
   // Wait for thread to continue for 100 - should be enough for it to set the flag

   TEST_OK("os_delay", os_delay(100));

   // Check global data is changed to non-zero
   TEST_OK("Flag = 1", (flag == 0));
   
   // Semaphore is currently released, so check the obtained function is correct.
   TEST_OK("os_semaphore_obtained - 0", os_semaphore_obtained(&sem1))
   
   // now get the sema and test again
   TEST_OK("os_semaphore_obtain", os_semaphore_obtain(&sem1));
   
   TEST_OK("os_semaphore_obtained - 1", (os_semaphore_obtained(&sem1) == 0))
   
   TEST_OK("os_semaphore_release", os_semaphore_release(&sem1));
}
/***********************************************************
 * Name: vchi_control_service_init
 *
 * Arguments:  VCHI_CONNECTION_T *connections,
 *             const uint32_t num_connections
 *
 * Description: Routine to init the control service
 *
 * Returns: int32_t - success == 0
 *
 ***********************************************************/
int32_t vchi_control_service_init( VCHI_CONNECTION_T **connections,
                                   const uint32_t num_connections,
                                   void **state )
{
   int32_t success = 0;
   uint32_t count = 0;
   CONTROL_SERVICE_INFO_T *control_info = (CONTROL_SERVICE_INFO_T *)*state;

   os_assert(num_connections <= VCHI_MAX_NUM_CONNECTIONS);

   if (!control_info)
   {
      control_info = (CONTROL_SERVICE_INFO_T *)os_malloc( VCHI_MAX_NUM_CONNECTIONS * sizeof(CONTROL_SERVICE_INFO_T), 0, "vchi:control_info" );
      memset( control_info, 0,VCHI_MAX_NUM_CONNECTIONS * sizeof(CONTROL_SERVICE_INFO_T) );

      for( count = 0; count < num_connections; count++ )
      {
#ifdef VCHI_COARSE_LOCKING
         os_semaphore_obtain(&connections[count]->sem);
#endif
         // create and obtain the semaphore used to signal when we have connected
         success += os_semaphore_create( &control_info[count].connected_semaphore, OS_SEMAPHORE_TYPE_BUSY_WAIT );
         os_assert( success == 0 );

         // record the connection info
         control_info[count].connection = connections[count];
         // create the server (this is a misnomer as the the CTRL service acts as both client and server
         success += (connections[count])->api->service_connect((connections[count])->state,MAKE_FOURCC("CTRL"),0,0,VC_TRUE,control_callback,&control_info[count],VC_FALSE,VC_FALSE,VC_FALSE,&control_info[count].open_handle);
         os_assert(success == 0);
#ifdef VCHI_COARSE_LOCKING
         os_semaphore_release(&connections[count]->sem);
#endif
      }
      // start timestamps from zero
      time_offset = 0;
      time_offset -= vchi_control_get_time();
   }
   else
   {
      for ( count = 0; count < num_connections; count++ )
      {
         os_assert(control_info[count].connection == connections[count]);
      }
   }

   // because we can have both ends of a connection running on one processor we need to send down the CONNECTION command after all
   // the connections have been connected
   for( count = 0; count < num_connections; count++ )
   {
#ifdef VCHI_COARSE_LOCKING
      os_semaphore_obtain(&connections[count]->sem);
#endif
      // record that we have not yet handled an INIT request
      control_info[count].initialised = VC_FALSE;
      success = os_semaphore_obtain( &control_info[count].connected_semaphore );
      os_assert( success == 0 );
      success = vchi_control_queue_connect( &control_info[count], VC_FALSE );
      os_assert(success == 0);
#ifdef VCHI_COARSE_LOCKING
      os_semaphore_release(&connections[count]->sem);
#endif
   }
   // now we must wait for the connections to have their INIT returned
   for( count = 0; count < num_connections; count++ )
   {
      success = os_semaphore_obtain( &control_info[count].connected_semaphore );
      os_assert( success == 0 );
      success = os_semaphore_release( &control_info[count].connected_semaphore );
      os_assert( success == 0 );
   }
   *state = control_info;
   return success;
}
Beispiel #11
0
/* ----------------------------------------------------------------------
 * send a string to the host side IL component service.  if resp is NULL
 * then there is no response to this call, so we should not wait for one.
 *
 * returns response, written to 'resp' pointer
 * -------------------------------------------------------------------- */
void
vc_ilcs_execute_function( IL_FUNCTION_T func, void *data, int len, void *data2, int len2, void *resp, int resplen )
{
   VC_ILCS_WAIT_T *wait;
   int num;

   // the host MUST receive a response
   assert( resp );

   // need to atomically find free ->wait entry
   os_semaphore_obtain( &vc_ilcsg.wait_sem );

   for (;;) {
      num = 0;

      while( num < VC_ILCS_MAX_WAITING && vc_ilcsg.wait[num].resp )
         num++;

      if ( num < VC_ILCS_MAX_WAITING )
         break;

      assert( num < VC_ILCS_MAX_WAITING );
      // might be a fatal error if another thread is relying
      // on this call completing before it can complete
      // we'll pause until we can carry on and hope that's sufficient.
      os_semaphore_release( &vc_ilcsg.wait_sem );
      os_sleep( 10 ); // 10 msec
      os_semaphore_obtain( &vc_ilcsg.wait_sem );
   }
   wait = &vc_ilcsg.wait[num];

   wait->resp = resp;
   wait->xid = vc_ilcsg.next_xid++;
   os_semaphore_create( &wait->sem, OS_SEMAPHORE_TYPE_SUSPEND );
   os_semaphore_obtain( &wait->sem );

   // at this point, ->wait is exclusively ours ()
   os_semaphore_release( &vc_ilcsg.wait_sem );

   // write the command header.
   vc_ilcs_transmit( func, wait->xid, data, len, data2, len2 );

   if ( !os_thread_current(vc_ilcsg.thread) ) {

      os_semaphore_obtain( &wait->sem );

   } else {

      // we're the vcilcs task, so wait for, and handle, incoming
      // messages while we're not completed
      for (;;) {

         // wait->sem will not be released until we process the response message
         if ( vc_ilcs_process_message() == 0 ) {
            // there were no more messages in the fifo; need to wait
            os_semaphore_obtain( &vc_ilcsg.rxmsg_sem );
            continue;
         }

         // did the last message release wait->sem ?
         if ( !os_semaphore_obtained(&wait->sem) )
            break;
      }
   }

   // safe to do the following - the assignment of NULL is effectively atomic
   os_semaphore_destroy( &wait->sem );
   wait->resp = NULL;
}
Beispiel #12
0
/* ----------------------------------------------------------------------
 * send a string to the host side IL component service.  if resp is NULL
 * then there is no response to this call, so we should not wait for one.
 *
 * returns 0 on successful call made, -1 on failure to send call.
 * on success, the response is written to 'resp' pointer
 * -------------------------------------------------------------------- */
int vc_ilcs_execute_function( IL_FUNCTION_T func, void *data, int len, void *data2, int len2, void *bulk, int bulk_len, void *resp )
{
   VC_ILCS_WAIT_T *wait;
   int i, num;

   // the host MUST receive a response
   vc_assert( resp );

   // need to atomically find free ->wait entry
   os_semaphore_obtain( &vc_ilcsg.wait_sem );

   // we try a number of times then give up with an error message
   // rather than just deadlocking
   for (i=0; i<VC_ILCS_WAIT_TIMEOUT; i++) {
      num = 0;

      while( num < VC_ILCS_MAX_WAITING && vc_ilcsg.wait[num].resp )
         num++;

      if ( num < VC_ILCS_MAX_WAITING || i == VC_ILCS_WAIT_TIMEOUT-1)
         break;

      // might be a fatal error if another thread is relying
      // on this call completing before it can complete
      // we'll pause until we can carry on and hope that's sufficient.
      os_semaphore_release( &vc_ilcsg.wait_sem );
      os_sleep( 10 ); // 10 msec

      // if we're the vcilcs thread, then the waiters might need
      // us to handle their response, so try and clear those now
      if(os_thread_is_running(&vc_ilcsg.thread))
         while(vc_ilcs_process_message(0));

      os_logging_message( "%s: wait for sem", __FUNCTION__);
      os_semaphore_obtain( &vc_ilcsg.wait_sem );
   }

   if(num == VC_ILCS_MAX_WAITING)
   {
      // failed to send message.
      vc_assert(0);
      os_semaphore_release( &vc_ilcsg.wait_sem );
      return -1;
   }

   wait = &vc_ilcsg.wait[num];

   wait->resp = resp;
   wait->xid = vc_ilcsg.next_xid++;
   os_semaphore_create( &wait->sem, OS_SEMAPHORE_TYPE_SUSPEND );
   os_semaphore_obtain( &wait->sem );

   // at this point, ->wait is exclusively ours ()
   os_semaphore_release( &vc_ilcsg.wait_sem );

   if(bulk)
      os_semaphore_obtain( &vc_ilcsg.send_sem);

   // write the command header.
   vc_ilcs_transmit( func, wait->xid, data, len, data2, len2 );

   if(bulk)
   {
      int result;
      result = vchi_bulk_queue_transmit( vc_ilcsg.vchi_handle,                // call to VCHI
                                         bulk, bulk_len,
                                         VCHI_FLAGS_BLOCK_UNTIL_QUEUED,
                                         NULL );
      vc_assert(result == 0);
      os_semaphore_release( &vc_ilcsg.send_sem);
   }

   if ( !os_thread_is_running(&vc_ilcsg.thread) ) {

      os_semaphore_obtain( &wait->sem );

   } else {

      // we're the vcilcs task, so wait for, and handle, incoming
      // messages while we're not completed
      for (;;) {
         // wait->sem will not be released until we process the response message
         vc_ilcs_process_message(1);

         // did the last message release wait->sem ?
         if ( !os_semaphore_obtained(&wait->sem) )
            break;
      }
   }

   // safe to do the following - the assignment of NULL is effectively atomic
   os_semaphore_destroy( &wait->sem );
   wait->resp = NULL;
   return 0;
}
/******************************************************************************
NAME
   vc_vchi_cec_init

SYNOPSIS
  void vc_vchi_cec_init(VCHI_INSTANCE_T initialise_instance, VCHI_CONNECTION_T **connections, uint32_t num_connections )

FUNCTION
  Initialise the CEC service for use.  A negative return value
   indicates failure (which may mean it has not been started on VideoCore).

RETURNS
   int
******************************************************************************/
VCHPRE_ void VCHPOST_ vc_vchi_cec_init(VCHI_INSTANCE_T initialise_instance, VCHI_CONNECTION_T **connections, uint32_t num_connections ) {
   int32_t success = -1;
   uint32_t i;

   // record the number of connections
   memset( &cecservice_client, 0, sizeof(CECSERVICE_HOST_STATE_T) );
   cecservice_client.num_connections = num_connections;
   success = os_semaphore_create( &cecservice_client.sema, OS_SEMAPHORE_TYPE_SUSPEND );
   vcos_assert( success == 0 );
   success = os_semaphore_create( &cecservice_message_available_semaphore, OS_SEMAPHORE_TYPE_BUSY_WAIT );
   vcos_assert( success == 0 );
   success = os_semaphore_obtain( &cecservice_message_available_semaphore );
   vcos_assert( success == 0 );
   success = os_semaphore_create( &cecservice_notify_available_semaphore, OS_SEMAPHORE_TYPE_SUSPEND );
   vcos_assert( success == 0 );
   success = os_semaphore_obtain( &cecservice_notify_available_semaphore );
   vcos_assert( success == 0 );

   cecservice_client.topology = os_malloc(sizeof(VC_CEC_TOPOLOGY_T), 16, "CEC topology");
   vcos_assert(cecservice_client.topology);

   for (i=0; i < cecservice_client.num_connections; i++) {
   
      // Create a 'Client' service on the each of the connections
      SERVICE_CREATION_T cecservice_parameters = { CECSERVICE_CLIENT_NAME,     // 4cc service code
                                                   connections[i],             // passed in fn ptrs
                                                   0,                          // tx fifo size (unused)
                                                   0,                          // tx fifo size (unused)
                                                   &cecservice_client_callback,// service callback
                                                   &cecservice_message_available_semaphore,  // callback parameter
                                                   VC_FALSE,                   // want_unaligned_bulk_rx
                                                   VC_FALSE,                   // want_unaligned_bulk_tx
                                                   VC_FALSE,                   // want_crc
      };

      SERVICE_CREATION_T cecservice_parameters2 = { CECSERVICE_NOTIFY_NAME,    // 4cc service code
                                                    connections[i],            // passed in fn ptrs
                                                    0,                         // tx fifo size (unused)
                                                    0,                         // tx fifo size (unused)
                                                    &cecservice_notify_callback,// service callback
                                                    &cecservice_notify_available_semaphore,  // callback parameter
                                                    VC_FALSE,                  // want_unaligned_bulk_rx
                                                    VC_FALSE,                  // want_unaligned_bulk_tx
                                                    VC_FALSE,                  // want_crc
      };

      //Create the client to normal CEC service 
      success = vchi_service_open( initialise_instance, &cecservice_parameters, &cecservice_client.client_handle[i] );
      vcos_assert( success == 0 );

      //Create the client to the async CEC service (any CEC related notifications)
      success = vchi_service_open( initialise_instance, &cecservice_parameters2, &cecservice_client.notify_handle[i] );
      vcos_assert( success == 0 );

   }

   //Create the notifier task
   success = os_thread_start(&cecservice_notify_task, cecservice_notify_func, &cecservice_client, 2048, "CEC Notify");
   vcos_assert( success == 0 );

   cecservice_client.initialised = 1;
}