/***********************************************************
 * Name: bulk_aux_callback
 *
 * Arguments: void *callback_param
 *            const VCHI_CALLBACK_REASON_T reason
 *            void *handle
 *
 * Description: Handles callbacks for received messages
 *
 * Returns: -
 *
 ***********************************************************/
static void bulk_aux_callback( void *callback_param, //my service local param
                               const VCHI_CALLBACK_REASON_T reason,
                               void *handle )
{
BULK_AUX_SERVICE_INFO_T * service_info = (BULK_AUX_SERVICE_INFO_T *)callback_param;

   switch(reason)
   {
      case VCHI_CALLBACK_MSG_AVAILABLE:
#if defined VCHI_COARSE_LOCKING
         os_semaphore_obtain(&service_info->connection->sem);
#endif
         service_info->connection->api->bulk_aux_received(service_info->connection->state);
#if defined VCHI_COARSE_LOCKING
         os_semaphore_release(&service_info->connection->sem);
#endif
         break;
      case VCHI_CALLBACK_MSG_SENT:
#if defined VCHI_COARSE_LOCKING
         os_semaphore_obtain(&service_info->connection->sem);
#endif
         service_info->connection->api->bulk_aux_transmitted(service_info->connection->state, handle);
#if defined VCHI_COARSE_LOCKING
         os_semaphore_release(&service_info->connection->sem);
#endif
         break;
      case VCHI_CALLBACK_BULK_RECEIVED:
      case VCHI_CALLBACK_BULK_DATA_READ:
      case VCHI_CALLBACK_BULK_SENT:      // bulk auxiliary service doesn't use bulk transfers(!)
         os_assert(0);
         break;
   }
}
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 );
   }

}
/***********************************************************
 * Name: os_cond_signal
 *
 * Arguments:  OS_COND_T *cond
 *
 * Description: Routine to signal at least one thread
 *              waiting on a condition variable. The
 *              caller must say whether they have obtained
 *              the semaphore.
 *
 * Returns: int32_t - success == 0
 *
 ***********************************************************/
int32_t os_cond_signal( OS_COND_T *cond, bool_t sem_claimed )
{
   int32_t success = -1;
   
   if (cond)
   {
      COND_WAITER_T *w;
      
      // Ensure the condvar's semaphore is claimed for thread-safe access
      if (!sem_claimed)
      {
         success = os_semaphore_obtain((*cond)->semaphore);
         os_assert(success == 0);
      }
      w = (*cond)->waiters;
      if (w)
      {
         // Wake the first person waiting
         vcos_event_signal(&w->latch);
         (*cond)->waiters = w->next;
         
      }
      success = 0;
      if (!sem_claimed)
      {
         success = os_semaphore_release((*cond)->semaphore);
      }
      os_assert(success == 0);
   }

   return success;
}
Example #4
0
/* ----------------------------------------------------------------------
 * received response to an ILCS command
 * -------------------------------------------------------------------- */
static void
vc_ilcs_response( uint32_t xid, unsigned char *msg, int len )
{
   VC_ILCS_WAIT_T *wait;
   int i;

   // atomically retrieve given ->wait entry
   os_semaphore_obtain( &vc_ilcsg.wait_sem );
   for (i=0; i<VC_ILCS_MAX_WAITING; i++) {
      wait = &vc_ilcsg.wait[i];
      if ( wait->resp && wait->xid == xid )
         break;
   }
   os_semaphore_release( &vc_ilcsg.wait_sem );

   if ( i == VC_ILCS_MAX_WAITING ) {
      // something bad happened
      assert(0);
      return;
   }

   // extract command from fifo and place in response buffer.
   memcpy( wait->resp, msg, len );

   //os_logging_message( "ilcs_poll_fifo: waking waiter %d", i );
   os_semaphore_release( &wait->sem );
}
/***********************************************************
 * Name: os_cond_broadcast
 *
 * Arguments:  OS_COND_T *cond
 *             bool_t sem_claimed
 *
 * Description: Routine to signal all threads waiting on
 *              a condition variable. The caller must
 *              say whether they have obtained the semaphore.
 *
 * Returns: int32_t - success == 0
 *
 ***********************************************************/
