void vc_vchi_gencmd_init (VCHI_INSTANCE_T initialise_instance, VCHI_CONNECTION_T **connections, uint32_t num_connections ) { VCOS_STATUS_T status; int32_t success; int i; if (gencmd_client.initialised) return; // record the number of connections memset( &gencmd_client, 0, sizeof(GENCMD_SERVICE_T) ); gencmd_client.num_connections = (int) num_connections; status = vcos_mutex_create(&gencmd_client.lock, "HGencmd"); vcos_assert(status == VCOS_SUCCESS); status = vcos_event_create(&gencmd_client.message_available_event, "HGencmd"); vcos_assert(status == VCOS_SUCCESS); for (i=0; i<gencmd_client.num_connections; i++) { // Create a 'LONG' service on the each of the connections SERVICE_CREATION_T gencmd_parameters = { VCHI_VERSION(VC_GENCMD_VER), 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_client.message_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, &gencmd_parameters, &gencmd_client.open_handle[i] ); assert( success == 0 ); } gencmd_client.initialised = 1; release_gencmd_service(); }
/** Disable processing on a port */ static MMAL_STATUS_T mmal_vc_port_disable(MMAL_PORT_T *port) { MMAL_PORT_MODULE_T *module = port->priv->module; MMAL_STATUS_T status; mmal_worker_reply reply; mmal_worker_port_action msg; size_t replylen = sizeof(reply); msg.component_handle = module->component_handle; msg.action = MMAL_WORKER_PORT_ACTION_DISABLE; msg.port_handle = module->port_handle; status = mmal_vc_sendwait_message(mmal_vc_get_client(), &msg.header, sizeof(msg), MMAL_WORKER_PORT_ACTION, &reply, &replylen, MMAL_FALSE); if (status == MMAL_SUCCESS) { vcos_assert(replylen == sizeof(reply)); status = reply.status; } if (status != MMAL_SUCCESS) LOG_ERROR("failed to disable port - reason %d", status); if (module->has_pool) { /* MMAL server should make sure that all buffers are sent back before it * disables the port. */ vcos_assert(vcos_blockpool_available_count(&module->pool) == port->buffer_num); vcos_blockpool_delete(&module->pool); module->has_pool = 0; } /* We need to make sure all the queued callbacks have been done */ while (mmal_queue_length(port->component->priv->module->callback_queue)) mmal_vc_do_callback(port->component); if (module->connected) mmal_vc_port_info_get(module->connected); return status; }
bool vg_tess_stroke_dash_prepare(VG_TESS_STROKE_DASH_T *dash, const float *pattern, uint32_t pattern_n, float phase, bool phase_reset) { float sum; uint32_t i; float oo_scale; uint32_t phase_i; /* find length of dash pattern */ sum = 0.0f; for (i = 0; i != pattern_n; ++i) { sum += pattern[i]; } if (sum < EPS) { return false; } /* no dashing */ oo_scale = recip_(sum); /* starting phase */ phase = mod_one_(phase * oo_scale); if (phase < 0.0f) { phase += 1.0f; } vcos_assert((phase >= 0.0f) && (phase <= 1.0f)); /* convert dash pattern and find starting index */ phase_i = 0; sum = 0.0f; for (i = 0; i != (pattern_n - 1); ++i) { sum = _minf(sum + (pattern[i] * oo_scale), 1.0f); dash->pattern[i] = sum; if (phase >= sum) { phase_i = i + 1; } } dash->pattern[pattern_n - 1] = 1.0f; dash->pattern_count = pattern_n; dash->oo_scale = oo_scale; dash->phase = phase; dash->phase_i = phase_i; dash->phase_reset = phase_reset; return true; }
static void callback_destroy_sync(KHRN_POINTER_MAP_T *map, uint32_t key, void *value, void *data) { EGL_SYNC_T *sync = (EGL_SYNC_T *)value; UNUSED(map); UNUSED(data); UNUSED(key); vcos_assert( sync != NULL ); egl_sync_term(sync); khrn_platform_free(sync); }
void eglTermDriverMonitorBRCM_impl() { EGL_SERVER_STATE_T *state = EGL_GET_SERVER_STATE(); vcos_assert(state->driver_monitor_refcount > 0); state->driver_monitor_refcount--; if (state->driver_monitor_refcount == 0) { khrn_reset_driver_counters(-1, -1); } }
/*********************************************************** * Name: vc_dispmanx_stop * * Arguments: * - * * Description: Stops the Host side part of dispmanx * * Returns: - * ***********************************************************/ VCHPRE_ void VCHPOST_ vc_dispmanx_stop( void ) { // Wait for the current lock-holder to finish before zapping dispmanx. //TODO: kill the notifier task void *dummy; uint32_t i; lock_obtain(); for (i=0; i<dispmanx_client.num_connections; i++) { int32_t result; result = vchi_service_close(dispmanx_client.client_handle[i]); vcos_assert( result == 0 ); result = vchi_service_close(dispmanx_client.notify_handle[i]); vcos_assert( result == 0 ); } lock_release(); dispmanx_client.initialised = 0; vcos_event_signal(&dispmanx_notify_available_event); vcos_thread_join(&dispmanx_notify_task, &dummy); vcos_mutex_delete(&dispmanx_client.lock); vcos_event_delete(&dispmanx_message_available_event); vcos_event_delete(&dispmanx_notify_available_event); }
static KHRN_IMAGE_FORMAT_T convert_format(uint32_t format) { switch (format & ~EGL_PIXEL_FORMAT_USAGE_MASK_BRCM) { case EGL_PIXEL_FORMAT_ARGB_8888_PRE_BRCM: return (KHRN_IMAGE_FORMAT_T)(ABGR_8888 | IMAGE_FORMAT_PRE); case EGL_PIXEL_FORMAT_ARGB_8888_BRCM: return ABGR_8888; case EGL_PIXEL_FORMAT_XRGB_8888_BRCM: return XBGR_8888; case EGL_PIXEL_FORMAT_RGB_565_BRCM: return RGB_565; case EGL_PIXEL_FORMAT_A_8_BRCM: return A_8; default: vcos_assert(0); return (KHRN_IMAGE_FORMAT_T)0; } }
/* void egl_context_maybe_free(EGL_CONTEXT_T *context) Frees a map together with its server-side resources if: - it has been destroyed - it is no longer current Implementation notes: - Preconditions: context is a valid pointer Postconditions: Either: - context->is_destroyed is false (we don't change this), or - context->is_current is true, or - context has been deleted. Invariants preserved: - Invariants used: - */ void egl_context_maybe_free(EGL_CONTEXT_T *context) { vcos_assert(context); if (!context->is_destroyed) return; if (context->is_current) return; egl_context_term(context); khrn_platform_free(context); }
void vcos_named_semaphore_delete(VCOS_NAMED_SEMAPHORE_T *sem) { VCOS_NAMED_SEMAPHORE_IMPL_T *actual = sem->actual; vcos_mutex_lock(&lock); vcos_assert(actual->refs); /* if this fires, the semaphore has already been deleted */ if (--actual->refs == 0) { vcos_semaphore_delete(&actual->sem); } vcos_mutex_unlock(&lock); }
static int32_t cecservice_send_command( uint32_t command, const void *buffer, uint32_t length, uint32_t has_reply) { VCHI_MSG_VECTOR_T vector[] = { {&command, sizeof(command)}, {buffer, length} }; int32_t success = 0; int32_t response; lock_obtain(); success = vchi_msg_queuev(cecservice_client.client_handle[0], vector, sizeof(vector)/sizeof(vector[0]), VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL ); vcos_assert( success == 0 ); if(success == 0 && has_reply) { //otherwise only wait for a reply if we ask for one success = cecservice_wait_for_reply(&response, sizeof(response)); response = VC_VTOH32(response); } else { //No reply expected or failed to send, send the success code back instead response = success; } vcos_assert(success == 0); lock_release(); return response; }
/** * buffer header callback function for encoder * * Callback will dump buffer data to the specific file * * @param port Pointer to port from which callback originated * @param buffer mmal buffer header pointer */ static void encoder_buffer_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) { MMAL_BUFFER_HEADER_T *new_buffer; // We pass our file handle and other stuff in via the userdata field. PORT_USERDATA *pData = (PORT_USERDATA *)port->userdata; if (pData) { int bytes_written = buffer->length; vcos_assert(pData->file_handle); if (buffer->length) { mmal_buffer_header_mem_lock(buffer); bytes_written = fwrite(buffer->data, 1, buffer->length, pData->file_handle); mmal_buffer_header_mem_unlock(buffer); } if (bytes_written != buffer->length) { vcos_log_error("Failed to write buffer data (%d from %d)- aborting", bytes_written, buffer->length); pData->abort = 1; } } else { vcos_log_error("Received a encoder buffer callback with no state"); } // release buffer back to the pool mmal_buffer_header_release(buffer); // and send one back to the port (if still open) if (port->is_enabled) { MMAL_STATUS_T status; new_buffer = mmal_queue_get(pData->pstate->encoder_pool->queue); if (new_buffer) status = mmal_port_send_buffer(port, new_buffer); if (!new_buffer || status != MMAL_SUCCESS) vcos_log_error("Unable to return a buffer to the encoder port"); } }
uint32_t rpc_recv(void *out, uint32_t *len_io, RPC_RECV_FLAG_T flags) { CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE(); uint32_t res = 0; uint32_t len; bool recv_ctrl; if (!len_io) { len_io = &len; } recv_ctrl = flags & (RPC_RECV_FLAG_RES | RPC_RECV_FLAG_CTRL | RPC_RECV_FLAG_LEN); /* do we want to receive anything in the control channel at all? */ vcos_assert(recv_ctrl || (flags & RPC_RECV_FLAG_BULK)); /* must receive something... */ vcos_assert(!(flags & RPC_RECV_FLAG_CTRL) || !(flags & RPC_RECV_FLAG_BULK)); /* can't receive user data over both bulk and control... */ if (recv_ctrl || len_io[0]) { /* do nothing if we're just receiving bulk of length 0 */ merge_flush(thread); if (recv_ctrl) { void *ctrl_begin; uint32_t ctrl_len; VCHI_HELD_MSG_T held_msg; int32_t success = ipc_vchi_msg_hold(get_vchi_handle(thread), &ctrl_begin, &ctrl_len, VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE, &held_msg); uint32_t *ctrl = (uint32_t *)ctrl_begin; assert(success == 0); assert(ctrl_len == rpc_pad_ctrl(ctrl_len)); if (flags & RPC_RECV_FLAG_LEN) { len_io[0] = *(ctrl++); } if (flags & RPC_RECV_FLAG_RES) { res = *(ctrl++); } if (flags & RPC_RECV_FLAG_CTRL) { memcpy(out, ctrl, len_io[0]); ctrl += rpc_pad_ctrl(len_io[0]) >> 2; } vcos_assert((uint8_t *)ctrl == ((uint8_t *)ctrl_begin + ctrl_len)); success = ipc_vchi_held_msg_release(&held_msg); assert(success == 0); }
VCOS_STATUS_T vcos_llthread_create(VCOS_LLTHREAD_T *thread, const char *name, VCOS_LLTHREAD_ENTRY_FN_T entry, void *arg, void *stack, VCOS_UNSIGNED stacksz, VCOS_UNSIGNED priority, VCOS_UNSIGNED affinity, VCOS_UNSIGNED timeslice, VCOS_UNSIGNED autostart) { HANDLE h; vcos_assert(inited); vcos_assert(stack == 0); /* We can't set the stack on this platform */ vcos_assert((priority >= VCOS_THREAD_PRI_MIN) && (priority <= VCOS_THREAD_PRI_MAX)); thread->entry = entry; thread->arg = arg; thread->magic = _VCOS_WIN32_THREAD_MAGIC; h = CreateThread(NULL, stacksz, wrapper, thread, CREATE_SUSPENDED, NULL); if (!h) { return VCOS_ENOMEM; } thread->thread = h; if (!SetThreadPriority(h, vcos_thread_priorities[priority - VCOS_THREAD_PRI_MIN])) { int err = GetLastError(); vcos_assert(err == 0); } if (autostart) { ResumeThread(h); } return VCOS_SUCCESS; }
/* ---------------------------------------------------------------------- * decrease the refcount of a pool object. if the refcount hits 0, * the object is treated as being returned to the pool as free; update * pool struct accordingly (and potentially wakeup any sleepers) * * return the new refcount * -------------------------------------------------------------------- */ int vc_pool_release( VC_POOL_OBJECT_T *object ) { vcos_assert( object->magic == OBJECT_MAGIC ); lock_pool( object->pool ); int refcount = --object->refcount; pool_object_logging( __FUNCTION__, object ); if ( refcount == 0 ) { free_object( object ); signal_event( object->pool ); } unlock_pool( object->pool ); return refcount; }
void vcos_thread_join(VCOS_THREAD_T *thread, void **pData) { vcos_assert(thread); vcos_assert(thread->magic == VCOS_THREAD_MAGIC); thread->joined = 1; vcos_semaphore_wait(&thread->wait); if (pData) { *pData = thread->exit_data; } /* Clean up */ if (thread->stack) vcos_free(thread->stack); vcos_semaphore_delete(&thread->wait); vcos_semaphore_delete(&thread->suspend); }
VCOS_STATUS_T vcos_timer_create(VCOS_TIMER_T *timer, const char *name, void (*expiration_routine)(void *context), void *context) { // TODO Implement UNREFERENCED_PARAMETER(context); UNREFERENCED_PARAMETER(name); UNREFERENCED_PARAMETER(expiration_routine); UNREFERENCED_PARAMETER(timer); vcos_assert(FALSE); return VCOS_EEXIST; }
void _vcos_task_timer_set(void (*pfn)(void*), void *cxt, VCOS_UNSIGNED ms) { VCOS_THREAD_T *thread = vcos_thread_current(); if (thread == NULL) return; vcos_assert(thread->orig_task_timer_expiration_routine == NULL); if (!thread->task_timer_created) { VCOS_STATUS_T st = vcos_timer_create(&thread->task_timer, NULL, _task_timer_expiration_routine, thread); (void)st; vcos_assert(st == VCOS_SUCCESS); thread->task_timer_created = 1; } thread->orig_task_timer_expiration_routine = pfn; thread->orig_task_timer_context = cxt; vcos_timer_set(&thread->task_timer, ms); }
/** * <DFN>vc_hdcp2_service_send_command_reply</DFN> sends a command and waits for a reply from * Videocore side HDCP2 service. * * @param client_handle is the vchi client handle * * @param lock_sema is the locking semaphore to protect the buffer * * @param reply_sema is the signalling semaphore for the reply * * @param command is the command (VC_HDCP2_CMD_CODE_T in vc_hdcp2service_defs.h) * * @param buffer is the command buffer to be sent * * @param length is the size of buffer in bytes * * @param response is the reponse buffer * * @param response_length is the maximum length of the response buffer * * @param actual_length is set to the actual length of the message * * @return zero if successful, VCHI error code if failed */ int32_t vc_hdcp2_service_send_command_reply(VCHI_SERVICE_HANDLE_T client_handle, VCOS_SEMAPHORE_T *lock_sema, VCOS_SEMAPHORE_T *reply_sema, uint32_t command, void *buffer, uint32_t length, void *response, uint32_t response_length, uint32_t *actual_length) { int32_t success = vc_hdcp2_service_send_command(client_handle, lock_sema, command, buffer, length); if(vcos_verify(!success)) { VCOS_STATUS_T status = vcos_semaphore_wait(lock_sema); vcos_assert(status == VCOS_SUCCESS); success = vc_hdcp2_service_wait_for_reply(client_handle, reply_sema, response, response_length, actual_length); status = vcos_semaphore_post(lock_sema); vcos_assert(status == VCOS_SUCCESS); } return success; }
/** * Dump image state parameters to printf. Used for debugging * * @param state Pointer to state structure to assign defaults to */ static void dump_status(RASPISTILLYUV_STATE *state) { if (!state) { vcos_assert(0); return; } printf("Width %d, Height %d, filename %s\n", state->width, state->height, state->filename); printf("Time delay %d", state->timeout); raspipreview_dump_parameters(&state->preview_parameters); raspicamcontrol_dump_parameters(&state->camera_parameters); }
void vcos_logging_init(void) { if (inited) { // FIXME: should print a warning or something here return; } vcos_mutex_create(&lock, "vcos_log"); vcos_log_register("default", &dflt_log_category); dflt_log_category.flags.want_prefix = 0; vcos_assert(!inited); inited = 1; }
/** * Dump image state parameters to printf. Used for debugging * * @param state Pointer to state structure to assign defaults to */ static void dump_status(RASPIVID_STATE *state) { if (!state) { vcos_assert(0); return; } fprintf(stderr, "Width %d, Height %d, filename %s\n", state->width, state->height, state->filename); fprintf(stderr, "bitrate %d, framerate %d, time delay %d\n", state->bitrate, state->framerate, state->timeout); raspipreview_dump_parameters(&state->preview_parameters); raspicamcontrol_dump_parameters(&state->camera_parameters); }
VCOS_STATUS_T vcos_timer_init(void) { if (timer_queue != NULL) { vcos_assert(0); return VCOS_EEXIST; } timer_queue = CreateTimerQueue(); if (!timer_queue) return VCOS_ENOMEM; return VCOS_SUCCESS; }
VCOS_STATUS_T vcos_log_assert_cmd( VCOS_CMD_PARAM_T *param ) { (void)param; #if defined( NDEBUG ) && !defined( VCOS_RELEASE_ASSERTS ) vcos_log_error( "vcos_asserts have been compiled out" ); vcos_cmd_printf( param, "vcos_asserts have been compiled out - did a vcos_log_error instead\n" ); #else vcos_assert(0); vcos_cmd_printf( param, "Executed vcos_assert(0)\n" ); #endif return VCOS_SUCCESS; }
/** * Dump image state parameters to stderr. Used for debugging * * @param state Pointer to state structure to assign defaults to */ static void dump_status(RASPISTILLYUV_STATE *state) { if (!state) { vcos_assert(0); return; } fprintf(stderr, "Width %d, Height %d\n", state->width, state->height); fprintf(stderr, "Time delay %d, Timelapse %d\n", state->timeout, state->timelapse); raspipreview_dump_parameters(&state->preview_parameters); raspicamcontrol_dump_parameters(&state->camera_parameters); }
uint32_t vcos_generic_blockpool_elem_to_handle(void *block) { uint32_t ret = (uint32_t)-1; uint32_t index = (uint32_t)-1; VCOS_BLOCKPOOL_HEADER_T *hdr = NULL; VCOS_BLOCKPOOL_T *pool = NULL; VCOS_BLOCKPOOL_SUBPOOL_T *subpool = NULL; uint32_t subpool_id; vcos_assert(block); hdr = (VCOS_BLOCKPOOL_HEADER_T*) block - 1; subpool = hdr->owner.subpool; ASSERT_SUBPOOL(subpool); pool = subpool->owner; ASSERT_POOL(pool); vcos_mutex_lock(&pool->mutex); /* The handle is the index into the array of blocks combined * with the subpool id. */ index = ((size_t) hdr - (size_t) subpool->start) / pool->block_size; vcos_assert(index < subpool->num_blocks); subpool_id = ((char*) subpool - (char*) &pool->subpools[0]) / sizeof(VCOS_BLOCKPOOL_SUBPOOL_T); vcos_assert(subpool_id < VCOS_BLOCKPOOL_MAX_SUBPOOLS); vcos_assert(subpool_id < pool->num_subpools); ret = VCOS_BLOCKPOOL_HANDLE_CREATE(index, subpool_id); vcos_log_trace("%s: index %d subpool_id %d handle 0x%08x", VCOS_FUNCTION, index, subpool_id, ret); vcos_mutex_unlock(&pool->mutex); return ret; }
static int simple_pingpong(void) { static VCOS_THREAD_T server, clients[N_CLIENTS]; unsigned long sent, received = 0; void *psent = &sent; int i; VCOS_STATUS_T st; VCOS_MSG_ENDPOINT_T self; st = vcos_msgq_endpoint_create(&self,"test"); st = vcos_thread_create(&server, "server", NULL, simple_server, NULL); for (i=0; i<N_CLIENTS; i++) { st = vcos_thread_create(&clients[i], "client", NULL, simple_client, NULL); } // wait for the clients to quit for (i=0; i<N_CLIENTS; i++) { unsigned long rx; void *prx = ℞ vcos_thread_join(&clients[i],prx); received += rx; } // tell the server to quit { VCOS_MSG_T quit; VCOS_MSGQUEUE_T *serverq = vcos_msgq_find("server"); vcos_assert(serverq != NULL); vcos_log("client: sending quit"); vcos_msg_sendwait(serverq, VCOS_MSG_N_QUIT, &quit); vcos_thread_join(&server,psent); } vcos_msgq_endpoint_delete(&self); if (sent == received) return 1; else { vcos_log("bad: sent %d, received %d", sent, received); return 0; } }
/** * Add an exif tag to the capture * * @param state Pointer to state control struct * @param exif_tag String containing a "key=value" pair. * @return Returns a MMAL_STATUS_T giving result of operation */ static MMAL_STATUS_T add_exif_tag(RASPISTILL_STATE *state, const char *exif_tag) { MMAL_STATUS_T status; MMAL_PARAMETER_EXIF_T *exif_param = (MMAL_PARAMETER_EXIF_T*)calloc(sizeof(MMAL_PARAMETER_EXIF_T) + MAX_EXIF_PAYLOAD_LENGTH, 1); vcos_assert(state); vcos_assert(state->encoder_component); // Check to see if the tag is present or is indeed a key=value pair. if (!exif_tag || strchr(exif_tag, '=') == NULL || strlen(exif_tag) > MAX_EXIF_PAYLOAD_LENGTH-1) return MMAL_EINVAL; exif_param->hdr.id = MMAL_PARAMETER_EXIF; strncpy((char*)exif_param->data, exif_tag, MAX_EXIF_PAYLOAD_LENGTH-1); exif_param->hdr.size = sizeof(MMAL_PARAMETER_EXIF_T) + strlen((char*)exif_param->data); status = mmal_port_parameter_set(state->encoder_component->output[0], &exif_param->hdr); free(exif_param); return status; }
/** * Get all the current camera parameters from specified camera component * @param camera Pointer to camera component * @param params Pointer to parameter block to accept settings * @return 0 if successful, non-zero if unsuccessful */ int raspicamcontrol_get_all_parameters(MMAL_COMPONENT_T *camera, RASPICAM_CAMERA_PARAMETERS *params) { vcos_assert(camera); vcos_assert(params); if (!camera || !params) return 1; /* TODO : Write these get functions params->sharpness = raspicamcontrol_get_sharpness(camera); params->contrast = raspicamcontrol_get_contrast(camera); params->brightness = raspicamcontrol_get_brightness(camera); params->saturation = raspicamcontrol_get_saturation(camera); params->ISO = raspicamcontrol_get_ISO(camera); params->videoStabilisation = raspicamcontrol_get_video_stabilisation(camera); params->exposureCompensation = raspicamcontrol_get_exposure_compensation(camera); params->exposureMode = raspicamcontrol_get_exposure_mode(camera); params->awbMode = raspicamcontrol_get_awb_mode(camera); params->imageEffect = raspicamcontrol_get_image_effect(camera); params->colourEffects = raspicamcontrol_get_colour_effect(camera); params->thumbnailConfig = raspicamcontrol_get_thumbnail_config(camera); */ return 0; }
/** * Display the list of commands in help format * * @param commands Array of command to check * @param num_command Number of commands in the arry * * */ void raspicli_display_help(const COMMAND_LIST *commands, const int num_commands) { int i; vcos_assert(commands); if (!commands) return; for (i = 0; i < num_commands; i++) { fprintf(stderr, "-%s, -%s\t: %s\n", commands[i].abbrev, commands[i].command, commands[i].help); } }
/** Free a port structure */ void mmal_port_free(MMAL_PORT_T *port) { LOG_TRACE("%s at %p", port ? port->name : "<invalid>", port); if (!port) return; vcos_assert(port->format == port->priv->core->format_ptr_copy); mmal_format_free(port->priv->core->format_ptr_copy); vcos_semaphore_delete(&port->priv->core->transit_sema); vcos_mutex_delete(&port->priv->core->transit_lock); vcos_mutex_delete(&port->priv->core->send_lock); vcos_mutex_delete(&port->priv->core->lock); vcos_free(port); }