Ejemplo n.º 1
0
static void
bcm2835_audio_update_params(struct bcm2835_audio_info *sc, struct bcm2835_audio_chinfo *ch)
{
	VC_AUDIO_MSG_T m;
	int ret;

	VCHIQ_VCHI_LOCK(sc);
	if (sc->vchi_handle != VCHIQ_SERVICE_HANDLE_INVALID) {
		vchi_service_use(sc->vchi_handle);

		sc->msg_result = -1;

		m.type = VC_AUDIO_MSG_TYPE_CONFIG;
		m.u.config.channels = AFMT_CHANNEL(ch->fmt);
		m.u.config.samplerate = ch->spd;
		m.u.config.bps = AFMT_BIT(ch->fmt);

		ret = vchi_msg_queue(sc->vchi_handle,
		    &m, sizeof m, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);

		if (ret != 0)
			printf("%s: vchi_msg_queue failed (err %d)\n", __func__, ret);

		mtx_lock(&sc->msg_avail_lock);
		cv_wait_sig(&sc->msg_avail_cv, &sc->msg_avail_lock);
		if (sc->msg_result)
			printf("%s failed: %d\n", __func__, sc->msg_result);
		mtx_unlock(&sc->msg_avail_lock);

		vchi_service_release(sc->vchi_handle);
	}
	VCHIQ_VCHI_UNLOCK(sc);
}
Ejemplo n.º 2
0
/***********************************************************
 * Name: vc_dispmanx_vsync_callback
 *
 * Arguments:
 *       DISPMANX_DISPLAY_HANDLE_T display
 *       DISPMANX_CALLBACK_FUNC_T cb_func
 *       void *cb_arg
 *
 * Description: start sending callbacks on vsync events
 *              Use a NULL cb_func to stop the callbacks
 * Returns: 0 or failure
 *
 ***********************************************************/
VCHPRE_ int VCHPOST_ vc_dispmanx_vsync_callback( DISPMANX_DISPLAY_HANDLE_T display, DISPMANX_CALLBACK_FUNC_T cb_func, void *cb_arg )
{
    // Steal the invalid 0 handle to indicate this is a vsync request
    DISPMANX_UPDATE_HANDLE_T update = 0;
    int enable = (cb_func != NULL);
    uint32_t update_param[] = {(uint32_t) VC_HTOV32(display), VC_HTOV32(update), (int32_t)enable};
    int success;

    // Set the callback
    dispmanx_client.vsync_callback = cb_func;
    dispmanx_client.vsync_callback_param = cb_arg;

    if (!dispmanx_client.vsync_enabled && enable) {
        // An extra "use" is required while a vsync callback is registered.
        // The corresponding "release" is below.
        vchi_service_use(dispmanx_client.notify_handle[0]);
    }

    success = (int) dispmanx_send_command( EDispmanVsyncCallback | DISPMANX_NO_REPLY_MASK,
                                           update_param, sizeof(update_param));

    if (dispmanx_client.vsync_enabled && !enable) {
        // The extra "use" added above is no longer required.
        vchi_service_release(dispmanx_client.notify_handle[0]);
    }

    dispmanx_client.vsync_enabled = enable;

    return (int) success;
}
Ejemplo n.º 3
0
static void
bcm2835_audio_update_controls(struct bcm2835_audio_info *sc)
{
	VC_AUDIO_MSG_T m;
	int ret, db;

	VCHIQ_VCHI_LOCK(sc);
	if (sc->vchi_handle != VCHIQ_SERVICE_HANDLE_INVALID) {
		vchi_service_use(sc->vchi_handle);

		sc->msg_result = -1;

		m.type = VC_AUDIO_MSG_TYPE_CONTROL;
		m.u.control.dest = sc->dest;
		if (sc->volume > 99)
			sc->volume = 99;
		db = db_levels[sc->volume/5];
		m.u.control.volume = VCHIQ_AUDIO_VOLUME(db);

		ret = vchi_msg_queue(sc->vchi_handle,
		    &m, sizeof m, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);

		if (ret != 0)
			printf("%s: vchi_msg_queue failed (err %d)\n", __func__, ret);

		mtx_lock(&sc->msg_avail_lock);
		cv_wait_sig(&sc->msg_avail_cv, &sc->msg_avail_lock);
		if (sc->msg_result)
			printf("%s failed: %d\n", __func__, sc->msg_result);
		mtx_unlock(&sc->msg_avail_lock);

		vchi_service_release(sc->vchi_handle);
	}
	VCHIQ_VCHI_UNLOCK(sc);
}
Ejemplo n.º 4
0
/***********************************************************
 * Name: dispmanx_notify_handle
 *
 * Arguments: not used
 *
 * Description: this purely notifies the update callback
 *
 * Returns: does not return
 *
 ***********************************************************/