int32_t os_cond_broadcast( OS_COND_T *cond, bool_t sem_claimed )
{
   int32_t success = -1;
   
   if (cond)
   {
      COND_WAITER_T *w;
      
      // Ensure the condvar's semaphore is claimed for thread-safe access
      if (!sem_claimed)
      {
         success = os_semaphore_obtain((*cond)->semaphore);
         os_assert(success == 0);
      }
      for (w = (*cond)->waiters; w; w = w->next)
      {
         vcos_event_signal(&w->latch);
      }
      (*cond)->waiters = NULL;
      
      success = 0;
      if (!sem_claimed)
      {
         success = os_semaphore_release((*cond)->semaphore);
      }
      os_assert(success == 0);
   }
   
   return success;
}
/***********************************************************
 * Name: cecservice_notify_func
 *
 * Arguments: CEC service state
 *
 * Description: This is the notification task which receives all CEC
 *              service notifications
 *
 * Returns: does not return
 *
 ***********************************************************/
static void cecservice_notify_func( unsigned int argc, void *argv ) {
   int32_t success;
   CECSERVICE_HOST_STATE_T *state = (CECSERVICE_HOST_STATE_T *) argv;

   //first send a dummy message to the Videocore to let it know we are ready
   cecservice_send_command(VC_CEC_END_OF_LIST, NULL, 0, 0);

   while(1) {
      success = os_semaphore_obtain(&cecservice_notify_available_semaphore);
      vcos_assert(!success && state->initialised);

      do {
         uint32_t reason, param1, param2;
         //Get all notifications in the queue
         success = vchi_msg_dequeue( state->notify_handle[0], state->notify_buffer, sizeof(state->notify_buffer), &state->notify_length, VCHI_FLAGS_NONE );
         if(success != 0 || state->notify_length < sizeof(uint32_t)*3 ) {
            continue;
         }

         lock_obtain();
         //Check what notification it is and update ourselves accordingly before notifying the host app
         //All notifications are of format: reason, param1, param2 (all 32-bit unsigned int)
         reason = VC_VTOH32(state->notify_buffer[0]), param1 = VC_VTOH32(state->notify_buffer[1]), param2 = VC_VTOH32(state->notify_buffer[2]);

         //Unlike the TV service we have nothing to store here, so just call the callback

         lock_release();

         //Now callback the host app
         if(state->notify_fn) {
            (*state->notify_fn)(state->notify_data, reason, param1, param2);
         }
      } while(success == 0 && state->notify_length >= sizeof(uint32_t)*3); //read the next message if any
   } //while (1)
}
/***********************************************************
 * Name: os_cond_wait
 *
 * Arguments:  OS_COND_T *cond,
 *             OS_SEMAPHORE_T *semaphore
 *
 * Description: Routine to wait for a condition variable
 *              to be signalled. Semaphore is released
 *              while waiting. The same semaphore must
 *              always be used.
 *
 * Returns: int32_t - success == 0
 *
 ***********************************************************/
int32_t os_cond_wait( OS_COND_T *cond, OS_SEMAPHORE_T *semaphore )
{
   int32_t success = -1;
    
   if (cond && semaphore)
   {
      COND_WAITER_T w;
      COND_WAITER_T *p, **prev;
       
      // Check the API is being followed
      os_assert((*cond)->semaphore == semaphore && os_semaphore_obtained(semaphore));
      
      // Fill in a new waiter structure allocated on our stack
      w.next = NULL;
      vcos_demand(vcos_event_create(&w.latch, NULL) == VCOS_SUCCESS);
      
      // Add it to the end of the condvar's wait queue (we wake first come, first served)
      prev = &(*cond)->waiters;
      p = (*cond)->waiters;
      while (p)
         prev = &p->next, p = p->next;
      *prev = &w;

      // Ready to go to sleep now
      success = os_semaphore_release(semaphore);
      os_assert(success == 0);

      vcos_event_wait(&w.latch);

      success = os_semaphore_obtain(semaphore);
      os_assert(success == 0);
   }
   
   return success;
}
/* ----------------------------------------------------------------------
 * remove the slot with the given address from the given non-wrap fifo.
 * intended for out-of-order operations
 *
 * the given address must belong to a slot between the read and write
 * slots, and be in the 'ready' state
 *
 * returns 0 on success, non-0 otherwise
 * -------------------------------------------------------------------- */
