--- /dev/null
+/*
+ * Copyright (c) 2012, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Intel Corporation nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <netdb.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <wait.h>
+
+#include <audio-session-manager.h>
+
+#include <murphy/common.h>
+#include <murphy/core.h>
+
+#include <murphy/resource/client-api.h>
+
+#include "resource-asm/asm-bridge.h"
+
+
+typedef struct {
+ uint32_t pid;
+ mrp_htbl_t *sets;
+ uint32_t n_sets;
+ uint32_t current_handle;
+} client_t;
+
+
+
+typedef struct {
+ /* configuration */
+ const char *address;
+ const char *binary;
+
+ /* asm-bridge management */
+ pid_t pid;
+ mrp_transport_t *mt; /* listening transport */
+ mrp_transport_t *t; /* connected transport */
+ bool active;
+
+ /* resource management */
+ mrp_htbl_t *clients;
+ mrp_resource_client_t *resource_client;
+ char *zone;
+
+ mrp_htbl_t *requests;
+ uint32_t current_request;
+
+ /* murphy integration */
+ mrp_sighandler_t *sighandler;
+ mrp_context_t *ctx;
+} asm_data_t;
+
+
+typedef enum {
+ request_type_acquire,
+ request_type_release,
+ request_type_server_event
+} request_type_t;
+
+
+typedef struct {
+ /* immutable */
+ uint32_t pid;
+ uint32_t handle;
+ mrp_resource_set_t *rset;
+ uint32_t request_id;
+ asm_data_t *ctx;
+
+ /* mutable */
+ request_type_t rtype;
+} resource_set_data_t;
+
+
+
+enum {
+ ARG_ASM_BRIDGE,
+ ARG_ASM_ZONE,
+ ARG_ASM_TPORT_ADDRESS,
+};
+
+static int tport_setup(const char *address, asm_data_t *ctx);
+
+static void *u_to_p(uint32_t u)
+{
+#ifdef __SIZEOF_POINTER__
+#if __SIZEOF_POINTER__ == 8
+ uint64_t o = u;
+#else
+ uint32_t o = u;
+#endif
+#else
+ uint32_t o = o;
+#endif
+ return (void *) o;
+}
+
+static uint32_t p_to_u(const void *p)
+{
+#ifdef __SIZEOF_POINTER__
+#if __SIZEOF_POINTER__ == 8
+ uint32_t o = 0;
+ uint64_t big = (uint64_t) p;
+ o = big & 0xffffffff;
+#else
+ uint32_t o = (uint32_t) p;
+#endif
+#else
+ uint32_t o = p;
+#endif
+ return o;
+}
+
+
+static int int_comp(const void *key1, const void *key2)
+{
+ return key1 != key2;
+}
+
+
+static uint32_t int_hash(const void *key)
+{
+ return p_to_u(key);
+}
+
+
+static void dump_incoming_msg(lib_to_asm_t *msg, asm_data_t *ctx)
+{
+ MRP_UNUSED(ctx);
+
+ mrp_log_info(" --> client id: %u", msg->instance_id);
+ mrp_log_info(" --> data handle: %d", msg->handle);
+ mrp_log_info(" --> request id: 0x%04x", msg->request_id);
+ mrp_log_info(" --> sound event: 0x%04x", msg->sound_event);
+ mrp_log_info(" --> system resource: 0x%04x", msg->system_resource);
+ mrp_log_info(" --> state: 0x%04x", msg->sound_state);
+#ifdef USE_SECURITY
+ {
+ int n_cookie = msg->n_cookie_bytes;
+ int i;
+
+ mrp_log_info(" --> cookie: ")
+ for (i = 0; i < n_cookie, i++) {
+ mrp_log_info("0x%02x ", msg->cookie[i]);
+ }
+ mrp_log_info("\n");
+ }
+#endif
+}
+
+
+
+static void dump_outgoing_msg(asm_to_lib_t *msg, asm_data_t *ctx)
+{
+ MRP_UNUSED(ctx);
+
+ mrp_log_info(" <-- client id: %u", msg->instance_id);
+ mrp_log_info(" <-- alloc handle: %d", msg->alloc_handle);
+ mrp_log_info(" <-- command handle: %d", msg->cmd_handle);
+ mrp_log_info(" <-- sound command: 0x%04x", msg->result_sound_command);
+ mrp_log_info(" <-- state: 0x%04x", msg->result_sound_state);
+ mrp_log_info(" <-- check privilege: %s",
+ msg->check_privilege ? "TRUE" : "FALSE");
+}
+
+#if 0
+static uint32_t encode_pid_handle(uint32_t pid, uint32_t handle) {
+
+ uint32_t max_pid = 4194304; /* 2^22 */
+ uint32_t max_handle = 1024; /* 2^10 */
+
+ if (pid > max_pid || handle > max_handle) {
+ return 0;
+ }
+
+ return pid | (handle << 22);
+}
+
+static uint32_t get_pid(uint32_t data) {
+ uint32_t pid_mask = 0xffffffff >> 10;
+
+ return data & pid_mask;
+}
+
+
+static uint32_t get_handle(uint32_t data) {
+
+ return data >> 22;
+}
+#endif
+
+
+static void htbl_free_set(void *key, void *object)
+{
+ resource_set_data_t *d = object;
+
+ MRP_UNUSED(key);
+
+ mrp_resource_set_destroy(d->rset);
+
+ mrp_free(d);
+}
+
+
+static client_t *create_client(uint32_t pid) {
+ client_t *client = mrp_allocz(sizeof(client_t));
+ mrp_htbl_config_t set_conf;
+
+ if (!client)
+ return NULL;
+
+ set_conf.comp = int_comp;
+ set_conf.hash = int_hash;
+ set_conf.free = htbl_free_set;
+ set_conf.nbucket = 0;
+ set_conf.nentry = 10;
+
+ client->sets = mrp_htbl_create(&set_conf);
+
+ if (!client->sets) {
+ mrp_free(client);
+ return NULL;
+ }
+
+ client->pid = pid;
+ client->current_handle = 1;
+ client->n_sets = 0;
+
+ return client;
+}
+
+
+static void event_cb(uint32_t request_id, mrp_resource_set_t *set, void *data)
+{
+ resource_set_data_t *d = data;
+ asm_data_t *ctx = d->ctx;
+
+ mrp_log_info("Event CB: id %u, set %p", request_id, set);
+ mrp_log_info("Resource set %u.%u", d->pid, d->handle);
+ mrp_log_info("Advice 0x%08x, Grant 0x%08x",
+ mrp_get_resource_set_advice(d->rset),
+ mrp_get_resource_set_grant(d->rset));
+
+
+ switch(d->rtype) {
+ case request_type_acquire:
+ {
+ asm_to_lib_t reply;
+ mrp_log_info("callback for acquire request %u", request_id);
+
+ /* expecting next server events */
+ d->rtype = request_type_server_event;
+
+ reply.instance_id = d->pid;
+ reply.check_privilege = FALSE;
+ reply.alloc_handle = d->handle;
+ reply.cmd_handle = d->handle;
+
+ reply.result_sound_command = ASM_COMMAND_NONE;
+
+ /* TODO: check the mask properly */
+ if (mrp_get_resource_set_grant(d->rset))
+ reply.result_sound_state = ASM_STATE_PLAYING;
+ else
+ reply.result_sound_state = ASM_STATE_STOP;
+
+ d->rtype = request_type_server_event;
+
+ dump_outgoing_msg(&reply, ctx);
+ mrp_transport_senddata(d->ctx->t, &reply, TAG_ASM_TO_LIB);
+ break;
+ }
+ case request_type_release:
+ {
+ asm_to_lib_t reply;
+ mrp_log_info("callback for release request %u", request_id);
+
+ /* expecting next server events */
+ d->rtype = request_type_server_event;
+
+ reply.instance_id = d->pid;
+ reply.check_privilege = FALSE;
+ reply.alloc_handle = d->handle;
+ reply.cmd_handle = d->handle;
+
+ reply.result_sound_command = ASM_COMMAND_NONE;
+ reply.result_sound_state = ASM_STATE_STOP;
+
+ d->rtype = request_type_server_event;
+
+ dump_outgoing_msg(&reply, ctx);
+ mrp_transport_senddata(d->ctx->t, &reply, TAG_ASM_TO_LIB);
+ break;
+ }
+ case request_type_server_event:
+ {
+ asm_to_lib_cb_t reply;
+ mrp_log_info("callback for no request %u", request_id);
+
+ reply.instance_id = d->pid;
+ reply.handle = d->handle;
+ reply.callback_expected = FALSE;
+
+ if (mrp_get_resource_set_grant(d->rset))
+ reply.sound_command = ASM_COMMAND_PLAY;
+ else
+ reply.sound_command = ASM_COMMAND_STOP;
+
+ /* FIXME: the player-player case needs to be solved here? */
+ reply.event_source = ASM_EVENT_SOURCE_RESOURCE_CONFLICT;
+
+ mrp_transport_senddata(d->ctx->t, &reply, TAG_ASM_TO_LIB_CB);
+
+ break;
+ }
+ }
+}
+
+
+static asm_to_lib_t *process_msg(lib_to_asm_t *msg, asm_data_t *ctx)
+{
+ pid_t pid = msg->instance_id;
+
+ asm_to_lib_t *reply;
+
+ reply = mrp_allocz(sizeof(asm_to_lib_t));
+
+ reply->instance_id = pid;
+ reply->check_privilege = FALSE;
+
+ reply->alloc_handle = msg->handle;
+ reply->cmd_handle = msg->handle;
+
+ reply->result_sound_command = ASM_COMMAND_NONE;
+ reply->result_sound_state = ASM_STATE_IGNORE;
+
+ switch(msg->request_id) {
+ case ASM_REQUEST_REGISTER:
+ {
+ client_t *client;
+ bool shared = FALSE;
+ char *resource = "invalid";
+
+ mrp_log_info("REQUEST: REGISTER");
+
+ /* see if the process already has a client object */
+ client = mrp_htbl_lookup(ctx->clients, u_to_p(pid));
+
+ if (!client) {
+ client = create_client(pid);
+ mrp_htbl_insert(ctx->clients, u_to_p(pid), client);
+ }
+#if 1
+ else {
+ /* From Murphy point of view this is actually an error case,
+ * since the application can only belong to one class. This is
+ * a Murphy limitation and should be fixed later. */
+
+ mrp_log_error("Application tried to register twice");
+ goto error;
+ }
+#endif
+
+ switch (msg->sound_event) {
+ case ASM_EVENT_NONE:
+ break;
+ case ASM_EVENT_SHARE_MMPLAYER:
+ resource = "player";
+ shared = TRUE;
+ break;
+ case ASM_EVENT_SHARE_MMCAMCORDER:
+ resource = "camera";
+ shared = TRUE;
+ break;
+ case ASM_EVENT_SHARE_MMSOUND:
+ resource = "sound";
+ shared = TRUE;
+ break;
+ case ASM_EVENT_SHARE_OPENAL:
+ shared = TRUE;
+ break;
+ case ASM_EVENT_SHARE_AVSYSTEM:
+ shared = TRUE;
+ break;
+ case ASM_EVENT_EXCLUSIVE_MMPLAYER:
+ resource = "player";
+ shared = FALSE;
+ break;
+ case ASM_EVENT_EXCLUSIVE_MMCAMCORDER:
+ resource = "camera";
+ shared = FALSE;
+ break;
+ case ASM_EVENT_EXCLUSIVE_MMSOUND:
+ resource = "sound";
+ shared = FALSE;
+ break;
+ case ASM_EVENT_EXCLUSIVE_OPENAL:
+ shared = FALSE;
+ break;
+ case ASM_EVENT_EXCLUSIVE_AVSYSTEM:
+ shared = FALSE;
+ break;
+ case ASM_EVENT_NOTIFY:
+ shared = FALSE;
+ break;
+ case ASM_EVENT_CALL:
+ resource = "phone";
+ shared = FALSE;
+ break;
+ case ASM_EVENT_SHARE_FMRADIO:
+ shared = TRUE;
+ break;
+ case ASM_EVENT_EXCLUSIVE_FMRADIO:
+ shared = FALSE;
+ break;
+ case ASM_EVENT_EARJACK_UNPLUG:
+ mrp_log_info("earjack unplug event");
+ break;
+ case ASM_EVENT_ALARM:
+ shared = FALSE;
+ break;
+ case ASM_EVENT_VIDEOCALL:
+ resource = "phone";
+ shared = FALSE;
+ break;
+ case ASM_EVENT_MONITOR:
+ break;
+ case ASM_EVENT_RICH_CALL:
+ resource = "phone";
+ shared = FALSE;
+ break;
+ default:
+ break;
+ }
+
+ if (strcmp(resource, "invalid") == 0) {
+ mrp_log_error("unknown resource type: %d", msg->sound_event);
+ goto error;
+ }
+
+ else {
+ uint32_t handle = client->current_handle++;
+ mrp_resource_set_t *set;
+ resource_set_data_t *d = mrp_allocz(sizeof(resource_set_data_t));
+
+ d->handle = handle;
+ d->ctx = ctx;
+ d->pid = pid;
+ d->rtype = request_type_server_event;
+ d->request_id = 0;
+
+ set = mrp_resource_set_create(ctx->resource_client, 0, 0,
+ event_cb, d);
+
+ if (!set) {
+ mrp_log_error("Failed to create resource set!");
+ goto error;
+ }
+
+ d->rset = set;
+
+ mrp_resource_set_add_resource(set, "audio_playback", shared, NULL, TRUE);
+ mrp_resource_set_add_resource(set, "audio_record", shared, NULL, TRUE);
+
+ mrp_application_class_add_resource_set(resource, ctx->zone, set, 0);
+
+ mrp_htbl_insert(client->sets, u_to_p(handle), d);
+ client->n_sets++;
+
+ reply->alloc_handle = handle;
+ reply->cmd_handle = reply->alloc_handle;
+
+ reply->result_sound_state = ASM_STATE_WAITING;
+ reply->result_sound_command = ASM_COMMAND_NONE;
+ }
+
+ break;
+ }
+ case ASM_REQUEST_UNREGISTER:
+ {
+ client_t *client = mrp_htbl_lookup(ctx->clients, u_to_p(pid));
+
+ mrp_log_info("REQUEST: UNREGISTER");
+
+ if (client) {
+ resource_set_data_t *d;
+
+ d = mrp_htbl_lookup(client->sets, u_to_p(msg->handle));
+ if (!d || !d->rset) {
+ mrp_log_error("set '%u.%u' not found", pid, msg->handle);
+ goto error;
+ }
+
+ /* the resource set id destroyed when it's removed from the
+ * table */
+ mrp_htbl_remove(client->sets, u_to_p(msg->handle), TRUE);
+ client->n_sets--;
+
+ if (client->n_sets <= 0) {
+ mrp_htbl_remove(ctx->clients, u_to_p(pid), TRUE);
+ client = NULL;
+ }
+ }
+
+ /* TODO: free memory and check if the resource set is empty when
+ * the resource library supports it */
+
+ /* no reply needed! */
+ goto noreply;
+
+ break;
+ }
+ case ASM_REQUEST_SETSTATE:
+ {
+ client_t *client = mrp_htbl_lookup(ctx->clients, u_to_p(pid));
+
+ resource_set_data_t *d;
+
+ mrp_log_info("REQUEST: SET STATE");
+
+ if (!client) {
+ mrp_log_error("client '%u' not found", pid);
+ goto error;
+ }
+
+ d = mrp_htbl_lookup(client->sets, u_to_p(msg->handle));
+ if (!d || !d->rset) {
+ mrp_log_error("set '%u.%u' not found", pid, msg->handle);
+ goto error;
+ }
+
+ d->request_id = ++ctx->current_request;
+
+ switch(msg->sound_state) {
+ case ASM_STATE_PLAYING:
+ {
+ d->rtype = request_type_acquire;
+
+ mrp_log_info("requesting acquisition of playback rights"
+ " for set '%u.%u' (id: %u)", pid, msg->handle,
+ d->request_id);
+
+ mrp_resource_set_acquire(d->rset, d->request_id);
+
+ break;
+ }
+ case ASM_STATE_STOP:
+ {
+ d->rtype = request_type_release;
+
+ mrp_log_info("requesting release of playback rights for"
+ " set '%u.%u' (id: %u)", pid, msg->handle,
+ d->request_id);
+
+ mrp_resource_set_release(d->rset, d->request_id);
+
+ break;
+ }
+ default:
+ {
+ mrp_log_error("Unknown state: %d", msg->sound_state);
+ }
+ }
+
+ goto noreply;
+
+ break;
+ }
+ case ASM_REQUEST_GETSTATE:
+ mrp_log_info("REQUEST: GET STATE");
+ /* TODO: get the current resource state for msg->sound_event (which
+ * is the application class). Put it to reply->result_sound_state
+ * field. */
+ break;
+ case ASM_REQUEST_GETMYSTATE:
+ mrp_log_info("REQUEST: GET MY STATE");
+ /* TODO: get the current state for the process (resource set). Put
+ * it to reply->result_sound_state field. */
+ break;
+ case ASM_REQUEST_EMERGENT_EXIT:
+ {
+ client_t *client = mrp_htbl_lookup(ctx->clients, u_to_p(pid));
+
+ mrp_log_info("REQUEST: EMERGENCY EXIT");
+
+ if (!client) {
+ mrp_log_error("client '%u' not found", pid);
+ goto noreply;
+ }
+
+ mrp_htbl_remove(ctx->clients, u_to_p(pid), TRUE);
+
+ goto noreply;
+ break;
+ }
+ case ASM_REQUEST_SET_SUBSESSION:
+ mrp_log_info("REQUEST: SET SUBSESSION");
+ break;
+ case ASM_REQUEST_GET_SUBSESSION:
+ mrp_log_info("REQUEST: GET SUBSESSION");
+ break;
+ default:
+ mrp_log_info("REQUEST: UNKNOWN REQUEST");
+ break;
+ }
+
+ return reply;
+
+error:
+noreply:
+
+ mrp_free(reply);
+ return NULL;
+}
+
+
+static void process_cb_msg(lib_to_asm_cb_t *msg, asm_data_t *ctx)
+{
+ const char *str;
+
+ MRP_UNUSED(ctx);
+
+ /* TODO: this function might tell something to the resource library */
+
+ switch (msg->cb_result) {
+ case ASM_CB_RES_IGNORE:
+ str = "ignore";
+ break;
+ case ASM_CB_RES_NONE:
+ str = "none";
+ break;
+ case ASM_CB_RES_PAUSE:
+ str = "pause";
+ break;
+ case ASM_CB_RES_PLAYING:
+ str = "playing";
+ break;
+ case ASM_CB_RES_STOP:
+ str = "stop";
+ break;
+ default:
+ mrp_log_error("unknown callback state %d", msg->cb_result);
+ return;
+ }
+
+ mrp_log_info("client %d.%u ended in state '%s' after callback",
+ msg->instance_id, msg->handle, str);
+}
+
+
+static void recvdatafrom_evt(mrp_transport_t *t, void *data, uint16_t tag,
+ mrp_sockaddr_t *addr, socklen_t addrlen, void *user_data)
+{
+ asm_data_t *ctx = user_data;
+
+ MRP_UNUSED(addr);
+ MRP_UNUSED(addrlen);
+
+ switch (tag) {
+ case TAG_LIB_TO_ASM:
+ {
+ lib_to_asm_t *msg = data;
+ asm_to_lib_t *reply;
+
+ /* client requests something from us */
+
+ dump_incoming_msg(msg, ctx);
+
+ reply = process_msg(msg, ctx);
+ if (reply) {
+ dump_outgoing_msg(reply, ctx);
+ mrp_transport_senddata(t, reply, TAG_ASM_TO_LIB);
+ }
+ break;
+ }
+ case TAG_LIB_TO_ASM_CB:
+ {
+ lib_to_asm_cb_t *msg = data;
+
+ /* client tells us which state it entered after preemption */
+
+ process_cb_msg(msg, ctx);
+ break;
+ }
+
+ default:
+ mrp_log_error("Unknown message received!");
+ break;
+ }
+
+ mrp_data_free(data, tag);
+}
+
+
+static void recvdata_evt(mrp_transport_t *t, void *data, uint16_t tag, void *user_data)
+{
+ recvdatafrom_evt(t, data, tag, NULL, 0, user_data);
+}
+
+
+
+static void closed_evt(mrp_transport_t *t, int error, void *user_data)
+{
+#if 1
+ asm_data_t *ctx = user_data;
+
+ MRP_UNUSED(error);
+
+ mrp_log_info("closed!");
+
+ mrp_transport_disconnect(t);
+ mrp_transport_destroy(t);
+
+ ctx->t = NULL;
+
+ /* TODO: start the listening socket again and relaunch the binary? */
+#endif
+}
+
+
+static void connection_evt(mrp_transport_t *lt, void *user_data)
+{
+ asm_data_t *ctx = user_data;
+
+ mrp_log_info("connection!");
+
+ if (ctx->t) {
+ mrp_log_error("Already connected");
+ }
+ else {
+ ctx->t = mrp_transport_accept(lt, ctx, 0);
+ }
+
+ /* close the listening socket, since we only have one client */
+
+ mrp_transport_destroy(lt);
+ ctx->mt = NULL;
+}
+
+
+
+static int tport_setup(const char *address, asm_data_t *ctx)
+{
+ const char *atype;
+ ssize_t alen;
+ mrp_sockaddr_t addr;
+
+ struct stat statbuf;
+
+ static mrp_transport_evt_t evt = {
+ { .recvdata = recvdata_evt },
+ { .recvdatafrom = recvdatafrom_evt },
+ .closed = closed_evt,
+ .connection = connection_evt
+ };
+
+ alen = mrp_transport_resolve(NULL, address, &addr, sizeof(addr), &atype);
+
+ if (alen <= 0) {
+ mrp_log_error("Error resolving transport address");
+ goto error;
+ }
+
+ /* remove the old socket if present */
+
+ if (strcmp(atype, "unxs") == 0) {
+ char *path = addr.unx.sun_path;
+ if (path[0] == '/') {
+ /* if local socket and file exists, remove it */
+ if (stat(path, &statbuf) == 0) {
+ if (S_ISSOCK(statbuf.st_mode)) {
+ if (unlink(path) < 0) {
+ mrp_log_error("error removing the socket");
+ goto error;
+ }
+ }
+ else {
+ mrp_log_error("a file where the socket should be created");
+ goto error;
+ }
+ }
+ }
+ }
+
+ ctx->mt = mrp_transport_create(ctx->ctx->ml, atype, &evt, ctx,
+ MRP_TRANSPORT_MODE_CUSTOM | MRP_TRANSPORT_NONBLOCK);
+
+ if (ctx->mt == NULL) {
+ mrp_log_error("Failed to create the transport");
+ goto error;
+ }
+
+ if (!mrp_transport_bind(ctx->mt, &addr, alen)) {
+ mrp_log_error("Failed to bind the transport to address '%s'", address);
+ goto error;
+ }
+
+
+ if (!mrp_transport_listen(ctx->mt, 5)) {
+ mrp_log_error("Failed to listen to transport");
+ goto error;
+ }
+
+ return 0;
+
+error:
+ if (ctx->mt) {
+ mrp_transport_destroy(ctx->mt);
+ ctx->mt = NULL;
+ }
+
+ return -1;
+}
+
+static void signal_handler(mrp_mainloop_t *ml, mrp_sighandler_t *h,
+ int signum, void *user_data)
+{
+ asm_data_t *ctx = user_data;
+
+ MRP_UNUSED(ml);
+ MRP_UNUSED(h);
+
+ if (signum == SIGCHLD) {
+ /* wait for the child */
+ if (ctx->pid > 0) {
+ int ret;
+
+ mrp_log_info("Received SIGCHLD, waiting for asm-bridge");
+
+ ret = waitpid(ctx->pid, NULL, WNOHANG);
+
+ if (ret == ctx->pid) {
+ mrp_log_warning("asm-bridge process died");
+ ctx->pid = 0;
+ }
+ }
+ }
+}
+
+static void htbl_free_client(void *key, void *object)
+{
+ MRP_UNUSED(key);
+
+ client_t *client = object;
+
+ mrp_htbl_destroy(client->sets, TRUE);
+
+ /* TODO: free memory when resource API allows that */
+ mrp_free(client);
+}
+
+static int asm_init(mrp_plugin_t *plugin)
+{
+ mrp_plugin_arg_t *args = plugin->args;
+ asm_data_t *ctx = mrp_allocz(sizeof(asm_data_t));
+ pid_t pid;
+ mrp_htbl_config_t client_conf;
+
+ if (!ctx) {
+ goto error;
+ }
+
+ ctx->ctx = plugin->ctx;
+ ctx->address = args[ARG_TPORT_ADDRESS].str;
+ ctx->binary = args[ARG_ASM_BRIDGE].str;
+ ctx->zone = args[ARG_ASM_ZONE].str;
+
+ /* create the transport and put it to listen mode */
+
+ if (!mrp_msg_register_type(&asm_to_lib_descr)) {
+ mrp_log_error("Failed to register message type asm_to_lib");
+ goto error;
+ }
+
+ if (!mrp_msg_register_type(&lib_to_asm_descr)) {
+ mrp_log_error("Failed to register message type lib_to_asm");
+ goto error;
+ }
+
+ if (!mrp_msg_register_type(&asm_to_lib_cb_descr)) {
+ mrp_log_error("Failed to register message type asm_to_lib_cb");
+ goto error;
+ }
+
+ if (!mrp_msg_register_type(&lib_to_asm_cb_descr)) {
+ mrp_log_error("Failed to register message type lib_to_asm_cb");
+ goto error;
+ }
+
+ if (tport_setup(ctx->address, ctx) < 0) {
+ goto error;
+ }
+
+ /* listen to SIGCHLD signal */
+
+ ctx->sighandler = mrp_add_sighandler(plugin->ctx->ml, SIGCHLD, signal_handler, ctx);
+
+ if (!ctx->sighandler) {
+ mrp_log_error("Failed to register signal handling");
+ goto error;
+ }
+
+ client_conf.comp = int_comp;
+ client_conf.hash = int_hash;
+ client_conf.free = htbl_free_client;
+ client_conf.nbucket = 0;
+ client_conf.nentry = 10;
+
+ ctx->clients = mrp_htbl_create(&client_conf);
+
+ if (!ctx->clients) {
+ mrp_log_error("Error creating resource set hash table");
+ goto error;
+ }
+
+ /* create the client structure towards Murphy */
+
+ ctx->resource_client = mrp_resource_client_create("ASM", ctx);
+
+ if (!ctx->resource_client) {
+ mrp_log_error("Failed to get a resource client");
+ goto error;
+ }
+
+ /* fork-exec the asm bridge binary */
+
+ mrp_log_info("going to fork!");
+
+ pid = fork();
+
+ if (pid < 0) {
+ mrp_log_error("error launching asm-bridge");
+ goto error;
+ }
+ else if (pid == 0) {
+ /* child */
+ execl(ctx->binary, ctx->binary, ctx->address, NULL);
+ exit(1);
+ }
+ else {
+ /* parent */
+ ctx->pid = pid;
+ mrp_log_info("child pid is %d", pid);
+ }
+
+ plugin->data = ctx;
+
+ return TRUE;
+
+error:
+
+ if (ctx->pid) {
+ kill(ctx->pid, SIGTERM);
+ ctx->pid = 0;
+ }
+
+ if (ctx->sighandler) {
+ mrp_del_sighandler(ctx->sighandler);
+ ctx->sighandler = NULL;
+ }
+
+ if (ctx->resource_client) {
+ mrp_resource_client_destroy(ctx->resource_client);
+ }
+
+ mrp_free(ctx);
+
+ return FALSE;
+}
+
+
+static void asm_exit(mrp_plugin_t *plugin)
+{
+ asm_data_t *ctx = plugin->data;
+
+ if (ctx->pid) {
+ kill(ctx->pid, SIGTERM);
+ ctx->pid = 0;
+ }
+
+ if (ctx->mt) {
+ mrp_transport_disconnect(ctx->mt);
+ mrp_transport_destroy(ctx->mt);
+ ctx->mt = NULL;
+ }
+
+ if (ctx->t) {
+ mrp_transport_disconnect(ctx->t);
+ mrp_transport_destroy(ctx->t);
+ ctx->t = NULL;
+ }
+
+ if (ctx->sighandler) {
+ mrp_del_sighandler(ctx->sighandler);
+ ctx->sighandler = NULL;
+ }
+
+ if (ctx->clients) {
+ mrp_htbl_destroy(ctx->clients, TRUE);
+ ctx->clients = NULL;
+ }
+
+ mrp_resource_client_destroy(ctx->resource_client);
+
+ mrp_free(ctx);
+ plugin->data = NULL;
+}
+
+
+#define ASM_DESCRIPTION "A plugin to handle SLP Audio Session Manager client requests."
+#define ASM_HELP "Audio Session Manager backend"
+#define ASM_VERSION MRP_VERSION_INT(0, 0, 1)
+#define ASM_AUTHORS "Ismo Puustinen <ismo.puustinen@intel.com>"
+
+static mrp_plugin_arg_t args[] = {
+ MRP_PLUGIN_ARGIDX(ARG_ASM_BRIDGE, STRING, "asm_bridge", "/usr/sbin/asm-bridge"),
+ MRP_PLUGIN_ARGIDX(ARG_ASM_ZONE, STRING, "zone", "default"),
+ MRP_PLUGIN_ARGIDX(ARG_ASM_TPORT_ADDRESS, STRING, "tport_address", "unxs:/tmp/murphy/asm"),
+};
+
+
+MURPHY_REGISTER_PLUGIN("resource-asm",
+ ASM_VERSION, ASM_DESCRIPTION, ASM_AUTHORS, ASM_HELP,
+ MRP_SINGLETON, asm_init, asm_exit,
+ args, MRP_ARRAY_SIZE(args),
+ NULL, 0, NULL, 0, NULL);
--- /dev/null
+/*
+ * Copyright (c) 2012, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Intel Corporation nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <pthread.h>
+
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+
+#include <signal.h>
+
+#include <audio-session-manager.h>
+
+#include <murphy/common.h>
+
+#include "asm-bridge.h"
+
+
+typedef struct ctx_s {
+ mrp_mainloop_t *ml;
+ mrp_transport_t *mt;
+ int snd_msgq;
+ mrp_htbl_t *watched_files;
+} ctx_t;
+
+struct watched_file {
+ char *watched_file;
+ mrp_io_watch_t *wd;
+ int32_t instance_id;
+ uint32_t handle;
+ ctx_t *ctx;
+};
+
+static void *wait_queue (void *arg) {
+ ASM_msg_lib_to_asm_t msg;
+
+ int *arg_thread = arg;
+
+ int asm_rcv_msgid = arg_thread[0];
+ int fd = arg_thread[1];
+
+ if (asm_rcv_msgid == -1) {
+ mrp_log_error("failed to create the receive message queue\n");
+ exit(1);
+ }
+
+ while (1) {
+ int ret = msgrcv(asm_rcv_msgid, &msg, sizeof(msg.data), 0, 0);
+
+ if (ret < 0) {
+ /* FIXME: proper error handling */
+ mrp_log_error("error receiving a message!");
+ continue;
+ }
+
+ /* alignment is fine, since the first argument to the struct is a long */
+ write(fd, &msg, sizeof(ASM_msg_lib_to_asm_t));
+ }
+
+ return NULL;
+}
+
+
+static void dump_msg(ASM_msg_lib_to_asm_t *msg, ctx_t *ctx)
+{
+ MRP_UNUSED(ctx);
+
+ mrp_log_info("Message id %ld:", msg->instance_id);
+
+ mrp_log_info("Data handle: %d", msg->data.handle);
+ mrp_log_info(" request id: 0x%04x", msg->data.request_id);
+ mrp_log_info(" sound event: 0x%04x", msg->data.sound_event);
+ mrp_log_info(" sound state: 0x%04x", msg->data.sound_state);
+ mrp_log_info(" system resource: 0x%04x", msg->data.system_resource);
+#ifdef USE_SECURITY
+ {
+ int i;
+
+ mrp_log_info(" cookie: ")
+ for (i = 0; i < COOKIE_SIZE, i++) {
+ mrp_log_info("0x%02x ", msg->data.cookie[i]);
+ }
+ mrp_log_info("\n");
+ }
+#endif
+}
+
+
+static int process_msg(ASM_msg_lib_to_asm_t *msg, ctx_t *ctx)
+{
+ lib_to_asm_t res;
+ uint8_t cookie_arr[] = {};
+ int cookie_len = 0;
+
+ dump_msg(msg, ctx);
+
+ /* FIXME: instance_id is signed? */
+ res.instance_id = msg->instance_id;
+ res.handle = msg->data.handle;
+ res.request_id = msg->data.request_id;
+ res.sound_event = msg->data.sound_event;
+ res.sound_state = msg->data.sound_state;
+ res.system_resource = msg->data.system_resource;
+#ifdef USE_SECURITY
+ {
+ cookie_len = strlen(msg->data.cookie);
+ cookie_arr = msg->data.cookie;
+
+ res.n_cookie_bytes = cookie_len;
+ res.cookie = cookie_arr;
+ }
+#endif
+
+ res.n_cookie_bytes = cookie_len;
+ res.cookie = cookie_arr;
+
+ if (!mrp_transport_senddata(ctx->mt, &res, lib_to_asm_descr.tag)) {
+ mrp_log_error("Failed to send message to murphy");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static void pipe_cb(mrp_mainloop_t *ml, mrp_io_watch_t *w, int fd,
+ mrp_io_event_t events, void *user_data)
+{
+ ASM_msg_lib_to_asm_t msg;
+ ctx_t *ctx = user_data;
+ int bytes;
+ int ret;
+
+ MRP_UNUSED(ml);
+ MRP_UNUSED(w);
+ MRP_UNUSED(events);
+
+ bytes = read(fd, &msg, sizeof(ASM_msg_lib_to_asm_t));
+
+ if (bytes != sizeof(ASM_msg_lib_to_asm_t)) {
+ mrp_log_error("failed to read from the pipe");
+ return;
+ }
+
+ ret = process_msg(&msg, ctx);
+
+ if (ret < 0) {
+ mrp_log_error("error parsing or proxying message");
+ }
+}
+
+
+static void read_watch_cb(mrp_mainloop_t *ml, mrp_io_watch_t *w, int fd,
+ mrp_io_event_t events, void *user_data)
+{
+ struct watched_file *wf = user_data;
+ ctx_t *ctx = wf->ctx;
+
+ MRP_UNUSED(ml);
+ MRP_UNUSED(w);
+
+ if (events & MRP_IO_EVENT_IN) {
+ uint32_t buf;
+ int ret;
+
+ ret = read(fd, &buf, sizeof(uint32_t));
+
+ if (ret == sizeof(uint32_t)) {
+ lib_to_asm_cb_t msg;
+
+ msg.instance_id = wf->instance_id;
+ msg.handle = wf->handle;
+ msg.cb_result = buf;
+
+ if (!mrp_transport_senddata(ctx->mt, &msg, lib_to_asm_cb_descr.tag)) {
+ mrp_log_error("Failed to send message to murphy");
+ }
+ }
+ }
+ if (events & MRP_IO_EVENT_HUP) {
+ /* can we assume that the client went away? */
+ mrp_log_error("HUP event from client");
+ }
+
+ mrp_htbl_remove(ctx->watched_files, wf->watched_file, TRUE);
+ close(fd);
+}
+
+
+static int send_callback_to_client(asm_to_lib_cb_t *msg, ctx_t *ctx)
+{
+#define ASM_FILENAME_SIZE 64
+ char wr_filename[ASM_FILENAME_SIZE];
+ char rd_filename[ASM_FILENAME_SIZE];
+
+ int wr_fd = -1;
+ int rd_fd = -1;
+ uint32_t data;
+ int ret;
+
+ struct watched_file *wf = NULL;
+
+ snprintf(wr_filename, ASM_FILENAME_SIZE, "/tmp/ASM.%d.%u",
+ msg->instance_id, msg->handle);
+
+ mrp_log_info("writing client preemption to file %s", wr_filename);
+
+ wr_fd = open(wr_filename, O_NONBLOCK | O_WRONLY);
+ if (wr_fd < 0) {
+ mrp_log_error("failed to open file '%s' for writing", wr_filename);
+ goto error;
+ }
+
+ if (msg->callback_expected) {
+
+ snprintf(rd_filename, ASM_FILENAME_SIZE, "/tmp/ASM.%d.%ur",
+ msg->instance_id, msg->handle);
+ rd_fd = open(wr_filename, O_NONBLOCK | O_RDONLY);
+ if (rd_fd < 0) {
+ mrp_log_error("failed to open file '%s' for reading", rd_filename);
+ goto error;
+ }
+
+ wf = mrp_htbl_lookup(ctx->watched_files, rd_filename);
+
+ if (wf) {
+ /* already watched, this is a bad thing */
+
+ mrp_log_error("client %d.%u missed a callback notification",
+ msg->instance_id, msg->handle);
+ }
+ else {
+
+ wf = mrp_allocz(sizeof(struct watched_file));
+
+ wf->watched_file = mrp_strdup(rd_filename);
+ wf->ctx = ctx;
+ wf->instance_id = msg->instance_id;
+ wf->handle = msg->handle;
+ wf->wd = mrp_add_io_watch(ctx->ml, rd_fd, MRP_IO_EVENT_IN | MRP_IO_EVENT_HUP,
+ read_watch_cb, wf);
+
+ mrp_htbl_insert(ctx->watched_files, wf->watched_file, wf);
+ }
+ }
+
+ /* encode the data for sending */
+ data = 0x0000ffff;
+ data &= msg->handle;
+ data |= msg->sound_command << 16;
+ data |= msg->event_source << 24;
+
+ ret = write(wr_fd, &data, sizeof(uint32_t));
+
+ if (ret < (int) sizeof(uint32_t)) {
+ mrp_log_error("failed to write callback data to %d.%u",
+ msg->instance_id, msg->handle);
+ goto error;
+ }
+
+ mrp_log_error("Wrote data 0x%08x successfully to client", data);
+
+ close(wr_fd);
+
+ return 0;
+
+error:
+ if (wf && wf->watched_file) {
+ mrp_htbl_remove(ctx->watched_files, wf->watched_file, TRUE);
+ }
+
+ if (wr_fd >= 0) {
+ close(wr_fd);
+ }
+
+ if (rd_fd >= 0) {
+ close(wr_fd);
+ }
+
+ return -1;
+#undef ASM_FILENAME_SIZE
+}
+
+
+static void recvfrom_murphy(mrp_transport_t *t, void *data, uint16_t tag,
+ mrp_sockaddr_t *addr, socklen_t addrlen, void *user_data)
+{
+ ctx_t *ctx = user_data;
+
+ MRP_UNUSED(t);
+ MRP_UNUSED(addr);
+ MRP_UNUSED(addrlen);
+
+ switch (tag) {
+ case TAG_ASM_TO_LIB:
+ {
+ asm_to_lib_t *res = data;
+ ASM_msg_asm_to_lib_t msg;
+
+ msg.instance_id = res->instance_id;
+ msg.data.alloc_handle = res->alloc_handle;
+ msg.data.cmd_handle = res->cmd_handle;
+ msg.data.result_sound_command = res->result_sound_command;
+ msg.data.result_sound_state = res->result_sound_state;
+#ifdef USE_SECURITY
+ msg.data.check_privilege = res->check_privilege;
+#endif
+
+ if (msgsnd(ctx->snd_msgq, (void *) &msg,
+ sizeof(msg.data), 0) < 0) {
+ mrp_log_error("failed to send message to client");
+ }
+ break;
+ }
+
+ case TAG_ASM_TO_LIB_CB:
+ {
+ if (send_callback_to_client(data, ctx) < 0) {
+ mrp_log_error("failed to send callback message to client");
+ }
+ break;
+ }
+
+ default:
+ mrp_log_error("Unknown message received!");
+ break;
+ }
+}
+
+
+static void recv_murphy(mrp_transport_t *t, void *data, uint16_t tag, void *user_data)
+{
+ recvfrom_murphy(t, data, tag, NULL, 0, user_data);
+}
+
+
+static void closed_evt(mrp_transport_t *t, int error, void *user_data)
+{
+ ctx_t *ctx = user_data;
+
+ MRP_UNUSED(t);
+ MRP_UNUSED(error);
+
+ mrp_log_error("server closed the connection");
+
+ mrp_mainloop_quit(ctx->ml, 0);
+}
+
+
+static int connect_to_murphy(char *address, ctx_t *ctx)
+{
+ const char *atype;
+ ssize_t alen;
+ mrp_sockaddr_t addr;
+
+ static mrp_transport_evt_t evt = {
+ { .recvdata = recv_murphy },
+ { .recvdatafrom = recvfrom_murphy },
+ .closed = closed_evt,
+ .connection = NULL
+ };
+
+ if (!mrp_msg_register_type(&lib_to_asm_descr) ||
+ !mrp_msg_register_type(&asm_to_lib_descr) ||
+ !mrp_msg_register_type(&asm_to_lib_cb_descr) ||
+ !mrp_msg_register_type(&lib_to_asm_cb_descr)) {
+ mrp_log_error("Failed to register message types");
+ goto error;
+ }
+
+ alen = mrp_transport_resolve(NULL, address, &addr, sizeof(addr), &atype);
+
+ if (alen <= 0) {
+ mrp_log_error("Error resolving transport address");
+ goto error;
+ }
+
+ ctx->mt = mrp_transport_create(ctx->ml, atype, &evt, ctx,
+ MRP_TRANSPORT_MODE_CUSTOM | MRP_TRANSPORT_NONBLOCK);
+
+ if (ctx->mt == NULL) {
+ mrp_log_error("Failed to create the transport");
+ goto error;
+ }
+
+#if 0
+ if (!mrp_transport_bind(ctx->mt, &addr, alen)) {
+ mrp_log_error("Failed to bind the transport to address '%s'", address);
+ goto error;
+ }
+#endif
+
+ if (!mrp_transport_connect(ctx->mt, &addr, alen)) {
+ mrp_log_error("Failed to connect the transport");
+ goto error;
+ }
+
+ return 0;
+
+error:
+ if (ctx->mt)
+ mrp_transport_destroy(ctx->mt);
+
+ return -1;
+}
+
+static void htbl_free_watches(void *key, void *object)
+{
+ struct watched_file *wf = object;
+
+ MRP_UNUSED(key);
+
+ mrp_free(wf->watched_file);
+ if (wf->wd)
+ mrp_del_io_watch(wf->wd);
+
+ mrp_free(wf);
+}
+
+
+int main (int argc, char **argv)
+{
+ pthread_t thread = 0;
+ void *res;
+ int pipes[2];
+ int thread_arg[2];
+ mrp_io_watch_t *iow;
+ mrp_io_event_t events = MRP_IO_EVENT_IN;
+
+ int asm_snd_msgid = msgget((key_t)4102, 0666 | IPC_CREAT);
+ int asm_rcv_msgid = msgget((key_t)2014, 0666 | IPC_CREAT);
+
+ mrp_htbl_config_t watches_conf;
+
+ ctx_t ctx;
+
+ /* set up the signal handling */
+
+ if (asm_snd_msgid == -1 || asm_rcv_msgid == -1) {
+ mrp_log_error("failed to create the message queues\n");
+ goto end;
+ }
+
+ ctx.ml = NULL;
+ ctx.mt = NULL;
+ ctx.snd_msgq = asm_snd_msgid;
+
+ if (argc != 2 || strncmp(argv[1], "unxs", 4) != 0) {
+ mrp_log_error("Usage: asm-bridge <socket_name>");
+ goto end;
+ }
+
+ watches_conf.comp = mrp_string_comp;
+ watches_conf.hash = mrp_string_hash;
+ watches_conf.free = htbl_free_watches;
+ watches_conf.nbucket = 0;
+ watches_conf.nentry = 10;
+
+ ctx.watched_files = mrp_htbl_create(&watches_conf);
+
+ ctx.ml = mrp_mainloop_create();
+
+ /* Initialize connection to murphyd */
+
+ if (connect_to_murphy(argv[1], &ctx) < 0) {
+ goto end;
+ }
+
+ /* create a pipe for communicating with the ASM thread */
+
+ pipe(pipes);
+
+ /* pass the message queue and the pipe writing end to the thread */
+
+ thread_arg[0] = asm_rcv_msgid;
+ thread_arg[1] = pipes[1];
+
+ /* start listening to the read end of the pipe */
+
+ iow = mrp_add_io_watch(ctx.ml, pipes[0], events, pipe_cb, &ctx);
+
+ if (!iow) {
+ goto end;
+ }
+
+ pthread_create(&thread, NULL, wait_queue, thread_arg);
+
+ /* start processing events */
+
+ mrp_mainloop_run(ctx.ml);
+
+ mrp_log_warning("shutting down asm-bridge");
+
+end:
+ if (iow)
+ mrp_del_io_watch(iow);
+
+ if (ctx.watched_files) {
+ mrp_htbl_destroy(ctx.watched_files, TRUE);
+ }
+
+ if (thread) {
+ pthread_cancel(thread);
+ pthread_join(thread, &res);
+ }
+
+ /* free the message queues */
+
+ msgctl(asm_snd_msgid, IPC_RMID, 0);
+ msgctl(asm_rcv_msgid, IPC_RMID, 0);
+
+ exit(0);
+}
--- /dev/null
+/*
+ * Copyright (c) 2012, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Intel Corporation nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef MURPHY_ASM_BRIDGE_H
+#define MURPHY_ASM_BRIDGE_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#include <murphy/common.h>
+
+#define TAG_LIB_TO_ASM ((uint16_t) 0x100)
+#define TAG_ASM_TO_LIB ((uint16_t) 0x101)
+#define TAG_ASM_TO_LIB_CB ((uint16_t) 0x102)
+#define TAG_LIB_TO_ASM_CB ((uint16_t) 0x103)
+
+/* library requests something */
+
+typedef struct {
+ uint32_t instance_id;
+ int32_t handle;
+ uint32_t request_id;
+ uint32_t sound_event;
+ uint32_t sound_state;
+ uint32_t system_resource;
+ uint32_t n_cookie_bytes;
+ uint8_t *cookie;
+} lib_to_asm_t;
+
+/* server reply to library */
+
+typedef struct {
+ uint32_t instance_id;
+ int32_t alloc_handle;
+ int32_t cmd_handle;
+ uint32_t result_sound_command;
+ uint32_t result_sound_state;
+ bool check_privilege;
+} asm_to_lib_t;
+
+/* server sends a preemption command */
+
+typedef struct {
+ uint32_t instance_id;
+ int32_t handle;
+ bool callback_expected;
+ uint32_t sound_command; /* ASM_sound_commands_t */
+ uint32_t event_source; /* ASM_event_sources_t */
+} asm_to_lib_cb_t;
+
+/* library tells the state it landed in after preemption */
+
+typedef struct {
+ uint32_t instance_id;
+ int32_t handle;
+ uint32_t cb_result; /* ASM_cb_result_t */
+} lib_to_asm_cb_t;
+
+
+
+MRP_DATA_DESCRIPTOR(lib_to_asm_descr, TAG_LIB_TO_ASM, lib_to_asm_t,
+ MRP_DATA_MEMBER(lib_to_asm_t, instance_id, MRP_MSG_FIELD_UINT32),
+ MRP_DATA_MEMBER(lib_to_asm_t, handle, MRP_MSG_FIELD_INT32),
+ MRP_DATA_MEMBER(lib_to_asm_t, request_id, MRP_MSG_FIELD_UINT32),
+ MRP_DATA_MEMBER(lib_to_asm_t, sound_event, MRP_MSG_FIELD_UINT32),
+ MRP_DATA_MEMBER(lib_to_asm_t, sound_state, MRP_MSG_FIELD_UINT32),
+ MRP_DATA_MEMBER(lib_to_asm_t, system_resource, MRP_MSG_FIELD_UINT32),
+ MRP_DATA_MEMBER(lib_to_asm_t, n_cookie_bytes, MRP_MSG_FIELD_UINT32),
+ MRP_DATA_ARRAY_COUNT(lib_to_asm_t, cookie, n_cookie_bytes,
+ MRP_MSG_FIELD_UINT8));
+
+MRP_DATA_DESCRIPTOR(asm_to_lib_descr, TAG_ASM_TO_LIB, asm_to_lib_t,
+ MRP_DATA_MEMBER(asm_to_lib_t, instance_id, MRP_MSG_FIELD_UINT32),
+ MRP_DATA_MEMBER(asm_to_lib_t, alloc_handle, MRP_MSG_FIELD_INT32),
+ MRP_DATA_MEMBER(asm_to_lib_t, cmd_handle, MRP_MSG_FIELD_INT32),
+ MRP_DATA_MEMBER(asm_to_lib_t, result_sound_command, MRP_MSG_FIELD_UINT32),
+ MRP_DATA_MEMBER(asm_to_lib_t, result_sound_state, MRP_MSG_FIELD_UINT32),
+ MRP_DATA_MEMBER(asm_to_lib_t, check_privilege, MRP_MSG_FIELD_BOOL));
+
+MRP_DATA_DESCRIPTOR(asm_to_lib_cb_descr, TAG_ASM_TO_LIB_CB, asm_to_lib_cb_t,
+ MRP_DATA_MEMBER(asm_to_lib_cb_t, instance_id, MRP_MSG_FIELD_UINT32),
+ MRP_DATA_MEMBER(asm_to_lib_cb_t, handle, MRP_MSG_FIELD_INT32),
+ MRP_DATA_MEMBER(asm_to_lib_cb_t, callback_expected, MRP_MSG_FIELD_BOOL),
+ MRP_DATA_MEMBER(asm_to_lib_cb_t, sound_command, MRP_MSG_FIELD_UINT32),
+ MRP_DATA_MEMBER(asm_to_lib_cb_t, event_source, MRP_MSG_FIELD_UINT32));
+
+MRP_DATA_DESCRIPTOR(lib_to_asm_cb_descr, TAG_LIB_TO_ASM_CB, lib_to_asm_cb_t,
+ MRP_DATA_MEMBER(lib_to_asm_cb_t, instance_id, MRP_MSG_FIELD_UINT32),
+ MRP_DATA_MEMBER(lib_to_asm_cb_t, handle, MRP_MSG_FIELD_INT32),
+ MRP_DATA_MEMBER(lib_to_asm_cb_t, cb_result, MRP_MSG_FIELD_UINT32));
+
+
+#endif