static void *dispmanx_notify_func( void *arg ) {
    int32_t success;
    VCOS_STATUS_T status;

    (void)arg;

    while (1) {
        DISPMANX_UPDATE_HANDLE_T handle;
        status = vcos_event_wait(&dispmanx_notify_available_event);
        if (status != VCOS_SUCCESS || !dispmanx_client.initialised)
            break;
        success = vchi_msg_dequeue( dispmanx_client.notify_handle[0], dispmanx_client.notify_buffer, sizeof(dispmanx_client.notify_buffer), &dispmanx_client.notify_length, VCHI_FLAGS_NONE );
        if (success != 0)
            continue;

        handle = (DISPMANX_UPDATE_HANDLE_T)dispmanx_client.notify_buffer[0];
        if (handle) {
            // This is the response to an update submit
            // Decrement the use count - the corresponding "use" is in vc_dispmanx_update_submit.
            vchi_service_release(dispmanx_client.notify_handle[0]);
            if (dispmanx_client.update_callback ) {
                vcos_assert( dispmanx_client.pending_update_handle == handle);
                dispmanx_client.update_callback(handle, dispmanx_client.update_callback_param);
            }
        } else {
            // This is a vsync notification
            if (dispmanx_client.vsync_callback ) {
                dispmanx_client.vsync_callback(handle, dispmanx_client.vsync_callback_param);
            }
        }
    }
    return 0;
}
Ejemplo n.º 5
0
static void
bcm2835_audio_start(struct bcm2835_audio_chinfo *ch)
{
	VC_AUDIO_MSG_T m;
	int ret;
	struct bcm2835_audio_info *sc = ch->parent;

	VCHIQ_VCHI_LOCK(sc);
	if (sc->vchi_handle != VCHIQ_SERVICE_HANDLE_INVALID) {
		vchi_service_use(sc->vchi_handle);

		bcm2835_audio_reset_channel(ch);

		m.type = VC_AUDIO_MSG_TYPE_START;
		ret = vchi_msg_queue(sc->vchi_handle,
		    &m, sizeof m, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);

		if (ret != 0)
			printf("%s: vchi_msg_queue failed (err %d)\n", __func__, ret);

		vchi_service_release(sc->vchi_handle);
	}
	VCHIQ_VCHI_UNLOCK(sc);

}
Ejemplo n.º 6
0
int release_gencmd_service(void) {
   int ret = 0;
   int i=0;
   for(i = 0; i < gencmd_client.num_connections; i++) {
      ret = (ret == 0) ? vchi_service_release(gencmd_client.open_handle[i]) : ret;
   }
   return ret;
}
Ejemplo n.º 7
0
//Unlock the host state
static __inline void lock_release (void) {
   uint32_t i;
   vcos_assert(dispmanx_client.initialised);
   if(dispmanx_client.initialised)
   {
      for (i=0; i<dispmanx_client.num_connections; i++) {
         vchi_service_release(dispmanx_client.client_handle[i]);
      }
   }
   vcos_mutex_unlock( &dispmanx_client.lock );
}
Ejemplo n.º 8
0
int bcm2835_audio_open(bcm2835_alsa_stream_t * alsa_stream)
{
	AUDIO_INSTANCE_T *instance;
	VC_AUDIO_MSG_T m;
	int32_t success;
	int ret;
	LOG_DBG(" .. IN\n");

	my_workqueue_init(alsa_stream);

	ret = bcm2835_audio_open_connection(alsa_stream);
	if (ret != 0) {
		ret = -1;
		goto exit;
	}
	instance = alsa_stream->instance;
	LOG_DBG(" instance (%p)\n", instance);

	if(mutex_lock_interruptible(&instance->vchi_mutex))
	{
		LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
		return -EINTR;
	}
	vchi_service_use(instance->vchi_handle[0]);

	m.type = VC_AUDIO_MSG_TYPE_OPEN;

	/* Send the message to the videocore */
	success = vchi_msg_queue(instance->vchi_handle[0],
				 &m, sizeof m,
				 VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);

	if (success != 0) {
		LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
			__func__, success);

		ret = -1;
		goto unlock;
	}

	ret = 0;

unlock:
	vchi_service_release(instance->vchi_handle[0]);
	mutex_unlock(&instance->vchi_mutex);
exit:
	LOG_DBG(" .. OUT\n");
	return ret;
}
Ejemplo n.º 9
0
static void
bcm2835_audio_release(struct bcm2835_audio_info *sc)
{
	int success;

	if (sc->vchi_handle != VCHIQ_SERVICE_HANDLE_INVALID) {
		success = vchi_service_close(sc->vchi_handle);
		if (success != 0)
			printf("vchi_service_close failed: %d\n", success);
		vchi_service_release(sc->vchi_handle);
		sc->vchi_handle = VCHIQ_SERVICE_HANDLE_INVALID;
	}

	vchi_disconnect(sc->vchi_instance);
}
Ejemplo n.º 10
0
/* VCHIQ stuff */
static void
bcm2835_audio_init(struct bcm2835_audio_info *sc)
{
	int status;

	/* Initialize and create a VCHI connection */
	status = vchi_initialise(&sc->vchi_instance);
	if (status != 0) {
		printf("vchi_initialise failed: %d\n", status);
		return;
	}

	status = vchi_connect(NULL, 0, sc->vchi_instance);
	if (status != 0) {
		printf("vchi_connect failed: %d\n", status);
		return;
	}

	SERVICE_CREATION_T params = {
	    VCHI_VERSION_EX(VC_AUDIOSERV_VER, VC_AUDIOSERV_MIN_VER),
	    VC_AUDIO_SERVER_NAME,   /* 4cc service code */
	    sc->vchi_connection,    /* passed in fn pointers */
	    0,  /* rx fifo size */
	    0,  /* tx fifo size */
	    bcm2835_audio_callback,    /* service callback */
	    sc,   /* service callback parameter */
	    1,
	    1,
	    0   /* want crc check on bulk transfers */
	};

	status = vchi_service_open(sc->vchi_instance, &params,
	    &sc->vchi_handle);

	if (status == 0)
		/* Finished with the service for now */
		vchi_service_release(sc->vchi_handle);
	else
		sc->vchi_handle = VCHIQ_SERVICE_HANDLE_INVALID;
}
Ejemplo n.º 11
0
/***********************************************************
 * Name: dispmanx_notify_handle
 *
 * Arguments: not used
 *
 * Description: this purely notifies the update callback
 *
 * Returns: does not return
 *
 ***********************************************************/