int32_t
non_wrap_fifo_remove( VCHI_NWFIFO_T *_fifo, void *address )
{
   NON_WRAP_FIFO_HANDLE_T *fifo = (NON_WRAP_FIFO_HANDLE_T *)_fifo;
   int32_t success = -1;
   uint32_t slot;

   os_semaphore_obtain( &fifo->sem );

   slot = fifo->read_slot;
   os_assert( fifo->base_address );

   while( slot != fifo->write_slot ) {

      if ( fifo->slot_info[slot].address == address && fifo->slot_info[slot].state == NON_WRAP_READY ) {
         // mark this as no longer being in use
         fifo->slot_info[slot].state = NON_WRAP_NOT_IN_USE;
         success = 0;
         break;
      }
      // increment and wrap our slot number
      slot = next_slot( fifo, slot );
   }

   // if the entry to be removed was the current read slot then we need to move on
   if ( slot == fifo->read_slot && success == 0 )
      fifo->read_slot = next_read_slot( fifo, slot );

   os_semaphore_release( &fifo->sem );
   return success;
}
/* ----------------------------------------------------------------------
 * fetch the address and length of the oldest message in the given
 * non-wrap fifo
 *
 * NOTE: on success, this routine will leave the fifo locked!
 *
 * returns 0 on success, non-0 otherwise
 * -------------------------------------------------------------------- */
int32_t
non_wrap_fifo_request_read_address( VCHI_NWFIFO_T *_fifo, const void **address, uint32_t *length )
{
   NON_WRAP_FIFO_HANDLE_T *fifo = (NON_WRAP_FIFO_HANDLE_T *)_fifo;
   int32_t success = -1;

   os_semaphore_obtain( &fifo->sem );
   os_assert( fifo->base_address );

   // check that this slot is ready to be read from
   if ( fifo->slot_info[fifo->read_slot].state == NON_WRAP_READY ) {

      *address = fifo->slot_info[fifo->read_slot].address;
      *length  = fifo->slot_info[fifo->read_slot].length;

      // mark this slot as being in the process of being read
      fifo->slot_info[fifo->read_slot].state = NON_WRAP_READING;

      // success!
      success = 0;
   }

   // on success, the fifo is left locked
   if ( success != 0 )
      os_semaphore_release( &fifo->sem );
   return success;
}
/******************************************************************************
NAME
   vc_gencmd_read_response

SYNOPSIS
   int vc_gencmd_read_response

FUNCTION
   Block until something comes back

RETURNS
   Error code from dequeue message
******************************************************************************/
int vc_gencmd_read_response (char *response, int maxlen) {
   int i = 0;
   int success = 0;
   int ret_code = 0;
   int32_t sem_ok = 0;

   //Note this will ALWAYS reset response buffer and overwrite any partially read responses

   do {
      //TODO : we need to deal with messages coming through on more than one connections properly
      //At the moment it will always try to read the first connection if there is something there
      for(i = 0; i < gencmd_client.num_connections; i++) {
         //Check if there is something in the queue, if so return immediately
         //otherwise wait for the semaphore and read again
         success = (int) vchi_msg_dequeue( gencmd_client.open_handle[i], gencmd_client.response_buffer, sizeof(gencmd_client.response_buffer), &gencmd_client.response_length, VCHI_FLAGS_NONE);
         if(success == 0) {
            ret_code = VC_VTOH32( *(int *)gencmd_client.response_buffer );
            break;
         } else {
            gencmd_client.response_length = 0;
         }
      }
   } while(!gencmd_client.response_length && (sem_ok = os_semaphore_obtain( &gencmd_message_available_semaphore)) == 0);

   if(gencmd_client.response_length && sem_ok == 0) {
      gencmd_client.response_length -= sizeof(int); //first word is error code
      memcpy(response, gencmd_client.response_buffer+sizeof(int), (size_t) OS_MIN((int)gencmd_client.response_length, (int)maxlen));
   }
   // If we read anything, return the VideoCore code. Error codes < 0 mean we failed to
   // read anything...
   //How do we let the caller know the response code of gencmd?
   //return ret_code;
   return success;
}
Example #11
0
//Receiver thread
static void hostreqclient_func(unsigned int argc, void *argv) {
   int32_t success;
   int32_t i, nothing;

   while(1) { //Run forever waiting for a callback to happen
      // wait for the semaphore to say that there is a message
      success = os_semaphore_obtain(&hostreq_client_message_available);
      assert( success == 0 );

      while(1) { //Read until we can read no more on all interfaces
         nothing = 0;
         for(i=0;i<hostreq_client.num_connections;i++) {
            success = vchi_msg_dequeue(hostreq_client.client_handle[i], hostreq_client.response_buffer, sizeof(hostreq_client.response_buffer), &hostreq_client.response_length, VCHI_FLAGS_NONE);
            if(success == 0) {
               hostreq_request_handler(i, &hostreq_client);
            } else {
               nothing++;
            }
         }
         //When there is nothing on all interfaces, wait for a callback
         if(nothing == hostreq_client.num_connections) {
            break;
         }
      }
   }
}
/* ----------------------------------------------------------------------
 * read data from the given non-wrap fifo, by copying out of the
 * fifo to the given address
 *
 * returns 0 on success, non-0 otherwise
 * -------------------------------------------------------------------- */
