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); }
/*********************************************************** * 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; }
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); }
/*********************************************************** * 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; }
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); }
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; }
//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 ); }
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; }
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); }
/* 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, ¶ms, &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; }
/*********************************************************** * 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; }
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); }
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]); } }
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, ¶ms, &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; }
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; }
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; }
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; }
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; }
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; }
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; }
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, ¶ms, &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; }
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; }
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; }
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; }