static void *dispmanx_notify_func( void *arg ) {
   int32_t success;
   VCOS_STATUS_T status;

   (void)arg;

   while(1) {
      status = vcos_event_wait(&dispmanx_notify_available_event);
      if(status != VCOS_SUCCESS || !dispmanx_client.initialised)
         break;
      success = vchi_msg_dequeue( dispmanx_client.notify_handle[0], dispmanx_client.notify_buffer, sizeof(dispmanx_client.notify_buffer), &dispmanx_client.notify_length, VCHI_FLAGS_NONE );
      vchi_service_release(dispmanx_client.notify_handle[0]); // corresponding use in vc_dispmanx_update_submit
      if(success != 0)
         continue;
   
      if(dispmanx_client.update_callback ) {
         vcos_assert( dispmanx_client.pending_update_handle == (DISPMANX_UPDATE_HANDLE_T) dispmanx_client.notify_buffer[1]);
         dispmanx_client.update_callback((DISPMANX_UPDATE_HANDLE_T) dispmanx_client.notify_buffer[1], dispmanx_client.update_callback_param);
      }
   }
   return 0;
}
Ejemplo n.º 12
0
static void
bcm2835_audio_write_samples(struct bcm2835_audio_chinfo *ch)
{
	struct bcm2835_audio_info *sc = ch->parent;
	VC_AUDIO_MSG_T m;
	void *buf;
	uint32_t count, size;
	int ret;

	VCHIQ_VCHI_LOCK(sc);
	if (sc->vchi_handle == VCHIQ_SERVICE_HANDLE_INVALID) {
		VCHIQ_VCHI_UNLOCK(sc);
		return;
	}

	vchi_service_use(sc->vchi_handle);

	size = sndbuf_getsize(ch->buffer);
	count = vchiq_unbuffered_bytes(ch);
	buf = (uint8_t*)sndbuf_getbuf(ch->buffer) + ch->buffered_ptr;

	if (ch->buffered_ptr + count > size)
		count = size - ch->buffered_ptr;

	if (count < VCHIQ_AUDIO_PACKET_SIZE)
		goto done;

	count = min(count, ch->free_buffer);
	count -= count % VCHIQ_AUDIO_PACKET_SIZE;

	m.type = VC_AUDIO_MSG_TYPE_WRITE;
	m.u.write.count = count;
	m.u.write.max_packet = VCHIQ_AUDIO_PACKET_SIZE;
	m.u.write.callback = NULL;
	m.u.write.cookie = ch;
	if (buf)
		m.u.write.silence = 0;
	else
		m.u.write.silence = 1;

	ret = vchi_msg_queue(sc->vchi_handle,
	    &m, sizeof m, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);

	if (ret != 0)
		printf("%s: vchi_msg_queue failed (err %d)\n", __func__, ret);

	if (buf) {
		while (count > 0) {
			int bytes = MIN((int)m.u.write.max_packet, (int)count);
			ch->free_buffer -= bytes;
			ch->buffered_ptr += bytes;
			ch->buffered_ptr = ch->buffered_ptr % size;
			ret = vchi_msg_queue(sc->vchi_handle,
			    buf, bytes, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
			if (ret != 0)
				printf("%s: vchi_msg_queue failed: %d\n",
				    __func__, ret);
			buf = (char *)buf + bytes;
			count -= bytes;
		}
	}
done:

	vchi_service_release(sc->vchi_handle);
	VCHIQ_VCHI_UNLOCK(sc);
}
Ejemplo n.º 13
0
void vc_vchi_dispmanx_init (VCHI_INSTANCE_T initialise_instance, VCHI_CONNECTION_T **connections, uint32_t num_connections ) {
   VCOS_STATUS_T status;
   int32_t success;
   uint32_t i;

   // record the number of connections
   memset( &dispmanx_client, 0, sizeof(DISPMANX_SERVICE_T) );
   dispmanx_client.num_connections = num_connections;

   status = vcos_mutex_create(&dispmanx_client.lock, "HDispmanx");
   vcos_assert(status == VCOS_SUCCESS);

   status = vcos_event_create(&dispmanx_message_available_event, "HDispmanx");
   vcos_assert(status == VCOS_SUCCESS);

   status = vcos_event_create(&dispmanx_notify_available_event, "HDispmanx");
   vcos_assert(status == VCOS_SUCCESS);

   dispmanx_client.initialised = 1;

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

      VCOS_THREAD_ATTR_T attrs;

      // Create a 'Client' service on the each of the connections
      SERVICE_CREATION_T dispmanx_parameters = { DISPMANX_CLIENT_NAME,     // 4cc service code
                                                 connections[i],           // passed in fn ptrs
                                                 0,                        // tx fifo size (unused)
                                                 0,                        // tx fifo size (unused)
                                                 &dispmanx_client_callback, // service callback
                                                 &dispmanx_message_available_event,  // callback parameter
                                                 VC_FALSE,                  // want_unaligned_bulk_rx
                                                 VC_FALSE,                  // want_unaligned_bulk_tx
                                                 VC_FALSE,                  // want_crc
                                                 };

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

      success = vchi_service_open( initialise_instance, &dispmanx_parameters, &dispmanx_client.client_handle[i] );
      vcos_assert( success == 0 );

      // Create the async service of dispman to handle update callback

      success = vchi_service_open( initialise_instance, &dispmanx_parameters2, &dispmanx_client.notify_handle[i] );
      vcos_assert( success == 0 );

      //Create the notifier task
      vcos_thread_attr_init(&attrs);
      vcos_thread_attr_setstacksize(&attrs, 2048);
      vcos_thread_attr_settimeslice(&attrs, 1);

      status = vcos_thread_create(&dispmanx_notify_task, "HDispmanx Notify", &attrs, dispmanx_notify_func, NULL);
      vcos_assert(status == VCOS_SUCCESS);

      // release services until they're actually used
      vchi_service_release(dispmanx_client.client_handle[i]);
      vchi_service_release(dispmanx_client.notify_handle[i]);
   }
}
Ejemplo n.º 14
0
VC_VCHI_FB_HANDLE_T vc_vchi_fb_init(VCHI_INSTANCE_T vchi_instance,
				    VCHI_CONNECTION_T ** vchi_connections,
				    uint32_t num_connections)
{
	uint32_t i;
	FB_INSTANCE_T *instance;
	int32_t status;

	LOG_DBG("%s: start", __func__);

	if (num_connections > VCHI_MAX_NUM_CONNECTIONS) {
		LOG_ERR("%s: unsupported number of connections %u (max=%u)",
			__func__, num_connections, VCHI_MAX_NUM_CONNECTIONS);

		return NULL;
	}
	/* Allocate memory for this instance */
	instance = kzalloc(sizeof(*instance), GFP_KERNEL);
	memset(instance, 0, sizeof(*instance));

	instance->num_connections = num_connections;

	/* Create the message available semaphore */
	sema_init(&instance->msg_avail, 0);

	/* Create a lock for exclusive, serialized VCHI connection access */
	mutex_init(&instance->vchi_mutex);

	/* Open the VCHI service connections */
	for (i = 0; i < num_connections; i++) {
		SERVICE_CREATION_T params = {
			VCHI_VERSION_EX(VC_FB_VER, VC_FB_VER_MIN),
			VC_FB_SERVER_NAME,
			vchi_connections[i],
			0,
			0,
			fb_vchi_callback,
			instance,
			0,
			0,
			0
		};

		status = vchi_service_open(vchi_instance, &params,
					   &instance->vchi_handle[i]);
		if (status) {
			LOG_ERR
			    ("%s: failed to open VCHI service (%d)",
			     __func__, status);

			goto err_close_services;
		}
		/* Finished with the service for now */
		vchi_service_release(instance->vchi_handle[i]);
	}

	return instance;

err_close_services:
	for (i = 0; i < instance->num_connections; i++)
		vchi_service_close(instance->vchi_handle[i]);

	kfree(instance);

	return NULL;
}
Ejemplo n.º 15
0
int32_t vc_vchi_fb_read(VC_VCHI_FB_HANDLE_T handle, uint32_t res_handle,
			void *buf, int32_t size)
{
	int32_t ret, success = 0;
	FB_INSTANCE_T *instance = handle;
	uint32_t msg_len;
	VC_FB_MSG_HDR_T *msg_hdr;
	VC_FB_READ_T *fb_read;
	VC_FB_RESULT_T result;

	if (handle == NULL) {
		LOG_ERR("%s: invalid handle", __func__);

		ret = -1;
		goto out;
	}

	if (buf == NULL) {
		LOG_ERR("%s: invalid buffer pointer", __func__);

		ret = -1;
		goto out;
	}

	if (size <= 0) {
		LOG_ERR("%s: invalid buffer size %d", __func__, size);

		ret = -1;
		goto out;
	}

	mutex_lock(&instance->vchi_mutex);
	vchi_service_use(instance->vchi_handle[0]);

	LOG_INFO("%s: enter", __func__);

	msg_len = sizeof(*msg_hdr) + sizeof(*fb_read);
	memset(instance->msg_buf, 0, msg_len);

	msg_hdr = (VC_FB_MSG_HDR_T *) instance->msg_buf;
	msg_hdr->type = VC_FB_MSG_TYPE_READ;

	fb_read = (VC_FB_READ_T *) msg_hdr->body;
	fb_read->res_handle = res_handle;
	fb_read->size = size;

	/* Send the message to the videocore */
	success = vchi_msg_queue(instance->vchi_handle[0],
				 instance->msg_buf, msg_len,
				 VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
	if (success != 0) {
		LOG_ERR("%s: failed to queue message (success=%d)",
			__func__, success);

		ret = -1;
		goto unlock;
	}
	LOG_INFO("%s: done sending msg", __func__);
	/* We are expecting a reply from the videocore */
	down(&instance->msg_avail);

	success = vchi_msg_dequeue(instance->vchi_handle[0],
				   &result, sizeof(result),
				   &msg_len, VCHI_FLAGS_NONE);

	LOG_INFO("%s: got reply message %x", __func__, result.success);

	if (success != 0) {
		LOG_ERR("%s: failed to dequeue message (success=%d)",
			__func__, success);

		ret = -1;
		goto unlock;
	} else if (msg_len != sizeof(result)) {
		LOG_ERR("%s: incorrect message length %u (expected=%u)",
			__func__, msg_len, sizeof(result));

		ret = -1;
		goto unlock;
	}

	LOG_INFO("%s: all good do bulk_receive %x", __func__, result.success);
	success = vchi_bulk_queue_receive(instance->vchi_handle[0],
					  buf,
					  size,
					  VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE,
					  0);

	if (success != 0)
		LOG_ERR("%s: vchi_bulk_queue_receive failed", __func__);

unlock:

	vchi_service_release(instance->vchi_handle[0]);
	mutex_unlock(&instance->vchi_mutex);

	ret = success;
	LOG_INFO("%s: exit", __func__);
out:
	return ret;
}
Ejemplo n.º 16
0
int32_t vc_vchi_fb_cfg(VC_VCHI_FB_HANDLE_T handle,
		       VC_FB_CFG_T * cfg, VC_FB_CFG_RESULT_T * cfg_result)
{
	int32_t ret;
	FB_INSTANCE_T *instance = handle;
	int32_t success;
	uint32_t msg_len;
	VC_FB_MSG_HDR_T *msg_hdr;

	if (handle == NULL) {
		LOG_ERR("%s: invalid handle", __func__);

		ret = -1;
		goto out;
	}

	if (cfg == NULL) {
		LOG_ERR("%s: invalid cfg pointer", __func__);

		ret = -1;
		goto out;
	}

	if (cfg_result == NULL) {
		LOG_ERR("%s: invalid cfg_result pointer", __func__);

		ret = -1;
		goto out;
	}

	mutex_lock(&instance->vchi_mutex);
	vchi_service_use(instance->vchi_handle[0]);

	msg_len = sizeof(*msg_hdr) + sizeof(*cfg);
	memset(instance->msg_buf, 0, msg_len);

	msg_hdr = (VC_FB_MSG_HDR_T *) instance->msg_buf;
	msg_hdr->type = VC_FB_MSG_TYPE_CFG;

	/* Copy the user buffer into the message buffer */
	memcpy(msg_hdr->body, cfg, sizeof(*cfg));

	/* Send the message to the videocore */
	success = vchi_msg_queue(instance->vchi_handle[0],
				 instance->msg_buf, msg_len,
				 VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
	if (success != 0) {
		LOG_ERR("%s: failed to queue message (success=%d)",
			__func__, success);

		ret = -1;
		goto unlock;
	}
	/* We are expecting a reply from the videocore */
	down(&instance->msg_avail);

	success = vchi_msg_dequeue(instance->vchi_handle[0],
				   cfg_result, sizeof(*cfg_result),
				   &msg_len, VCHI_FLAGS_NONE);
	if (success != 0) {
		LOG_ERR("%s: failed to dequeue message (success=%d)",
			__func__, success);

		ret = -1;
		goto unlock;
	} else if (msg_len != sizeof(*cfg_result)) {
		LOG_ERR("%s: incorrect message length %u (expected=%u)",
			__func__, msg_len, sizeof(*cfg_result));

		ret = -1;
		goto unlock;
	}

	ret = cfg_result->success ? -1 : 0;

unlock:
	vchi_service_release(instance->vchi_handle[0]);
	mutex_unlock(&instance->vchi_mutex);

out:
	return ret;
}
Ejemplo n.º 17
0
int32_t vc_vchi_fb_swap(VC_VCHI_FB_HANDLE_T handle,
			uint32_t res_handle, uint32_t active_frame)
{
	int ret;
	FB_INSTANCE_T *instance = handle;
	int32_t success;
	uint32_t msg_len;
	VC_FB_MSG_HDR_T *msg_hdr;
	VC_FB_SWAP_T *swap;
	VC_FB_RESULT_T result;

	if (handle == NULL) {
		LOG_ERR("%s: invalid handle %p", __func__, handle);

		return -1;
	}

	mutex_lock(&instance->vchi_mutex);
	vchi_service_use(instance->vchi_handle[0]);

	msg_len = sizeof(*msg_hdr) + sizeof(*swap);
	memset(instance->msg_buf, 0, msg_len);

	msg_hdr = (VC_FB_MSG_HDR_T *) instance->msg_buf;
	msg_hdr->type = VC_FB_MSG_TYPE_SWAP;

	swap = (VC_FB_SWAP_T *) msg_hdr->body;
	swap->res_handle = res_handle;
	swap->active_frame = active_frame;

	/* Send the message to the videocore */
	success = vchi_msg_queue(instance->vchi_handle[0],
				 instance->msg_buf, msg_len,
				 VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
	if (success != 0) {
		LOG_ERR("%s: failed to queue message (success=%d)",
			__func__, success);

		ret = -1;
		goto unlock;
	}
	/* We are expecting a reply from the videocore */
	down(&instance->msg_avail);

	success = vchi_msg_dequeue(instance->vchi_handle[0],
				   &result, sizeof(result),
				   &msg_len, VCHI_FLAGS_NONE);
	if (success != 0) {
		LOG_ERR("%s: failed to dequeue message (success=%d)",
			__func__, success);

		ret = -1;
		goto unlock;
	} else if (msg_len != sizeof(result)) {
		LOG_ERR("%s: incorrect message length %u (expected=%u)",
			__func__, msg_len, sizeof(result));

		ret = -1;
		goto unlock;
	}

	ret = result.success ? -1 : 0;

unlock:
	vchi_service_release(instance->vchi_handle[0]);
	mutex_unlock(&instance->vchi_mutex);

	return ret;
}
Ejemplo n.º 18
0
int32_t vc_vchi_fb_alloc(VC_VCHI_FB_HANDLE_T handle,
			 VC_FB_ALLOC_T * alloc,
			 VC_FB_ALLOC_RESULT_T * alloc_result)
{
	FB_INSTANCE_T *instance = handle;
	int32_t success;
	uint32_t msg_len;
	VC_FB_MSG_HDR_T *msg_hdr;
	int32_t ret = -1;

	if (handle == NULL) {
		LOG_ERR("%s: invalid handle %p", __func__, handle);

		return -1;
	}

	if (alloc == NULL) {
		LOG_ERR("%s: invalid alloc pointer %p", __func__, alloc);

		return -1;
	}
	/* TODO check individual alloc member values */

	if (alloc_result == NULL) {
		LOG_ERR("%s: invalid alloc_result pointer 0x%p", __func__,
			alloc_result);

		return -1;
	}

	mutex_lock(&instance->vchi_mutex);
	vchi_service_use(instance->vchi_handle[0]);

	msg_len = sizeof(*msg_hdr) + sizeof(*alloc);
	memset(instance->msg_buf, 0, msg_len);

	msg_hdr = (VC_FB_MSG_HDR_T *) instance->msg_buf;
	msg_hdr->type = VC_FB_MSG_TYPE_ALLOC;

	/* Copy the user buffer into the message buffer */
	memcpy(msg_hdr->body, alloc, sizeof(*alloc));

	/* Send the message to the videocore */
	success = vchi_msg_queue(instance->vchi_handle[0],
				 instance->msg_buf, msg_len,
				 VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
	if (success != 0) {
		LOG_ERR("%s: failed to queue message (success=%d)",
			__func__, success);

		goto unlock;
	}
	/*  We are expecting a reply from the videocore */
	down(&instance->msg_avail);

	success = vchi_msg_dequeue(instance->vchi_handle[0],
				   alloc_result, sizeof(*alloc_result),
				   &msg_len, VCHI_FLAGS_NONE);
	if (success != 0) {
		LOG_ERR("%s: failed to dequeue message (success=%d)",
			__func__, success);

		goto unlock;
	} else if (msg_len != sizeof(*alloc_result)) {
		LOG_ERR("%s: incorrect message length %u (expected=%u)",
			__func__, msg_len, sizeof(*alloc_result));

		goto unlock;
	}
	/* success if we got to here */
	ret = 0;

unlock:
	vchi_service_release(instance->vchi_handle[0]);
	mutex_unlock(&instance->vchi_mutex);

	return ret;
}
Ejemplo n.º 19
0
int32_t vc_vchi_fb_get_scrn_info(VC_VCHI_FB_HANDLE_T handle,
				 VC_FB_SCRN scrn, VC_FB_SCRN_INFO_T * info)
{
	int ret;
	FB_INSTANCE_T *instance = handle;
	int32_t success;
	uint32_t msg_len;
	VC_FB_MSG_HDR_T *msg_hdr;
	VC_FB_GET_SCRN_INFO_T *get_scrn_info;

	if (handle == NULL) {
		LOG_ERR("%s: invalid handle %p", __func__, handle);

		return -1;
	}

	if (scrn >= VC_FB_SCRN_MAX) {
		LOG_ERR("%s: invalid screen %u", __func__, scrn);

		return -1;
	}

	if (info == NULL) {
		LOG_ERR("%s: invalid info pointer %p", __func__, info);

		return -1;
	}

	mutex_lock(&instance->vchi_mutex);
	vchi_service_use(instance->vchi_handle[0]);

	msg_len = sizeof(*msg_hdr) + sizeof(*get_scrn_info);
	memset(instance->msg_buf, 0, msg_len);

	msg_hdr = (VC_FB_MSG_HDR_T *) instance->msg_buf;
	msg_hdr->type = VC_FB_MSG_TYPE_GET_SCRN_INFO;

	get_scrn_info = (VC_FB_GET_SCRN_INFO_T *) msg_hdr->body;
	get_scrn_info->scrn = scrn;

	/* Send the message to the videocore */
	success = vchi_msg_queue(instance->vchi_handle[0],
				 instance->msg_buf, msg_len,
				 VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
	if (success != 0) {
		LOG_ERR("%s: failed to queue message (success=%d)",
			__func__, success);

		ret = -1;
		goto unlock;
	}
	/* We are expecting a reply from the videocore */
	down(&instance->msg_avail);

	success = vchi_msg_dequeue(instance->vchi_handle[0],
				   info, sizeof(*info),
				   &msg_len, VCHI_FLAGS_NONE);
	if (success != 0) {
		LOG_ERR("%s: failed to dequeue message (success=%d)",
			__func__, success);

		ret = -1;
		goto unlock;
	} else if (msg_len != sizeof(*info)) {
		LOG_ERR("%s: incorrect message length %u (expected=%u)",
			__func__, msg_len, sizeof(*info));

		ret = -1;
		goto unlock;
	}

	ret = 0;

unlock:
	vchi_service_release(instance->vchi_handle[0]);
	mutex_unlock(&instance->vchi_mutex);

	return ret;
}
Ejemplo n.º 20
0
static int bcm2835_audio_set_ctls_chan(bcm2835_alsa_stream_t * alsa_stream,
				       bcm2835_chip_t * chip)
{
	VC_AUDIO_MSG_T m;
	AUDIO_INSTANCE_T *instance = alsa_stream->instance;
	int32_t success;
	int ret;
	LOG_DBG(" .. IN\n");

	LOG_INFO
	    (" Setting ALSA dest(%d), volume(%d)\n", chip->dest, chip->volume);

	if(mutex_lock_interruptible(&instance->vchi_mutex))
	{
		LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
		return -EINTR;
	}
	vchi_service_use(instance->vchi_handle[0]);

	instance->result = -1;

	m.type = VC_AUDIO_MSG_TYPE_CONTROL;
	m.u.control.dest = chip->dest;
	m.u.control.volume = chip->volume;

	/* Create the message available completion */
	init_completion(&instance->msg_avail_comp);

	/* Send the message to the videocore */
	success = vchi_msg_queue(instance->vchi_handle[0],
				 &m, sizeof m,
				 VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);

	if (success != 0) {
		LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
			__func__, success);

		ret = -1;
		goto unlock;
	}

	/* We are expecting a reply from the videocore */
	ret = wait_for_completion_interruptible(&instance->msg_avail_comp);
	if (ret) {
		LOG_DBG("%s: failed on waiting for event (status=%d)\n",
			__func__, success);
		goto unlock;
	}

	if (instance->result != 0) {
		LOG_ERR("%s: result=%d\n", __func__, instance->result);

		ret = -1;
		goto unlock;
	}

	ret = 0;

unlock:
	vchi_service_release(instance->vchi_handle[0]);
	mutex_unlock(&instance->vchi_mutex);

	LOG_DBG(" .. OUT\n");
	return ret;
}
Ejemplo n.º 21
0
static AUDIO_INSTANCE_T *vc_vchi_audio_init(VCHI_INSTANCE_T vchi_instance,
					    VCHI_CONNECTION_T **
					    vchi_connections,
					    uint32_t num_connections)
{
	uint32_t i;
	AUDIO_INSTANCE_T *instance;
	int status;

	LOG_DBG("%s: start", __func__);

	if (num_connections > VCHI_MAX_NUM_CONNECTIONS) {
		LOG_ERR("%s: unsupported number of connections %u (max=%u)\n",
			__func__, num_connections, VCHI_MAX_NUM_CONNECTIONS);

		return NULL;
	}
	/* Allocate memory for this instance */
	instance = kmalloc(sizeof(*instance), GFP_KERNEL);
	if (!instance)
		return NULL;

	memset(instance, 0, sizeof(*instance));
	instance->num_connections = num_connections;

	/* Create a lock for exclusive, serialized VCHI connection access */
	mutex_init(&instance->vchi_mutex);
	/* Open the VCHI service connections */
	for (i = 0; i < num_connections; i++) {
		SERVICE_CREATION_T params = {
			VCHI_VERSION_EX(VC_AUDIOSERV_VER, VC_AUDIOSERV_MIN_VER),
			VC_AUDIO_SERVER_NAME,	// 4cc service code
			vchi_connections[i],	// passed in fn pointers
			0,	// rx fifo size (unused)
			0,	// tx fifo size (unused)
			audio_vchi_callback,	// service callback
			instance,	// service callback parameter
			1,	//TODO: remove VCOS_FALSE,   // unaligned bulk recieves
			1,	//TODO: remove VCOS_FALSE,   // unaligned bulk transmits
			0	// want crc check on bulk transfers
		};

		LOG_DBG("%s: about to open %i\n", __func__, i);
		status = vchi_service_open(vchi_instance, &params,
					   &instance->vchi_handle[i]);
		LOG_DBG("%s: opened %i: %p=%d\n", __func__, i, instance->vchi_handle[i], status);
		if (status) {
			LOG_ERR
			    ("%s: failed to open VCHI service connection (status=%d)\n",
			     __func__, status);

			goto err_close_services;
		}
		/* Finished with the service for now */
		vchi_service_release(instance->vchi_handle[i]);
	}

	LOG_DBG("%s: okay\n", __func__);
	return instance;

err_close_services:
	for (i = 0; i < instance->num_connections; i++) {
		LOG_ERR("%s: closing %i: %p\n", __func__, i, instance->vchi_handle[i]);
		if (instance->vchi_handle[i])
			vchi_service_close(instance->vchi_handle[i]);
	}

	kfree(instance);
	LOG_ERR("%s: error\n", __func__);

	return NULL;
}
Ejemplo n.º 22
0
int bcm2835_audio_set_params(bcm2835_alsa_stream_t * alsa_stream,
			     uint32_t channels, uint32_t samplerate,
			     uint32_t bps)
{
	VC_AUDIO_MSG_T m;
	AUDIO_INSTANCE_T *instance = alsa_stream->instance;
	int32_t success;
	int ret;
	LOG_DBG(" .. IN\n");

	LOG_INFO
	    (" Setting ALSA channels(%d), samplerate(%d), bits-per-sample(%d)\n",
	     channels, samplerate, bps);

	/* resend ctls - alsa_stream may not have been open when first send */
	ret = bcm2835_audio_set_ctls_chan(alsa_stream, alsa_stream->chip);
	if (ret != 0) {
		LOG_ERR(" Alsa controls not supported\n");
		return -EINVAL;
	}

	if(mutex_lock_interruptible(&instance->vchi_mutex))
	{
		LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
		return -EINTR;
	}
	vchi_service_use(instance->vchi_handle[0]);

	instance->result = -1;

	m.type = VC_AUDIO_MSG_TYPE_CONFIG;
	m.u.config.channels = channels;
	m.u.config.samplerate = samplerate;
	m.u.config.bps = bps;

	/* Create the message available completion */
	init_completion(&instance->msg_avail_comp);

	/* Send the message to the videocore */
	success = vchi_msg_queue(instance->vchi_handle[0],
				 &m, sizeof m,
				 VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);

	if (success != 0) {
		LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
			__func__, success);

		ret = -1;
		goto unlock;
	}

	/* We are expecting a reply from the videocore */
	ret = wait_for_completion_interruptible(&instance->msg_avail_comp);
	if (ret) {
		LOG_DBG("%s: failed on waiting for event (status=%d)\n",
			__func__, success);
		goto unlock;
	}

	if (instance->result != 0) {
		LOG_ERR("%s: result=%d", __func__, instance->result);

		ret = -1;
		goto unlock;
	}

	ret = 0;

unlock:
	vchi_service_release(instance->vchi_handle[0]);
	mutex_unlock(&instance->vchi_mutex);

	LOG_DBG(" .. OUT\n");
	return ret;
}
Ejemplo n.º 23
0
int bcm2835_audio_close(bcm2835_alsa_stream_t * alsa_stream)
{
	VC_AUDIO_MSG_T m;
	AUDIO_INSTANCE_T *instance = alsa_stream->instance;
	int32_t success;
	int ret;
	LOG_DBG(" .. IN\n");

	my_workqueue_quit(alsa_stream);

	if(mutex_lock_interruptible(&instance->vchi_mutex))
	{
		LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
		return -EINTR;
	}
	vchi_service_use(instance->vchi_handle[0]);

	m.type = VC_AUDIO_MSG_TYPE_CLOSE;

	/* Create the message available completion */
	init_completion(&instance->msg_avail_comp);

	/* Send the message to the videocore */
	success = vchi_msg_queue(instance->vchi_handle[0],
				 &m, sizeof m,
				 VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);

	if (success != 0) {
		LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
			__func__, success);
		ret = -1;
		goto unlock;
	}

	ret = wait_for_completion_interruptible(&instance->msg_avail_comp);
	if (ret) {
		LOG_DBG("%s: failed on waiting for event (status=%d)\n",
			__func__, success);
		goto unlock;
	}
	if (instance->result != 0) {
		LOG_ERR("%s: failed result (status=%d)\n",
			__func__, instance->result);

		ret = -1;
		goto unlock;
	}

	ret = 0;

unlock:
	vchi_service_release(instance->vchi_handle[0]);
	mutex_unlock(&instance->vchi_mutex);

	/* Stop the audio service */
	if (instance) {
		vc_vchi_audio_deinit(instance);
		alsa_stream->instance = NULL;
	}
	LOG_DBG(" .. OUT\n");
	return ret;
}
Ejemplo n.º 24
0
int bcm2835_audio_write_worker(bcm2835_alsa_stream_t *alsa_stream,
			       uint32_t count, void *src)
{
	VC_AUDIO_MSG_T m;
	AUDIO_INSTANCE_T *instance = alsa_stream->instance;
	int32_t success;
	int ret;

	LOG_DBG(" .. IN\n");

	LOG_INFO(" Writing %d bytes from %p\n", count, src);

	if(mutex_lock_interruptible(&instance->vchi_mutex))
	{
		LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections);
		return -EINTR;
	}
	vchi_service_use(instance->vchi_handle[0]);

	if ( instance->peer_version==0 && vchi_get_peer_version(instance->vchi_handle[0], &instance->peer_version) == 0 ) {
		LOG_DBG("%s: client version %d connected\n", __func__, instance->peer_version);
	}
	m.type = VC_AUDIO_MSG_TYPE_WRITE;
	m.u.write.count = count;
	// old version uses bulk, new version uses control
	m.u.write.max_packet = instance->peer_version < 2 || force_bulk ? 0:4000;
	m.u.write.callback = alsa_stream->fifo_irq_handler;
	m.u.write.cookie = alsa_stream;
	m.u.write.silence = src == NULL;

	/* Send the message to the videocore */
	success = vchi_msg_queue(instance->vchi_handle[0],
				 &m, sizeof m,
				 VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);

	if (success != 0) {
		LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
			__func__, success);

		ret = -1;
		goto unlock;
	}
	if (!m.u.write.silence) {
		if (m.u.write.max_packet == 0) {
			/* Send the message to the videocore */
			success = vchi_bulk_queue_transmit(instance->vchi_handle[0],
							   src, count,
							   0 *
							   VCHI_FLAGS_BLOCK_UNTIL_QUEUED
							   +
							   1 *
							   VCHI_FLAGS_BLOCK_UNTIL_DATA_READ,
							   NULL);
		} else {
			while (count > 0) {
				int bytes = min((int)m.u.write.max_packet, (int)count);
				success = vchi_msg_queue(instance->vchi_handle[0],
							 src, bytes,
							 VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL);
				src = (char *)src + bytes;
				count -= bytes;
			}
		}
		if (success != 0) {
			LOG_ERR
			    ("%s: failed on vchi_bulk_queue_transmit (status=%d)\n",
			     __func__, success);

			ret = -1;
			goto unlock;
		}
	}
	ret = 0;

unlock:
	vchi_service_release(instance->vchi_handle[0]);
	mutex_unlock(&instance->vchi_mutex);
	LOG_DBG(" .. OUT\n");
	return ret;
}