int32_t
non_wrap_fifo_read( VCHI_NWFIFO_T *_fifo, void *data, const uint32_t max_data_size )
{
   NON_WRAP_FIFO_HANDLE_T *fifo = (NON_WRAP_FIFO_HANDLE_T *)_fifo;
   int32_t  success = -1;
   uint8_t *address = NULL;
   uint32_t length;

   os_assert(0); // FIXME: will deadlock
   os_semaphore_obtain( &fifo->sem );
   os_assert( fifo->base_address );
   // request the address and length for this transfer
   if ( non_wrap_fifo_request_read_address(fifo,&address,&length) == 0 ) {
      if ( length <= max_data_size ){
         // there is enough space and the data has been written so we can copy it out
         memcpy(data,address,length);
         // now tidy up our information about what is in the FIFO
         if ( non_wrap_fifo_read_complete(fifo,address) == 0 ) {
            // success!
            success = 0;
         }
      }
   }
   os_semaphore_release( &fifo->sem );
   return success;
}
Example #13
0
void ThreadOne(unsigned int a, void *b)
{
   TEST_OK("os_semaphore_obtain", os_semaphore_obtain(&sem1));

   flag = 1;
      
   TEST_OK("os_semaphore_release", os_semaphore_release(&sem1));
}
Example #14
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: cecservice_wait_for_reply
 *
 * Arguments: response buffer, buffer length
 *
 * Description: blocked until something is in the buffer
 *
 * Returns error code of vchi
 *
 ***********************************************************/
static int32_t cecservice_wait_for_reply(void *response, uint32_t max_length) {
   int32_t success = 0;
   int32_t sem_ok = 0;
   uint32_t length_read = 0;
   do {
      //TODO : we need to deal with messages coming through on more than one connections properly
      //At the moment it will always try to read the first connection if there is something there
      //Check if there is something in the queue, if so return immediately
      //otherwise wait for the semaphore and read again
      success = vchi_msg_dequeue( cecservice_client.client_handle[0], response, max_length, &length_read, VCHI_FLAGS_NONE );
   } while( length_read == 0 && (sem_ok = os_semaphore_obtain( &cecservice_message_available_semaphore)) == 0);
   
   return success;
}
Example #16
0
int vc_ilcs_componentlock_change(int val)
{
  OS_SEMAPHORE_T *lock = (OS_SEMAPHORE_T*)vc_ilcs_component_lock();
  
  if(NULL == lock)
	{
	  VC_DEBUG( Trace, "Error: invalid lock\n");
	  return -1;
	}
  if(val)
    {
      os_semaphore_obtain(lock);
    }
  else 
    {
      os_semaphore_release(lock);
    }
  return 0;
  
}
Example #17
0
/* ----------------------------------------------------------------------
 * send a message and wait for reply.
 * repeats continuously, on each connection
 * -------------------------------------------------------------------- */
static void
vc_ilcs_task( unsigned argc, void *argv )
{
   // FIXME: figure out why initial connect() doesn't block...
   //os_sleep( 50 );

   for (;;) {

      // wait to receive one or more messages
      os_semaphore_obtain( &vc_ilcsg.rxmsg_sem );

      while( vc_ilcs_process_message() )
         ;

   }

   // FIXME: once we implement service close
   //err = OMX_Deinit();
   //assert( err == OMX_ErrorNone );
   //filesys_deregister();
}
Example #18
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 );
}
Example #19
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 );
   }
}
/* ----------------------------------------------------------------------
 * write data to the given non-wrap fifo, by copying from the given
 * address
 *
 * returns 0 on success, non-0 otherwise
 * -------------------------------------------------------------------- */
int32_t
non_wrap_fifo_write( VCHI_NWFIFO_T *_fifo, const void *data, const uint32_t data_size )
{
   NON_WRAP_FIFO_HANDLE_T *fifo = (NON_WRAP_FIFO_HANDLE_T *)_fifo;
   int32_t  success = -1;
   uint8_t *address = NULL;

   os_assert( fifo->base_address );

   os_assert(0); // FIXME: will deadlock
   os_semaphore_obtain( &fifo->sem );
   // request the address and length for this transfer
   if ( non_wrap_fifo_request_write_address(fifo,&address,data_size) == 0 ) {
      // there is enough space so we can write the data
      memcpy(address,data,data_size);
      // now tidy up our information about what is in the FIFO
      if ( non_wrap_fifo_write_complete(fifo,address) == 0 ) {
         // success!
         success = 0;
      }
   }
   os_semaphore_release( &fifo->sem );
   return success;
}
Example #21
0
/***********************************************************
 * 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;
}
Example #22
0
/***********************************************************
 * Name: control_callback
 *
 * Arguments: void *callback_param
 *            const VCHI_CALLBACK_REASON_T reason
 *            const void *handle
 *
 * Description: Handles callbacks for received messages
 *
 * Returns: -
 *
 ***********************************************************/
static void control_callback( void *callback_param, //my service local param
                              const VCHI_CALLBACK_REASON_T reason,
                              void *handle )
{
CONTROL_SERVICE_INFO_T * service_info = (CONTROL_SERVICE_INFO_T *)callback_param;
uint8_t *message;
uint8_t output_message[128];
uint32_t message_length;
int32_t return_value;
fourcc_t service_id;
uint32_t flags;
VCHI_FLAGS_T output_flags = VCHI_FLAGS_NONE;

   switch(reason)
   {
      case VCHI_CALLBACK_MSG_AVAILABLE:
      {
         // handle the message in place
         void *message_handle;
#if defined VCHI_COARSE_LOCKING
         os_semaphore_obtain(&service_info->connection->sem);
#endif
#ifdef VCHI_FEWER_MSG_AVAILABLE_CALLBACKS
         do {
         message_handle = NULL;
#endif
         return_value = service_info->connection->api->service_hold_msg(service_info->open_handle,(void**)&message,&message_length,VCHI_FLAGS_NONE,&message_handle);
         if(return_value == 0)
         {
            if (message_length>0)
            {
               // this is a valid message - read the command
               uint32_t command = vchi_readbuf_uint32(&message[0]);
               int32_t reply_required = VC_FALSE;
               switch(command)
               {
               case CONNECT:
                  os_logging_message("CTRL SERVICE: Connect message");
                  if(service_info->initialised ==  VC_FALSE)
                  {
                     uint32_t protocol_version;
                     uint32_t slot_size;
                     uint32_t num_slots;
                     uint32_t min_bulk_size;

                     return_value = os_semaphore_release( &service_info->connected_semaphore );
                     os_assert( return_value == 0 );
                     // record that we have been initialised
                     service_info->initialised = VC_TRUE;
                     // extract the values we need to pass back to the service - principally slot size for the moment
                     protocol_version = vchi_readbuf_uint32(&message[4]);
                     slot_size        = vchi_readbuf_uint32(&message[8]);
                     num_slots        = vchi_readbuf_uint32(&message[12]);
                     min_bulk_size    = message_length >= 20 ? vchi_readbuf_uint32(&message[16]) : 0;
                     //os_assert(0);
                     service_info->connection->api->connection_info(service_info->connection->state,protocol_version, slot_size, num_slots, min_bulk_size);
                     // we are going to reply with 'CONNECT'
                     return_value = vchi_control_queue_connect( service_info, VC_TRUE );
                     os_assert( return_value == 0);
                  }
                  break;
               case SERVER_AVAILABLE:
               {
                  VCHI_SERVICE_FLAGS_T peer_flags = (VCHI_SERVICE_FLAGS_T)(message_length >= 12 ? vchi_readbuf_uint32(&message[8]) : 0);
                  int32_t our_flags;
                  service_id = vchi_readbuf_fourcc(&message[4]);
                  os_logging_message("CTRL SERVICE: Server available (%c%c%c%c:0x%x)",FOURCC_TO_CHAR(service_id),peer_flags);
                  message_length = 12;
                  // we are replying
                  reply_required = VC_TRUE;
                  // first part of the reply is the command
                  vchi_writebuf_uint32( &output_message[0], SERVER_AVAILABLE_REPLY );
                  // then the requested server ID
                  vchi_writebuf_fourcc( &output_message[4], service_id );
                  // check if this fourcc is in our list of servers on this connection
                  our_flags = service_info->connection->api->server_present(service_info->connection->state, service_id, peer_flags);
                  if(our_flags >= 0)
                     vchi_writebuf_uint32( &output_message[8], AVAILABLE | our_flags );
                  else
                     vchi_writebuf_uint32( &output_message[8], 0 );
                  break;
               }
               case SERVER_AVAILABLE_REPLY:
                  // Connection can take ownership of the message - signalled by returning true.
                  service_id = vchi_readbuf_fourcc(&message[4]);
                  flags = vchi_readbuf_uint32(&message[8]);
                  service_info->connection->api->server_available_reply(service_info->connection->state, service_id, flags);
                  break;
               case BULK_TRANSFER_RX:
               {
                  uint32_t length, channel_params, data_length, data_offset;
                  MESSAGE_TX_CHANNEL_T channel;
                  // extract the service and length and pass it to the low level driver
                  service_id = vchi_readbuf_fourcc(&message[4]);
                  length = vchi_readbuf_uint32(&message[8]);
                  channel = (MESSAGE_TX_CHANNEL_T)(message_length >= 20 ? message[12] : MESSAGE_TX_CHANNEL_BULK);
                  channel_params = message_length >= 20 ? vchi_readbuf_uint32(&message[16]) : 0;
                  data_length = message_length >= 28 ? vchi_readbuf_uint32(&message[20]) : length;
                  data_offset = message_length >= 28 ? vchi_readbuf_uint32(&message[24]) : 0;
                  os_logging_message("CTRL SERVICE: Bulk transfer rx (%c%c%c%c), channel %d, %u Bytes (core=%u, offset=%u)",FOURCC_TO_CHAR(service_id), channel, length, data_length, data_offset);
                  service_info->connection->api->rx_bulk_buffer_added(service_info->connection->state,service_id,length,channel,channel_params,data_length,data_offset);
                  break;
               }
               case XON:
                  service_id = vchi_readbuf_fourcc(&message[4]);
                  os_logging_message("CTRL SERVICE: Xon (%c%c%c%c)",FOURCC_TO_CHAR(service_id));
                  service_info->connection->api->flow_control(service_info->connection->state, service_id, VC_FALSE);
                  break;
               case XOFF:
                  service_id = vchi_readbuf_fourcc(&message[4]);
                  os_logging_message("CTRL SERVICE: Xoff (%c%c%c%c)",FOURCC_TO_CHAR(service_id));
                  service_info->connection->api->flow_control(service_info->connection->state, service_id, VC_TRUE);
                  break;
               case DISCONNECT:
                  flags = message_length >= 8 ? vchi_readbuf_uint32(&message[4]) : 0;
                  service_info->connection->api->disconnect(service_info->connection->state, flags);
                  break;
               case POWER_CONTROL:
               {
                  MESSAGE_TX_CHANNEL_T channel = vchi_readbuf_uint32(&message[4]);
                  bool_t enable = vchi_readbuf_uint32(&message[8]);
                  uint32_t cookie = vchi_readbuf_uint32(&message[12]);
                  os_logging_message("CTRL SERVICE: Power (%d -> %d; %d)", channel, enable, cookie);
                  // connection should synchronously perform the power change, then we reply
                  // don't currently allow for any sort of error (protocol doesn't allow for it)
                  service_info->connection->api->power_control(service_info->connection->state, channel, enable);
                  // we are replying
                  reply_required = VC_TRUE;
                  message_length = 16;
                  // reply is the same as the message, except for the command code
                  vchi_writebuf_uint32( &output_message[0], POWER_CONTROL_REPLY );
                  memcpy(output_message+4, message+4, 12);
                  break;
               }
               default:
                  os_logging_message("CTRL SERVICE: Unknown message (0x%x)", command);
                  os_assert(0);
                  break;
               }
               // transmit the reply (if needed)
               if(reply_required)
               {
                  //attempt to send
                  return_value = service_info->connection->api->service_queue_msg(service_info->open_handle,output_message,message_length,output_flags,NULL);
                  if (return_value != 0) //failed because tx slots are full or whatever
                  {
                     //save the msg and send it later
                     return_value = vchi_control_reply_add_service(service_info,service_id,output_message);
                     os_assert(return_value == 0);
                  }
               }
            }
            return_value = service_info->connection->api->held_msg_release(service_info->open_handle, message_handle);
            os_assert(return_value == 0);
         }
#ifdef VCHI_FEWER_MSG_AVAILABLE_CALLBACKS
         } while (message_handle);
#endif
#if defined VCHI_COARSE_LOCKING
         os_semaphore_release(&service_info->connection->sem);
#endif
         break;
      }
      case VCHI_CALLBACK_MSG_SENT:
         break;
         
      case VCHI_CALLBACK_BULK_RECEIVED:
      case VCHI_CALLBACK_BULK_DATA_READ:
      case VCHI_CALLBACK_BULK_SENT:      // control service doesn't use bulk transfers
      case VCHI_CALLBACK_SENT_XOFF:
      case VCHI_CALLBACK_SENT_XON:       // control service must never be XOFFed
         os_assert(0);
         break;
   }
}
Example #23
0
/***********************************************************
 * Name: software_fifo_protect
 *
 * Arguments: SOFTWARE_FIFO_HANDLE_T *handle - handle to this FIFO
 *
 * Description: Acquires the semaphore used to protect the SOFTWARE_FIFO_HANDLE_T structure
 *
 * Returns: 0 if successful, any other value is failure
 *
 ***********************************************************/
int32_t software_fifo_protect( SOFTWARE_FIFO_HANDLE_T *handle )
{
   return(os_semaphore_obtain(&handle->software_fifo_semaphore));
}
/******************************************************************************
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;
}
//Lock the host state
static void lock_obtain (void) {
   int32_t success;
   vcos_assert(cecservice_client.initialised);
   success = os_semaphore_obtain( &cecservice_client.sema );
   vcos_assert(success >= 0);
}
Example #26
0
//Lock the host state
static void lock_obtain (void) {
   assert(hostreq_client.initialised);
   assert(!os_semaphore_obtained(&hostreq_client.sema));
   int success = os_semaphore_obtain(&hostreq_client.sema);
   assert(success >= 0);
}
static void lock_obtain (void) {
   int32_t success;
   assert(!os_semaphore_obtained(&gencmd_client.sema));
   success = os_semaphore_obtain( &gencmd_client.sema );
   assert(success >= 0);
}
Example #28
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;
}
Example #29
0
void
vc_ilcs_obtain_component_lock( void )
{
   os_semaphore_obtain( &vc_ilcsg.component_lock );
}
Example #30
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;
}