echo "and then set installed Python/bin path into PATH system variable on your PC!"
exit 1
fi
--
++
PURIFIED_ROOTDIR=`TEMP=\`echo "${ROOTDIR}" | cut -c-2 | sed "s/[:/]//g" | awk {'print tolower ($_)'}\`; echo \`echo "${ROOTDIR}" | sed "s/^../\/${TEMP}/"\``
PATH=$PATH:$PURIFIED_ROOTDIR/bin:$PURIFIED_ROOTDIR/apache-ant_1.9.2/bin:$PURIFIED_ROOTDIR/SDL_1.2.15/bin:$PURIFIED_ROOTDIR/pixman_0.30.0/bin:$PURIFIED_ROOTDIR/gtk-bundle_2.24.10/bin:$PURIFIED_ROOTDIR/libcurl-4_1.0.1/bin
export PATH
--- /dev/null
-obj-y += ecs_msg.o ecs.o ecs_sensor.o
+ obj-y += genmsg/ecs.pb-c.o genmsg/ecs_ids.pb-c.o ../../distrib/protobuf/protobuf-c.o
++obj-y += ecs.o ecs_msg.o ecs_msg_injector.o ecs_msg_device.o
+ obj-y += ecs_mon.o ecs-json-streamer.o
+ obj-y += ecs_eventcast.o
++obj-y += ecs_sensor.o
++obj-y += ecs_nfc.o
#include "ecs-json-streamer.h"
#include "genmsg/ecs.pb-c.h"
#include "genmsg/ecs_ids.pb-c.h"
- #include "../osutil.h"
-#include "../util/osutil.h"
#define ECS_VERSION "1.0"
--- /dev/null
- send_to_ecp(&master);
+ /*
+ * Emulator Control Server - Device Tethering Handler
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * KiTae Kim <kt920.kim@samsung.com>
+ * JiHye Kim <jihye1128.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+ #include "ui/console.h"
+
+ #include "ecs.h"
+ #include "ecs_eventcast.h"
+ #include "eventcast/common.h"
+ #include "eventcast/sensor.h"
+ #include "eventcast/touch.h"
+ #include "hw/virtio/maru_virtio_touchscreen.h"
+ #include "hw/virtio/maru_virtio_hwkey.h"
+
+ #include "util/new_debug_ch.h"
+
+ DECLARE_DEBUG_CHANNEL(ecs_eventcast);
+
+ #define MSG_BUF_SIZE 255
+ #define MSG_LEN_SIZE 4
+
+ #define PRESSED 1
+ #define RELEASED 2
+
+ static bool send_eventcast_ntf(const char *data);
+ static void send_eventcast_status_ntf(type_group group, type_action action);
+
+ static int eventcast_port = 0;
+
+ void send_eventcast_sensor_status_ecp(void)
+ {
+ LOG_INFO(">> send eventcast_event_status to ecp\n");
+ send_eventcast_status_ntf(ECS_EVENTCAST_MSG_GROUP_ECP,
+ ECS_EVENTCAST_MSG_ACTION_SENSOR_STATUS);
+ }
+
+ void send_eventcast_touch_status_ecp(void)
+ {
+ send_eventcast_status_ntf(ECS_EVENTCAST_MSG_GROUP_ECP,
+ ECS_EVENTCAST_MSG_ACTION_TOUCH_STATUS);
+ }
+
+ void send_eventcast_connection_status_ecp(void)
+ {
+ LOG_INFO(">> send eventcast_connection_status to ecp\n");
+ send_eventcast_status_ntf(ECS_EVENTCAST_MSG_GROUP_ECP,
+ ECS_EVENTCAST_MSG_ACTION_CONNECTION_STATUS);
+ }
+
+ #if 0
+ static void send_eventcast_port_ecp(void)
+ {
+ type_length length;
+ type_group group = ECS_EVENTCAST_MSG_GROUP_ECP;
+ type_action action = ECS_EVENTCAST_MSG_ACTION_CONNECT;
+ uint8_t *msg = NULL;
+ gchar data[12];
+
+ msg = g_malloc(MSG_BUF_SIZE);
+ if (!msg) {
+ return;
+ }
+
+ LOG_TRACE(">> send port_num: %d\n", eventcast_port);
+ g_snprintf(data, sizeof(data) - 1, "%d", eventcast_port);
+ length = strlen(data);
+
+ memcpy(msg, ECS_EVENTCAST_MSG_CATEGORY, 10);
+ memcpy(msg + 10, &length, sizeof(unsigned short));
+ memcpy(msg + 12, &group, sizeof(unsigned char));
+ memcpy(msg + 13, &action, sizeof(unsigned char));
+ memcpy(msg + 14, data, length);
+
+ LOG_TRACE(">> send eventcast_ntf to ecp. action=%d, group=%d, data=%s\n",
+ action, group, data);
+
+ send_eventcast_ntf((const char *)msg);
+
+ if (msg) {
+ g_free(msg);
+ }
+ }
+ #endif
+
+ static void send_eventcast_connection_info(void)
+ {
+ type_length length;
+ type_group group = ECS_EVENTCAST_MSG_GROUP_ECP;
+ type_action action = ECS_EVENTCAST_MSG_ACTION_CONNECT;
+ uint8_t *msg = NULL;
+ gchar data[64];
+
+ msg = g_malloc(MSG_BUF_SIZE);
+ if (!msg) {
+ LOG_SEVERE("failed to allocate memory\n");
+ return;
+ }
+
+ LOG_INFO(">> send port_num: %d\n", eventcast_port);
+ {
+ const char *ip = get_eventcast_connected_ipaddr();
+ int port = get_eventcast_connected_port();
+
+ if (!ip) {
+ LOG_SEVERE("invalid connected ip\n");
+ return;
+ }
+
+ if (!port) {
+ LOG_SEVERE("invalid connected port\n");
+ return;
+ }
+ g_snprintf(data, sizeof(data) - 1, "%s:%d", ip, port);
+ length = strlen(data);
+ data[length] = '\0';
+ }
+
+ memcpy(msg, ECS_EVENTCAST_MSG_CATEGORY, 10);
+ memcpy(msg + 10, &length, sizeof(unsigned short));
+ memcpy(msg + 12, &group, sizeof(unsigned char));
+ memcpy(msg + 13, &action, sizeof(unsigned char));
+ memcpy(msg + 14, data, length);
+
+ LOG_INFO(">> send connection msg to ecp. "
+ "action=%d, group=%d, data=%s length=%d\n",
+ action, group, data, length);
+
+ send_eventcast_ntf((const char *)msg);
+
+ g_free(msg);
+ }
+
+ static void send_eventcast_status_ntf(type_group group, type_action action)
+ {
+ type_length length = 1;
+ int status = 0;
+ uint8_t *msg = NULL;
+ gchar data[2];
+
+ switch (action) {
+ case ECS_EVENTCAST_MSG_ACTION_CONNECTION_STATUS:
+ status = get_eventcast_connection_status();
+ if (status == CONNECTED) {
+ send_eventcast_connection_info();
+ }
+ break;
+ case ECS_EVENTCAST_MSG_ACTION_SENSOR_STATUS:
+ status = get_eventcast_sensor_status();
+ break;
+ case ECS_EVENTCAST_MSG_ACTION_TOUCH_STATUS:
+ status = get_eventcast_touch_status();
+ break;
+ default:
+ break;
+ }
+
+ msg = g_malloc(MSG_BUF_SIZE);
+ if (!msg) {
+ return;
+ }
+
+ g_snprintf(data, sizeof(data), "%d", status);
+
+ memcpy(msg, ECS_EVENTCAST_MSG_CATEGORY, 10);
+ memcpy(msg + 10, &length, sizeof(unsigned short));
+ memcpy(msg + 12, &group, sizeof(unsigned char));
+ memcpy(msg + 13, &action, sizeof(unsigned char));
+ memcpy(msg + 14, data, 1);
+
+ LOG_TRACE(">> send eventcast_ntf to ecp. action=%d, group=%d, data=%s\n",
+ action, group, data);
+
+ send_eventcast_ntf((const char *)msg);
+
+ if (msg) {
+ g_free(msg);
+ }
+ }
+
+ static bool send_eventcast_ntf(const char *data)
+ {
+ type_length length = 0;
+ type_group group = 0;
+ type_action action = 0;
+
+ const int catsize = 10;
+ char cat[catsize + 1];
+ memset(cat, 0, catsize + 1);
+
+ read_val_str(data, cat, catsize);
+ read_val_short(data + catsize, &length);
+ read_val_char(data + catsize + 2, &group);
+ read_val_char(data + catsize + 2 + 1, &action);
+
+ const char* ijdata = (data + catsize + 2 + 1 + 1);
+
+ LOG_TRACE(">> header cat = %s, length = %d, action=%d, group=%d\n", cat, length,action, group);
+
+ ECS__Master master = ECS__MASTER__INIT;
+ ECS__EventCastNtf ntf = ECS__EVENT_CAST_NTF__INIT;
+
+ ntf.category = (char*) g_malloc(catsize + 1);
+ strncpy(ntf.category, cat, 10);
+
+ ntf.length = length;
+ ntf.group = group;
+ ntf.action = action;
+
+ if (length > 0) {
+ ntf.has_data = 1;
+
+ ntf.data.data = g_malloc(length);
+ ntf.data.len = length;
+ memcpy(ntf.data.data, ijdata, length);
+
+ LOG_TRACE("data = %s, length = %hu\n", ijdata, length);
+ }
+
+ master.type = ECS__MASTER__TYPE__EVENTCAST_NTF;
+ master.eventcast_ntf = &ntf;
+
++ pb_to_all_clients(&master);
+
+ if (ntf.data.data && ntf.data.len > 0) {
+ g_free(ntf.data.data);
+ }
+
+ if (ntf.category) {
+ g_free(ntf.category);
+ }
+
+ return true;
+ }
+
+ void send_eventcast_sensor_data(const char *data, int len)
+ {
+ set_injector_data(data);
+ }
+
+ void send_eventcast_touch_data(int x, int y, int index, int status)
+ {
+ virtio_touchscreen_event(x, y, index, status);
+ }
+
+ void send_eventcast_hwkey_data(int keycode)
+ {
+ maru_hwkey_event(PRESSED, keycode);
+ maru_hwkey_event(RELEASED, keycode);
+ }
+
+ // handle eventcast_req message
+ bool msgproc_eventcast_req(ECS_Client* ccli, ECS__EventCastReq* msg)
+ {
+ gchar cmd[10] = {0};
+ gchar **server_addr = NULL;
+
+ LOG_TRACE("enter %s\n", __func__);
+
+ g_strlcpy(cmd, msg->category, sizeof(cmd));
+ type_length length = (type_length) msg->length;
+ type_group group = (type_group) (msg->group & 0xff);
+ type_action action = (type_action) (msg->action & 0xff);
+
+ LOG_TRACE("<< header = cmd = %s, length = %d, action=%d, group=%d\n",
+ cmd, length, action, group);
+
+ switch(action) {
+ case ECS_EVENTCAST_MSG_ACTION_CONNECT:
+ LOG_INFO("MSG_ACTION_CONNECT\n");
+
+ if (msg->data.data && msg->data.len > 0) {
+ const gchar *data = (const gchar *)msg->data.data;
+ gchar *ip_address = NULL;
+ guint64 port = 0;
+
+ server_addr = g_strsplit(data, ":", 0);
+ if (server_addr && server_addr[0]) {
+ int len = strlen(server_addr[0]);
+
+ if (len) {
+ ip_address = g_malloc(len + 1);
+ g_strlcpy(ip_address, server_addr[0], len + 1);
+ }
+ LOG_INFO("IP address: %s, length: %d\n", ip_address, len);
+ }
+
+ if (server_addr && server_addr[1]) {
+ port = g_ascii_strtoull(server_addr[1], NULL, 10);
+ LOG_INFO("port number: %d\n", port);
+ } else {
+ LOG_SEVERE("failed to parse port number\n");
+ }
+ LOG_TRACE("len = %zd, data\" %s\"", strlen(data), data);
+
+ connect_eventcast_app(ip_address, port);
+ eventcast_port = port;
+
+ LOG_TRACE(">> port_num: %d, %d\n", port, eventcast_port);
+ g_free(ip_address);
+ g_strfreev(server_addr);
+ } else {
+ LOG_INFO("ip address and port value are null\n");
+ }
+ break;
+ case ECS_EVENTCAST_MSG_ACTION_DISCONNECT:
+ LOG_INFO(">> MSG_ACTION_DISCONNECT\n");
+ disconnect_eventcast_app();
+ eventcast_port = 0;
+ break;
+ case ECS_EVENTCAST_MSG_ACTION_CONNECTION_STATUS:
+ case ECS_EVENTCAST_MSG_ACTION_SENSOR_STATUS:
+ case ECS_EVENTCAST_MSG_ACTION_TOUCH_STATUS:
+ LOG_TRACE(">> get_status_action\n");
+ send_eventcast_status_ntf(group, action);
+ break;
+ default:
+ break;
+ }
+
+ LOG_TRACE("leave %s\n", __func__);
+
+ return true;
+ }
#include "qapi/qmp/json-parser.h"
#include "ui/qemu-spice.h"
#include "qemu/queue.h"
-#include "qemu/option.h"
#include "sysemu/char.h"
#include "qemu/main-loop.h"
-
- #ifdef CONFIG_LINUX
- #include <sys/epoll.h>
- #endif
-
#include "qemu-common.h"
- #include "sdb.h"
+ #include "util/sdb.h"
#include "ecs-json-streamer.h"
#include "qmp-commands.h"
- #include "hw/maru_virtio_vmodem.h"
- #include "hw/maru_virtio_evdi.h"
-#include "ecs.h"
-#ifndef CONFIG_USE_SHM
-#include "display/maru_finger.h"
-#endif
-
-#include "hw/virtio/maru_virtio_evdi.h"
-#include "hw/virtio/maru_virtio_sensor.h"
-#include "hw/virtio/maru_virtio_jack.h"
-#include "hw/virtio/maru_virtio_power.h"
-#include "hw/virtio/maru_virtio_nfc.h"
+ #include "hw/virtio/maru_virtio_vmodem.h"
-#include "skin/maruskin_operation.h"
-#include "skin/maruskin_server.h"
-#include "util/maru_device_hotplug.h"
-#include "emul_state.h"
++#include "hw/virtio/maru_virtio_evdi.h"
+
+#include "ecs.h"
#include "debug_ch.h"
-MULTI_DEBUG_CHANNEL(qemu, ecs-msg);
-// utility functions
-static int guest_connection = 0;
-extern QemuMutex mutex_guest_connection;
-extern QemuMutex mutex_location_data;
-static char location_data[MAX_INJECTOR_REQ_DATA];
-/*static function define*/
-static bool handle_sdcard(char* dataBuf, size_t dataLen);
-static char* get_emulator_sdcard_path(void);
-static char *get_old_tizen_sdk_data_path(void);
+MULTI_DEBUG_CHANNEL(qemu, ecs);
static void* build_master(ECS__Master* master, int* payloadsize)
{
return true;
}
-
-static bool injector_req_handle(const char* cat, type_action action)
-{
- /*SD CARD msg process*/
- if (!strcmp(cat, MSG_TYPE_SDCARD)) {
- return false;
-
- } else if (!strcmp(cat, "suspend")) {
- ecs_suspend_lock_state(ecs_get_suspend_state());
- return true;
- } else if (!strcmp(cat, MSG_TYPE_GUEST)) {
- INFO("emuld connection is %d\n", action);
- qemu_mutex_lock(&mutex_guest_connection);
- guest_connection = action;
- qemu_mutex_unlock(&mutex_guest_connection);
- return false;
- }
-
- return false;
-}
-
-bool send_injector_ntf(const char* data, const int len)
-{
- type_length length = 0;
- type_group group = 0;
- type_action action = 0;
-
- const int catsize = 10;
- char cat[catsize + 1];
- memset(cat, 0, catsize + 1);
-
- read_val_str(data, cat, catsize);
- read_val_short(data + catsize, &length);
- read_val_char(data + catsize + 2, &group);
- read_val_char(data + catsize + 2 + 1, &action);
-
- if (injector_req_handle(cat, action)) {
- return true;
- }
-
- const char* ijdata = (data + catsize + 2 + 1 + 1);
-
- TRACE("<< header cat = %s, length = %d, action=%d, group=%d", cat, length,action, group);
-
- ECS__Master master = ECS__MASTER__INIT;
- ECS__InjectorNtf ntf = ECS__INJECTOR_NTF__INIT;
-
- ntf.category = (char*) g_malloc(catsize + 1);
- strncpy(ntf.category, cat, 10);
-
- ntf.length = length;
- ntf.group = group;
- ntf.action = action;
-
- if (length > 0)
- {
- ntf.has_data = 1;
-
- ntf.data.data = g_malloc(length);
- ntf.data.len = length;
- memcpy(ntf.data.data, ijdata, length);
- }
-
- master.type = ECS__MASTER__TYPE__INJECTOR_NTF;
- master.injector_ntf = &ntf;
-
- send_to_ecp(&master);
-
- if (ntf.data.len > 0)
- {
- g_free(ntf.data.data);
- }
-
- g_free(ntf.category);
-
- return true;
-}
-
-bool send_device_ntf(const char* data, const int len)
-{
- type_length length = 0;
- type_group group = 0;
- type_action action = 0;
-
- const int catsize = 10;
- char cat[catsize + 1];
- memset(cat, 0, catsize + 1);
-
- read_val_str(data, cat, catsize);
- read_val_short(data + catsize, &length);
- read_val_char(data + catsize + 2, &group);
- read_val_char(data + catsize + 2 + 1, &action);
-
- const char* ijdata = (data + catsize + 2 + 1 + 1);
-
- TRACE("<< header cat = %s, length = %d, action=%d, group=%d", cat, length,action, group);
-
- ECS__Master master = ECS__MASTER__INIT;
- ECS__DeviceNtf ntf = ECS__DEVICE_NTF__INIT;
-
- ntf.category = (char*) g_malloc(catsize + 1);
- strncpy(ntf.category, cat, 10);
-
-
- ntf.length = length;
- ntf.group = group;
- ntf.action = action;
-
- if (length > 0)
- {
- ntf.has_data = 1;
-
- ntf.data.data = g_malloc(length);
- ntf.data.len = length;
- memcpy(ntf.data.data, ijdata, length);
-
- TRACE("data = %s, length = %hu", ijdata, length);
- }
-
- master.type = ECS__MASTER__TYPE__DEVICE_NTF;
- master.device_ntf = &ntf;
-
- send_to_ecp(&master);
-
- if (ntf.data.data && ntf.data.len > 0)
- {
- g_free(ntf.data.data);
- }
-
- if (ntf.category)
- g_free(ntf.category);
-
- return true;
-}
-
-bool send_nfc_ntf(struct nfc_msg_info* msg)
-{
- const int catsize = 10;
- char cat[catsize + 1];
- ECS_Client *clii;
- memset(cat, 0, catsize + 1);
-
- print_binary((char*)msg->buf, msg->use);
- TRACE("id: %02x, type: %02x, use: %d", msg->client_id, msg->client_type, msg->use);
- clii = find_client(msg->client_id, msg->client_type);
- if (clii) {
- if(clii->client_type == TYPE_SIMUL_NFC) {
- strncpy(cat, MSG_TYPE_NFC, 3);
- } else if (clii->client_type == TYPE_ECP) {
- strncpy(cat, MSG_TYPE_SIMUL_NFC, 9);
- }else {
- ERR("cannot find type! : %d", clii->client_type);
- }
- TRACE("header category = %s", cat);
- }
- else {
- ERR("cannot find client!\n");
- }
-
- ECS__Master master = ECS__MASTER__INIT;
- ECS__NfcNtf ntf = ECS__NFC_NTF__INIT;
-
- ntf.category = (char*) g_malloc(catsize + 1);
- strncpy(ntf.category, cat, 10);
-
- ntf.has_data = 1;
-
- ntf.data.data = g_malloc(NFC_MAX_BUF_SIZE);
- ntf.data.len = NFC_MAX_BUF_SIZE;
- memcpy(ntf.data.data, msg->buf, NFC_MAX_BUF_SIZE);
-
- printf("send to nfc injector: ");
- master.type = ECS__MASTER__TYPE__NFC_NTF;
- master.nfc_ntf = &ntf;
-
- send_single_msg(&master, clii);
-
- if (ntf.data.data && ntf.data.len > 0)
- {
- g_free(ntf.data.data);
- }
-
- if (ntf.category)
- g_free(ntf.category);
-
- return true;
-}
-
-static bool handle_sdcard(char* dataBuf, size_t dataLen)
-{
- int err_no = 0;
- char ret = 0;
- INFO("handle_sdcard() data: %s\n", dataBuf);
- if (dataBuf != NULL) {
- ret = dataBuf[0];
-
- if (ret == '0' ) {
- /* umount sdcard */
- //mloop_evcmd_usbdisk(NULL);
- char sdcard_img_path[256];
- char* sdcard_path = NULL;
-
- sdcard_path = get_emulator_sdcard_path();
- if (sdcard_path) {
- g_strlcpy(sdcard_img_path, sdcard_path,
- sizeof(sdcard_img_path));
-
- /* emulator_sdcard_img_path + sdcard img name */
- char* sdcard_img_name = dataBuf+2;
- if (dataLen > 3 && sdcard_img_name != NULL) {
- char* pLinechange = strchr(sdcard_img_name, '\n');
- if(pLinechange != NULL){
- sdcard_img_name = g_strndup(sdcard_img_name, pLinechange - sdcard_img_name);
- }
-
- g_strlcat(sdcard_img_path, sdcard_img_name, sizeof(sdcard_img_path));
- INFO("sdcard path: [%s]\n", sdcard_img_path);
-
- /*if using strndup than free string*/
- if (pLinechange != NULL && sdcard_img_name!= NULL) {
- free(sdcard_img_name);
- }
- }
- g_free(sdcard_path);
-
- }
- err_no = remove_sdcard_lock_os(sdcard_img_path);
- INFO("umount err_no: %d\n", err_no);
- if (errno == 0 && is_sdcard_attached()) {
- do_hotplug(DETACH_SDCARD, NULL, 0);
- } else {
- ERR("failed to umount: %s\n", sdcard_img_path);
- send_gen_injector_ntf(MSG_TYPE_SDCARD, 6, 11, err_no, NULL);
- return err_no;
- }
- }
- else if (ret == '1') {
- /* mount sdcard */
- char sdcard_img_path[256];
- char* sdcard_path = NULL;
-
- sdcard_path = get_emulator_sdcard_path();
- if (sdcard_path) {
- g_strlcpy(sdcard_img_path, sdcard_path,
- sizeof(sdcard_img_path));
-
- /* emulator_sdcard_img_path + sdcard img name */
- char* sdcard_img_name = dataBuf+2;
- if (dataLen > 3 && sdcard_img_name != NULL) {
- char* pLinechange = strchr(sdcard_img_name, '\n');
- if(pLinechange != NULL){
- sdcard_img_name = g_strndup(sdcard_img_name, pLinechange - sdcard_img_name);
- }
-
- g_strlcat(sdcard_img_path, sdcard_img_name, sizeof(sdcard_img_path));
- TRACE("sdcard path: [%s]\n", sdcard_img_path);
-
- //mloop_evcmd_usbdisk(sdcard_img_path);
- if ( !is_sdcard_attached() && make_sdcard_lock_os(sdcard_img_path)) {
- do_hotplug(ATTACH_SDCARD, sdcard_img_path, strlen(sdcard_img_path) + 1);
- send_gen_injector_ntf(MSG_TYPE_SDCARD, 6, 11, 0, NULL);
- } else {
- send_gen_injector_ntf(MSG_TYPE_SDCARD, 6, 11, 5, NULL);
- return ERR_LCK;
- }
- /*if using strndup than free string*/
- if (pLinechange != NULL && sdcard_img_name!= NULL) {
- free(sdcard_img_name);
- }
-
- }
-
- g_free(sdcard_path);
- } else {
- ERR("failed to get sdcard path!!\n");
- }
- } else if (ret == '2') {
- TRACE("sdcard status 2 bypass\n" );
- } else {
- ERR("!!! unknown command : %c\n", ret);
- }
-
- } else {
- ERR("!!! unknown data : %c\n", ret);
- }
- return ERR_SUCCESS;
-}
-
-static char* get_emulator_sdcard_path(void)
-{
- char *emulator_sdcard_path = NULL;
- char *tizen_sdk_data = NULL;
-
-#ifndef CONFIG_WIN32
- char emulator_sdcard[] = "/emulator/sdcard/";
-#else
- char emulator_sdcard[] = "\\emulator\\sdcard\\";
-#endif
-
- TRACE("emulator_sdcard: %s, %zu\n", emulator_sdcard, sizeof(emulator_sdcard));
-
- tizen_sdk_data = get_tizen_sdk_data_path();
- if (!tizen_sdk_data) {
- ERR("failed to get tizen-sdk-data path.\n");
- return NULL;
- }
-
- emulator_sdcard_path =
- g_malloc(strlen(tizen_sdk_data) + sizeof(emulator_sdcard) + 1);
- if (!emulator_sdcard_path) {
- ERR("failed to allocate memory.\n");
- return NULL;
- }
-
- g_snprintf(emulator_sdcard_path, strlen(tizen_sdk_data) + sizeof(emulator_sdcard),
- "%s%s", tizen_sdk_data, emulator_sdcard);
-
- g_free(tizen_sdk_data);
-
- TRACE("sdcard path: %s\n", emulator_sdcard_path);
- return emulator_sdcard_path;
-}
-
-/*
- * get tizen-sdk-data path from sdk.info.
- */
-char *get_tizen_sdk_data_path(void)
-{
- char const *emul_bin_path = NULL;
- char *sdk_info_file_path = NULL;
- char *tizen_sdk_data_path = NULL;
-#ifndef CONFIG_WIN32
- const char *sdk_info = "../../../sdk.info";
-#else
- const char *sdk_info = "..\\..\\..\\sdk.info";
-#endif
- const char sdk_data_var[] = "TIZEN_SDK_DATA_PATH";
-
- FILE *sdk_info_fp = NULL;
- int sdk_info_path_len = 0;
-
- TRACE("%s\n", __func__);
-
- emul_bin_path = get_bin_path();
- if (!emul_bin_path) {
- ERR("failed to get emulator path.\n");
- return NULL;
- }
-
- sdk_info_path_len = strlen(emul_bin_path) + strlen(sdk_info) + 1;
- sdk_info_file_path = g_malloc(sdk_info_path_len);
- if (!sdk_info_file_path) {
- ERR("failed to allocate sdk-data buffer.\n");
- return NULL;
- }
-
- g_snprintf(sdk_info_file_path, sdk_info_path_len, "%s%s",
- emul_bin_path, sdk_info);
- INFO("sdk.info path: %s\n", sdk_info_file_path);
-
- sdk_info_fp = fopen(sdk_info_file_path, "r");
- g_free(sdk_info_file_path);
-
- if (sdk_info_fp) {
- TRACE("Succeeded to open [sdk.info].\n");
-
- char tmp[256] = { '\0', };
- char *tmpline = NULL;
- while (fgets(tmp, sizeof(tmp), sdk_info_fp) != NULL) {
- if ((tmpline = g_strstr_len(tmp, sizeof(tmp), sdk_data_var))) {
- tmpline += strlen(sdk_data_var) + 1; // 1 for '='
- break;
- }
- }
-
- if (tmpline) {
- if (tmpline[strlen(tmpline) - 1] == '\n') {
- tmpline[strlen(tmpline) - 1] = '\0';
- }
- if (tmpline[strlen(tmpline) - 1] == '\r') {
- tmpline[strlen(tmpline) - 1] = '\0';
- }
-
- tizen_sdk_data_path = g_malloc(strlen(tmpline) + 1);
- g_strlcpy(tizen_sdk_data_path, tmpline, strlen(tmpline) + 1);
-
- INFO("tizen-sdk-data path: %s\n", tizen_sdk_data_path);
-
- fclose(sdk_info_fp);
- return tizen_sdk_data_path;
- }
-
- fclose(sdk_info_fp);
- }
-
- // legacy mode
- ERR("Failed to open [sdk.info].\n");
-
- return get_old_tizen_sdk_data_path();
-}
-
-static char *get_old_tizen_sdk_data_path(void)
-{
- char *tizen_sdk_data_path = NULL;
-
- INFO("try to search tizen-sdk-data path in another way.\n");
-
-#ifndef CONFIG_WIN32
- char tizen_sdk_data[] = "/tizen-sdk-data";
- int tizen_sdk_data_len = 0;
- char *home_dir;
-
- home_dir = (char *)g_getenv("HOME");
- if (!home_dir) {
- home_dir = (char *)g_get_home_dir();
- }
-
- tizen_sdk_data_len = strlen(home_dir) + sizeof(tizen_sdk_data) + 1;
- tizen_sdk_data_path = g_malloc(tizen_sdk_data_len);
- if (!tizen_sdk_data_path) {
- ERR("failed to allocate memory.\n");
- return NULL;
- }
- g_strlcpy(tizen_sdk_data_path, home_dir, tizen_sdk_data_len);
- g_strlcat(tizen_sdk_data_path, tizen_sdk_data, tizen_sdk_data_len);
-
-#else
- char tizen_sdk_data[] = "\\tizen-sdk-data\\";
- gint tizen_sdk_data_len = 0;
- HKEY hKey;
- char strLocalAppDataPath[1024] = { 0 };
- DWORD dwBufLen = 1024;
-
- RegOpenKeyEx(HKEY_CURRENT_USER,
- "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders",
- 0, KEY_QUERY_VALUE, &hKey);
-
- RegQueryValueEx(hKey, "Local AppData", NULL,
- NULL, (LPBYTE)strLocalAppDataPath, &dwBufLen);
- RegCloseKey(hKey);
-
- tizen_sdk_data_len = strlen(strLocalAppDataPath) + sizeof(tizen_sdk_data) + 1;
- tizen_sdk_data_path = g_malloc(tizen_sdk_data_len);
- if (!tizen_sdk_data_path) {
- ERR("failed to allocate memory.\n");
- return NULL;
- }
-
- g_strlcpy(tizen_sdk_data_path, strLocalAppDataPath, tizen_sdk_data_len);
- g_strlcat(tizen_sdk_data_path, tizen_sdk_data, tizen_sdk_data_len);
-#endif
-
- INFO("tizen-sdk-data path: %s\n", tizen_sdk_data_path);
- return tizen_sdk_data_path;
-}
--
--- /dev/null
- #include "mloop_event.h"
- #include "hw/maru_virtio_sensor.h"
- #include "hw/maru_virtio_nfc.h"
+/* Emulator Control Server
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * Jinhyung choi <jinhyung2.choi@samsung.com>
+ * MunKyu Im <munkyu.im@samsung.com>
+ * Daiyoung Kim <daiyoung777.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#include "qemu-common.h"
+#include "qemu/option.h"
+#include "qemu/config-file.h"
+
+#include "qmp-commands.h"
+#include "net/slirp.h"
+#include "fsdev/qemu-fsdev.h"
+#include "monitor/qdev.h"
- #ifndef CONFIG_USE_SHM
- #include "maru_finger.h"
- #endif
++#include "hw/virtio/maru_virtio_sensor.h"
++#include "hw/virtio/maru_virtio_nfc.h"
+#include "skin/maruskin_operation.h"
+#include "skin/maruskin_server.h"
- #include "emulator.h"
+
- static bool is_hds_attached = false;
-
- #define FS_FILE_SYSTEM "virtfs"
- #define FS_DRIVER "virtio-9p-pci"
- #define FS_MOUNT_TAG "fileshare"
- static bool do_virtfs_attach(const char * const file)
- {
- QemuOpts *fsdev;
- int ret;
- QDict *qdict = qdict_new();
-
- fsdev = qemu_opts_create(qemu_find_opts("fsdev"),
- FS_MOUNT_TAG, 0, NULL);
- if (!fsdev) {
- fprintf(stderr, "duplicate fsdev id: %s\n", FS_MOUNT_TAG);
- return false;
- }
-
- qemu_opt_set(fsdev, "fsdriver", "local");
- qemu_opt_set(fsdev, "path", file);
- qemu_opt_set(fsdev, "security_model", "none");
-
- ret = qemu_fsdev_add(fsdev);
- if (ret != 0) {
- ERR("qemu_fsdev_add failed. with ret: %d\n", ret);
- return false;
- }
-
- qdict = qdict_new();
- qdict_put(qdict, "driver", qstring_from_str(FS_DRIVER));
- qdict_put(qdict, "fsdev", qstring_from_str(FS_MOUNT_TAG));
- qdict_put(qdict, "mount_tag", qstring_from_str(FS_MOUNT_TAG));
-
- qdict_put(qdict, "id", qstring_from_str(FS_MOUNT_TAG));
-
- if (do_device_add(default_mon, qdict, NULL)) {
- QDECREF(qdict);
- return false;
- }
-
- QDECREF(qdict);
-
- is_hds_attached = true;
-
- return true;
- }
-
- bool do_virtfs_detach(void)
- {
- INFO("try to detach hds.\n");
-
- QDict *qdict = qdict_new();
- qemu_fsdev_remove(FS_MOUNT_TAG);
-
- qdict_put(qdict, "id", qstring_from_str(FS_MOUNT_TAG));
-
- if (qmp_marshal_input_device_del(cur_mon, qdict, NULL)) {
- QDECREF(qdict);
- return false;
- }
-
- QDECREF(qdict);
-
- is_hds_attached = false;
-
- return true;
- }
-
++#include "util/maru_device_hotplug.h"
+#include "emul_state.h"
+#include "ecs.h"
+#include "debug_ch.h"
+
+MULTI_DEBUG_CHANNEL(qemu, ecs);
+
+static void msgproc_device_ans(ECS_Client* ccli, const char* category, bool succeed, char* data)
+{
+ if (ccli == NULL) {
+ return;
+ }
+ int catlen = 0;
+ ECS__Master master = ECS__MASTER__INIT;
+ ECS__DeviceAns ans = ECS__DEVICE_ANS__INIT;
+
+ TRACE("device ans - category : %s, succed : %d\n", category, succeed);
+
+ catlen = strlen(category);
+ ans.category = (char*) g_malloc0(catlen + 1);
+ memcpy(ans.category, category, catlen);
+
+ ans.errcode = !succeed;
+
+ if (data != NULL) {
+ ans.length = strlen(data);
+
+ if (ans.length > 0) {
+ ans.has_data = 1;
+ ans.data.data = g_malloc(ans.length);
+ ans.data.len = ans.length;
+ memcpy(ans.data.data, data, ans.length);
+ TRACE("data = %s, length = %hu\n", data, ans.length);
+ }
+ }
+
+ master.type = ECS__MASTER__TYPE__DEVICE_ANS;
+ master.device_ans = &ans;
+
+ pb_to_all_clients(&master);
+
+ if (ans.category)
+ g_free(ans.category);
+}
+
+extern char tizen_target_img_path[];
+void send_target_image_information(ECS_Client* ccli) {
+ ECS__Master master = ECS__MASTER__INIT;
+ ECS__DeviceAns ans = ECS__DEVICE_ANS__INIT;
+ int length = strlen(tizen_target_img_path); // ??
+
+ ans.category = (char*) g_malloc(10 + 1);
+ strncpy(ans.category, "info", 10);
+
+ ans.errcode = 0;
+ ans.length = length;
+ ans.group = 1;
+ ans.action = 1;
+
+ if (length > 0)
+ {
+ ans.has_data = 1;
+
+ ans.data.data = g_malloc(length);
+ ans.data.len = length;
+ memcpy(ans.data.data, tizen_target_img_path, length);
+
+ TRACE("data = %s, length = %hu\n", tizen_target_img_path, length);
+ }
+
+ master.type = ECS__MASTER__TYPE__DEVICE_ANS;
+ master.device_ans = &ans;
+
+ pb_to_single_client(&master, ccli);
+
+ if (ans.data.len > 0)
+ {
+ g_free(ans.data.data);
+ }
+
+ g_free(ans.category);
+}
+
+static void msgproc_device_req_sensor(ECS_Client* ccli, ECS__DeviceReq* msg, char* cmd)
+{
+ char* data = NULL;
+ type_group group = (type_group) (msg->group & 0xff);
+ type_action action = (type_action) (msg->action & 0xff);
+
+ if (msg->has_data && msg->data.len > 0)
+ {
+ data = (char*) g_malloc0(msg->data.len + 1);
+ memcpy(data, msg->data.data, msg->data.len);
+ }
+
+ if (group == MSG_GROUP_STATUS) {
+ if (action == MSG_ACT_ACCEL) {
+ get_sensor_accel();
+ } else if (action == MSG_ACT_GYRO) {
+ get_sensor_gyro();
+ } else if (action == MSG_ACT_MAG) {
+ get_sensor_mag();
+ } else if (action == MSG_ACT_LIGHT) {
+ get_sensor_light();
+ } else if (action == MSG_ACT_PROXI) {
+ get_sensor_proxi();
+ }
+ } else {
+ if (data != NULL) {
+ set_injector_data(data);
+ } else {
+ ERR("sensor set data is null\n");
+ }
+ }
+ msgproc_device_ans(ccli, cmd, true, NULL);
+
+ if (data) {
+ g_free(data);
+ }
+}
+
+static void msgproc_device_req_network(ECS_Client* ccli, ECS__DeviceReq* msg)
+{
+ char* data = NULL;
+
+ if (msg->has_data && msg->data.len > 0)
+ {
+ data = (char*) g_malloc0(msg->data.len + 1);
+ memcpy(data, msg->data.data, msg->data.len);
+ }
+
+ if (data != NULL) {
+ TRACE(">>> Network msg: '%s'\n", data);
+ if(net_slirp_redir(data) < 0) {
+ ERR( "redirect [%s] fail\n", data);
+ } else {
+ TRACE("redirect [%s] success\n", data);
+ }
+ } else {
+ ERR("Network redirection data is null.\n");
+ }
+
+ if (data) {
+ g_free(data);
+ }
+}
+
+static void msgproc_device_req_tgesture(ECS_Client* ccli, ECS__DeviceReq* msg)
+{
+ char* data = NULL;
+ type_group group = (type_group) (msg->group & 0xff);
+
+ if (msg->has_data && msg->data.len > 0)
+ {
+ data = (char*) g_malloc0(msg->data.len + 1);
+ memcpy(data, msg->data.data, msg->data.len);
+ }
+
+ /* release multi-touch */
+#ifndef CONFIG_USE_SHM
+ if (get_multi_touch_enable() != 0) {
+ clear_finger_slot(false);
+ }
+#else
+ // TODO:
+#endif
+
+ if (data == NULL) {
+ ERR("touch gesture data is NULL\n");
+ return;
+ }
+
+ TRACE("%s\n", data);
+
+ char token[] = "#";
+
+ if (group == 1) { /* HW key event */
+ char *section = strtok(data, token);
+ int event_type = atoi(section);
+
+ section = strtok(NULL, token);
+ int keycode = atoi(section);
+
+ do_hw_key_event(event_type, keycode);
+ } else { /* touch event */
+ char *section = strtok(data, token);
+ int event_type = atoi(section);
+
+ section = strtok(NULL, token);
+ int xx = atoi(section);
+
+ section = strtok(NULL, token);
+ int yy = atoi(section);
+
+ section = strtok(NULL, token);
+ int zz = atoi(section);
+
+ do_mouse_event(1/* LEFT */, event_type, 0, 0, xx, yy, zz);
+ }
+
+ if (data) {
+ g_free(data);
+ }
+}
+
+static void msgproc_device_req_input(ECS_Client* ccli, ECS__DeviceReq* msg, char* cmd)
+{
+ char* data = NULL;
+ type_group group = (type_group) (msg->group & 0xff);
+ type_action action = (type_action) (msg->action & 0xff);
+
+ if (msg->has_data && msg->data.len > 0)
+ {
+ data = (char*) g_malloc0(msg->data.len + 1);
+ memcpy(data, msg->data.data, msg->data.len);
+ }
+
+ // cli input
+ TRACE("receive input message [%s]\n", data);
+
+ if (group == 0) {
+ TRACE("input keycode data : [%s]\n", data);
+
+ char token[] = " ";
+ char *section = strtok(data, token);
+ int keycode = atoi(section);
+ if (action == 1) {
+ //action 1 press
+ do_hw_key_event(KEY_PRESSED, keycode);
+
+ } else if (action == 2) {
+ //action 2 released
+ do_hw_key_event(KEY_RELEASED, keycode);
+
+ } else {
+ ERR("unknown action : [%d]\n", (int)action);
+ }
+ } else if (group == 1) {
+ //spec out
+ TRACE("input category's group 1 is spec out\n");
+ } else {
+ ERR("unknown group [%d]\n", (int)group);
+ }
+ msgproc_device_ans(ccli, cmd, true, NULL);
+
+ if (data) {
+ g_free(data);
+ }
+}
+
+static void msgproc_device_req_nfc(ECS_Client* ccli, ECS__DeviceReq* msg)
+{
+ char* data = NULL;
+ type_group group = (type_group) (msg->group & 0xff);
+
+ if (msg->has_data && msg->data.len > 0)
+ {
+ data = (char*) g_malloc0(msg->data.len + 1);
+ memcpy(data, msg->data.data, msg->data.len);
+ }
+
+ if (group == MSG_GROUP_STATUS) {
+ get_nfc_data();
+ } else {
+ if (data != NULL) {
+ send_to_nfc(ccli->client_id, ccli->client_type, data, msg->data.len);
+ } else {
+ ERR("nfc data is null\n");
+ }
+ }
+
+ if (data) {
+ g_free(data);
+ }
+}
+
- if (is_hds_attached) {
+static char hds_path[PATH_MAX];
+
+static void msgproc_device_req_hds(ECS_Client* ccli, ECS__DeviceReq* msg, char * cmd)
+{
+ char* data = NULL;
+ type_group group = (type_group) (msg->group & 0xff);
+ type_action action = (type_action) (msg->action & 0xff);
+
+ if (msg->has_data && msg->data.len > 0)
+ {
+ data = (char*) g_malloc0(msg->data.len + 1);
+ memcpy(data, msg->data.data, msg->data.len);
+ }
+
+ INFO("hds group: %d, action : %d\n", group, action);
+ if (group == MSG_GROUP_STATUS) {
+ char hds_data_send[PATH_MAX + 3];
- INFO("try attach with is_hds_attached : %d\n", is_hds_attached);
- if (data != NULL && !is_hds_attached) {
- if (!do_virtfs_attach(data)) {
++ if (is_hds_attached()) {
+ sprintf(hds_data_send, "1, %s", hds_path);
+ } else {
+ sprintf(hds_data_send, "0, ");
+ }
+ make_send_device_ntf(cmd, group, 99, hds_data_send);
+ } else if (group == 100 && action == 1) {
- }
++ INFO("try attach with is_hds_attached : %d\n", is_hds_attached());
++ if (data != NULL && !is_hds_attached()) {
++ do_hotplug(ATTACH_HDS, data, strlen(data) + 1);
++ if (!is_hds_attached()) {
+ ERR("failed to attach");
+ make_send_device_ntf(cmd, 100, 2, NULL);
+ } else {
+ memset(hds_path, 0, sizeof(hds_path));
+ memcpy(hds_path, data, sizeof(hds_path) - 1);
+ INFO("send emuld to mount.\n");
+ send_msg_to_guest(ccli, cmd, group, action, data, strlen(data));
+ }
+ } else {
+ make_send_device_ntf(cmd, 100, 2, NULL);
- INFO("try detach with is_hds_attached : %d\n", is_hds_attached);
- if (is_hds_attached) {
++ }
+ } else if (group == 100 && action == 2) {
- TRACE(">> device_req: header = cmd = %s, length = %d, action=%d, group=%d\n",
++ INFO("try detach with is_hds_attached : %d\n", is_hds_attached());
++ if (is_hds_attached()) {
+ INFO("send emuld to umount.\n");
+ send_msg_to_guest(ccli, cmd, group, action, NULL, 0);
+ } else {
+ INFO("hds is not attached. do not try detach it.\n");
+ }
+ } else {
+ ERR("hds unknown command: group %d action %d\n", group, action);
+ }
+
+ if (data) {
+ g_free(data);
+ }
+}
+
+bool msgproc_device_req(ECS_Client* ccli, ECS__DeviceReq* msg)
+{
+ char cmd[10];
+ memset(cmd, 0, 10);
+ strcpy(cmd, msg->category);
+
++ TRACE(">> device_req: header = cmd = %s, length = %d, action=%d, group=%d\n",
+ cmd, msg->length, msg->action, msg->group);
+
+ if (!strcmp(cmd, MSG_TYPE_SENSOR)) {
+ msgproc_device_req_sensor(ccli, msg, cmd);
+ } else if (!strcmp(cmd, "Network")) {
+ msgproc_device_req_network(ccli, msg);
+ } else if (!strcmp(cmd, "TGesture")) {
+ msgproc_device_req_tgesture(ccli, msg);
+ } else if (!strcmp(cmd, "info")) {
+ // check to emulator target image path
+ TRACE("receive info message %s\n", tizen_target_img_path);
+ send_target_image_information(ccli);
+ } else if (!strcmp(cmd, "hds")) {
+ msgproc_device_req_hds(ccli, msg, cmd);
+ } else if (!strcmp(cmd, "input")) {
+ msgproc_device_req_input(ccli, msg, cmd);
+ } else if (!strcmp(cmd, "vmname")) {
+ char* vmname = get_emul_vm_name();
+ msgproc_device_ans(ccli, cmd, true, vmname);
+ } else if (!strcmp(cmd, "nfc")) {
+ msgproc_device_req_nfc(ccli, msg);
+ } else {
+ ERR("unknown cmd [%s]\n", cmd);
+ }
+
+ return true;
+}
+
+bool send_device_ntf(const char* data, const int len)
+{
+ type_length length = 0;
+ type_group group = 0;
+ type_action action = 0;
+
+ const int catsize = 10;
+ char cat[catsize + 1];
+ memset(cat, 0, catsize + 1);
+
+ read_val_str(data, cat, catsize);
+ read_val_short(data + catsize, &length);
+ read_val_char(data + catsize + 2, &group);
+ read_val_char(data + catsize + 2 + 1, &action);
+
+ const char* ijdata = (data + catsize + 2 + 1 + 1);
+
+ TRACE("<< header cat = %s, length = %d, action=%d, group=%d\n", cat, length,action, group);
+
+ ECS__Master master = ECS__MASTER__INIT;
+ ECS__DeviceNtf ntf = ECS__DEVICE_NTF__INIT;
+
+ ntf.category = (char*) g_malloc(catsize + 1);
+ strncpy(ntf.category, cat, 10);
+
+
+ ntf.length = length;
+ ntf.group = group;
+ ntf.action = action;
+
+ if (length > 0)
+ {
+ ntf.has_data = 1;
+
+ ntf.data.data = g_malloc(length);
+ ntf.data.len = length;
+ memcpy(ntf.data.data, ijdata, length);
+
+ TRACE("data = %s, length = %hu\n", ijdata, length);
+ }
+
+ master.type = ECS__MASTER__TYPE__DEVICE_NTF;
+ master.device_ntf = &ntf;
+
+ pb_to_all_clients(&master);
+
+ if (ntf.data.data && ntf.data.len > 0)
+ {
+ g_free(ntf.data.data);
+ }
+
+ if (ntf.category)
+ g_free(ntf.category);
+
+ return true;
+}
+
--- /dev/null
- #include "mloop_event.h"
+/* Emulator Control Server
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * Jinhyung choi <jinhyung2.choi@samsung.com>
+ * MunKyu Im <munkyu.im@samsung.com>
+ * Daiyoung Kim <daiyoung777.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#include "qemu-common.h"
+
- #include "hw/maru_virtio_vmodem.h"
- #include "hw/maru_virtio_evdi.h"
- #include "hw/maru_virtio_jack.h"
- #include "hw/maru_virtio_power.h"
-
- #include "emulator.h"
++#include "hw/virtio/maru_virtio_vmodem.h"
++#include "hw/virtio/maru_virtio_evdi.h"
++#include "hw/virtio/maru_virtio_jack.h"
++#include "hw/virtio/maru_virtio_power.h"
+
- static bool is_sdcard_attached = false;
-
++#include "util/maru_device_hotplug.h"
+#include "emul_state.h"
+#include "ecs.h"
+#include "debug_ch.h"
+
+MULTI_DEBUG_CHANNEL(qemu, ecs);
+
+extern QemuMutex mutex_guest_connection;
+static int guest_connection = 0;
+
+extern QemuMutex mutex_location_data;
+static char location_data[MAX_INJECTOR_REQ_DATA];
+
- char *emul_bin_path = NULL;
+static void msgproc_injector_ans(ECS_Client* ccli, const char* category, bool succeed)
+{
+ if (ccli == NULL) {
+ return;
+ }
+ int catlen = 0;
+ ECS__Master master = ECS__MASTER__INIT;
+ ECS__InjectorAns ans = ECS__INJECTOR_ANS__INIT;
+
+ TRACE("injector ans - category : %s, succed : %d\n", category, succeed);
+
+ catlen = strlen(category);
+ ans.category = (char*) g_malloc0(catlen + 1);
+ memcpy(ans.category, category, catlen);
+
+ ans.errcode = !succeed;
+ master.type = ECS__MASTER__TYPE__INJECTOR_ANS;
+ master.injector_ans = &ans;
+
+ pb_to_all_clients(&master);
+
+ if (ans.category)
+ g_free(ans.category);
+}
+
+static bool injector_send(ECS_Client* ccli, ECS__InjectorReq* msg, char* cmd)
+{
+ int sndlen = 15; // HEADER(CMD + LENGTH + GROUP + ACTION) + 1
+ const char* msg_data;
+ char* sndbuf;
+ bool ret = false;
+ type_group group;
+
+ group = (type_group) (msg->group & 0xff);
+
+ if (msg->has_data && msg->data.data && msg->data.len > 0)
+ sndlen += msg->data.len;
+
+ sndbuf = (char*) g_malloc0(sndlen);
+ if (!sndbuf) {
+ msgproc_injector_ans(ccli, cmd, false);
+ return false;
+ }
+
+ memcpy(sndbuf, cmd, 10);
+ memcpy(sndbuf + 10, &msg->length, 2);
+ memcpy(sndbuf + 12, &msg->group, 1);
+ memcpy(sndbuf + 13, &msg->action, 1);
+
+ if (msg->has_data && msg->data.data && msg->data.len > 0) {
+ msg_data = (const char*)msg->data.data;
+ memcpy(sndbuf + 14, msg_data, msg->data.len);
+ TRACE(">> print len = %zd, data\" %s\"\n", msg->data.len, msg_data);
+ }
+
+ if(strcmp(cmd, "telephony") == 0) {
+ TRACE("telephony msg >>");
+ ret = send_to_vmodem(route_ij, sndbuf, sndlen);
+ } else {
+ TRACE("evdi msg >> %s", cmd);
+ ret = send_to_evdi(route_ij, sndbuf, sndlen);
+ }
+
+ g_free(sndbuf);
+
+ if (group != MSG_GROUP_STATUS) {
+ msgproc_injector_ans(ccli, cmd, ret);
+ }
+
+ if (!ret) {
+ return false;
+ }
+
+ return true;
+}
+
+static char* get_emulator_sdcard_path(void)
+{
+ char *emulator_sdcard_path = NULL;
+ char *tizen_sdk_data = NULL;
+
+#ifndef CONFIG_WIN32
+ char emulator_sdcard[] = "/emulator/sdcard/";
+#else
+ char emulator_sdcard[] = "\\emulator\\sdcard\\";
+#endif
+
+ TRACE("emulator_sdcard: %s, %zu\n", emulator_sdcard, sizeof(emulator_sdcard));
+
+ tizen_sdk_data = get_tizen_sdk_data_path();
+ if (!tizen_sdk_data) {
+ ERR("failed to get tizen-sdk-data path.\n");
+ return NULL;
+ }
+
+ emulator_sdcard_path =
+ g_malloc(strlen(tizen_sdk_data) + sizeof(emulator_sdcard) + 1);
+ if (!emulator_sdcard_path) {
+ ERR("failed to allocate memory.\n");
+ return NULL;
+ }
+
+ g_snprintf(emulator_sdcard_path, strlen(tizen_sdk_data) + sizeof(emulator_sdcard),
+ "%s%s", tizen_sdk_data, emulator_sdcard);
+
+ g_free(tizen_sdk_data);
+
+ TRACE("sdcard path: %s\n", emulator_sdcard_path);
+ return emulator_sdcard_path;
+}
+
+static char *get_old_tizen_sdk_data_path(void)
+{
+ char *tizen_sdk_data_path = NULL;
+
+ INFO("try to search tizen-sdk-data path in another way.\n");
+
+#ifndef CONFIG_WIN32
+ char tizen_sdk_data[] = "/tizen-sdk-data";
+ int tizen_sdk_data_len = 0;
+ char *home_dir;
+
+ home_dir = (char *)g_getenv("HOME");
+ if (!home_dir) {
+ home_dir = (char *)g_get_home_dir();
+ }
+
+ tizen_sdk_data_len = strlen(home_dir) + sizeof(tizen_sdk_data) + 1;
+ tizen_sdk_data_path = g_malloc(tizen_sdk_data_len);
+ if (!tizen_sdk_data_path) {
+ ERR("failed to allocate memory.\n");
+ return NULL;
+ }
+ g_strlcpy(tizen_sdk_data_path, home_dir, tizen_sdk_data_len);
+ g_strlcat(tizen_sdk_data_path, tizen_sdk_data, tizen_sdk_data_len);
+
+#else
+ char tizen_sdk_data[] = "\\tizen-sdk-data\\";
+ gint tizen_sdk_data_len = 0;
+ HKEY hKey;
+ char strLocalAppDataPath[1024] = { 0 };
+ DWORD dwBufLen = 1024;
+
+ RegOpenKeyEx(HKEY_CURRENT_USER,
+ "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders",
+ 0, KEY_QUERY_VALUE, &hKey);
+
+ RegQueryValueEx(hKey, "Local AppData", NULL,
+ NULL, (LPBYTE)strLocalAppDataPath, &dwBufLen);
+ RegCloseKey(hKey);
+
+ tizen_sdk_data_len = strlen(strLocalAppDataPath) + sizeof(tizen_sdk_data) + 1;
+ tizen_sdk_data_path = g_malloc(tizen_sdk_data_len);
+ if (!tizen_sdk_data_path) {
+ ERR("failed to allocate memory.\n");
+ return NULL;
+ }
+
+ g_strlcpy(tizen_sdk_data_path, strLocalAppDataPath, tizen_sdk_data_len);
+ g_strlcat(tizen_sdk_data_path, tizen_sdk_data, tizen_sdk_data_len);
+#endif
+
+ INFO("tizen-sdk-data path: %s\n", tizen_sdk_data_path);
+ return tizen_sdk_data_path;
+}
+
+/*
+ * get tizen-sdk-data path from sdk.info.
+ */
+char *get_tizen_sdk_data_path(void)
+{
- static void send_gen_injector_ntf(const char* cmd, int cmdlen, int grp, int act, char* on)
++ char const *emul_bin_path = NULL;
+ char *sdk_info_file_path = NULL;
+ char *tizen_sdk_data_path = NULL;
+#ifndef CONFIG_WIN32
+ const char *sdk_info = "../../../sdk.info";
+#else
+ const char *sdk_info = "..\\..\\..\\sdk.info";
+#endif
+ const char sdk_data_var[] = "TIZEN_SDK_DATA_PATH";
+
+ FILE *sdk_info_fp = NULL;
+ int sdk_info_path_len = 0;
+
+ TRACE("%s\n", __func__);
+
+ emul_bin_path = get_bin_path();
+ if (!emul_bin_path) {
+ ERR("failed to get emulator path.\n");
+ return NULL;
+ }
+
+ sdk_info_path_len = strlen(emul_bin_path) + strlen(sdk_info) + 1;
+ sdk_info_file_path = g_malloc(sdk_info_path_len);
+ if (!sdk_info_file_path) {
+ ERR("failed to allocate sdk-data buffer.\n");
+ return NULL;
+ }
+
+ g_snprintf(sdk_info_file_path, sdk_info_path_len, "%s%s",
+ emul_bin_path, sdk_info);
+ INFO("sdk.info path: %s\n", sdk_info_file_path);
+
+ sdk_info_fp = fopen(sdk_info_file_path, "r");
+ g_free(sdk_info_file_path);
+
+ if (sdk_info_fp) {
+ TRACE("Succeeded to open [sdk.info].\n");
+
+ char tmp[256] = { '\0', };
+ char *tmpline = NULL;
+ while (fgets(tmp, sizeof(tmp), sdk_info_fp) != NULL) {
+ if ((tmpline = g_strstr_len(tmp, sizeof(tmp), sdk_data_var))) {
+ tmpline += strlen(sdk_data_var) + 1; // 1 for '='
+ break;
+ }
+ }
+
+ if (tmpline) {
+ if (tmpline[strlen(tmpline) - 1] == '\n') {
+ tmpline[strlen(tmpline) - 1] = '\0';
+ }
+ if (tmpline[strlen(tmpline) - 1] == '\r') {
+ tmpline[strlen(tmpline) - 1] = '\0';
+ }
+
+ tizen_sdk_data_path = g_malloc(strlen(tmpline) + 1);
+ g_strlcpy(tizen_sdk_data_path, tmpline, strlen(tmpline) + 1);
+
+ INFO("tizen-sdk-data path: %s\n", tizen_sdk_data_path);
+
+ fclose(sdk_info_fp);
+ return tizen_sdk_data_path;
+ }
+
+ fclose(sdk_info_fp);
+ }
+
+ // legacy mode
+ ERR("Failed to open [sdk.info].\n");
+
+ return get_old_tizen_sdk_data_path();
+}
+
- int msglen = 0, datalen = 0;
- type_length length = 0;
- type_group group = grp;
- type_action action = act;
++static void handle_sdcard(char* dataBuf, size_t dataLen)
+{
- if (cmd == NULL || cmdlen > 10)
- return;
-
- if (on == NULL) {
- msglen = 14;
- } else {
- datalen = strlen(on);
- length = (unsigned short)datalen;
-
- msglen = datalen + 15;
- }
-
- char* status_msg = (char*) malloc(msglen);
- if(!status_msg)
- return;
-
- memset(status_msg, 0, msglen);
-
- memcpy(status_msg, cmd, cmdlen);
- memcpy(status_msg + 10, &length, sizeof(unsigned short));
- memcpy(status_msg + 12, &group, sizeof(unsigned char));
- memcpy(status_msg + 13, &action, sizeof(unsigned char));
-
- if (on != NULL) {
- memcpy(status_msg + 14, on, datalen);
- }
-
- send_injector_ntf(status_msg, msglen);
-
- if (status_msg)
- free(status_msg);
- }
-
- static bool handle_sdcard(char* dataBuf, size_t dataLen)
- {
- int err_no = 0;
+
- INFO("handle_sdcard() data: %s\n", dataBuf);
- if (dataBuf != NULL) {
+ char ret = 0;
- //mloop_evcmd_usbdisk(NULL);
- char sdcard_img_path[256];
- char* sdcard_path = NULL;
-
- sdcard_path = get_emulator_sdcard_path();
- if (sdcard_path) {
- g_strlcpy(sdcard_img_path, sdcard_path,
- sizeof(sdcard_img_path));
-
- /* emulator_sdcard_img_path + sdcard img name */
- char* sdcard_img_name = dataBuf+2;
- if (dataLen > 3 && sdcard_img_name != NULL) {
- char* pLinechange = strchr(sdcard_img_name, '\n');
- if(pLinechange != NULL){
- sdcard_img_name = g_strndup(sdcard_img_name, pLinechange - sdcard_img_name);
- }
-
- g_strlcat(sdcard_img_path, sdcard_img_name, sizeof(sdcard_img_path));
- INFO("sdcard path: [%s]\n", sdcard_img_path);
-
- /*if using strndup than free string*/
- if (pLinechange != NULL && sdcard_img_name!= NULL) {
- free(sdcard_img_name);
- }
- }
- g_free(sdcard_path);
-
- }
- err_no = remove_sdcard_lock_os(sdcard_img_path);
- INFO("umount err_no: %d\n", err_no);
- if (errno == 0 && is_sdcard_attached) {
- mloop_evcmd_sdcard(NULL);
- is_sdcard_attached = false;
- } else {
- ERR("failed to umount: %s\n", sdcard_img_path);
- send_gen_injector_ntf(MSG_TYPE_SDCARD, 6, 11, err_no, NULL);
- return err_no;
- }
- }
- else if (ret == '1') {
++
++ if (dataBuf != NULL){
+ ret = dataBuf[0];
+
+ if (ret == '0' ) {
+ /* umount sdcard */
- if (dataLen > 3 && sdcard_img_name != NULL) {
++ do_hotplug(DETACH_SDCARD, NULL, 0);
++ } else if (ret == '1') {
+ /* mount sdcard */
+ char sdcard_img_path[256];
+ char* sdcard_path = NULL;
+
+ sdcard_path = get_emulator_sdcard_path();
+ if (sdcard_path) {
+ g_strlcpy(sdcard_img_path, sdcard_path,
+ sizeof(sdcard_img_path));
+
+ /* emulator_sdcard_img_path + sdcard img name */
+ char* sdcard_img_name = dataBuf+2;
- //mloop_evcmd_usbdisk(sdcard_img_path);
- if (!is_sdcard_attached && make_sdcard_lock_os(sdcard_img_path)) {
- mloop_evcmd_sdcard(sdcard_img_path);
- is_sdcard_attached = true;
- } else {
- send_gen_injector_ntf(MSG_TYPE_SDCARD, 6, 11, 5, NULL);
- return ERR_LCK;
- }
++ if(dataLen > 3 && sdcard_img_name != NULL){
+ char* pLinechange = strchr(sdcard_img_name, '\n');
+ if(pLinechange != NULL){
+ sdcard_img_name = g_strndup(sdcard_img_name, pLinechange - sdcard_img_name);
+ }
+
+ g_strlcat(sdcard_img_path, sdcard_img_name, sizeof(sdcard_img_path));
+ TRACE("sdcard path: [%s]\n", sdcard_img_path);
+
- if (pLinechange != NULL && sdcard_img_name!= NULL) {
++ do_hotplug(ATTACH_SDCARD, sdcard_img_path, strlen(sdcard_img_path) + 1);
++
+ /*if using strndup than free string*/
- } else if (ret == '2') {
- TRACE("sdcard status 2 bypass\n" );
- } else {
++ if(pLinechange != NULL && sdcard_img_name!= NULL){
+ free(sdcard_img_name);
+ }
+
+ }
+
+ g_free(sdcard_path);
+ } else {
+ ERR("failed to get sdcard path!!\n");
+ }
- } else {
++ } else if(ret == '2'){
++ TRACE("sdcard status 2 bypass" );
++ }else {
+ ERR("!!! unknown command : %c\n", ret);
+ }
+
- return ERR_SUCCESS;
++ }else{
+ ERR("!!! unknown data : %c\n", ret);
+ }
- if (handle_sdcard((char*) msg->data.data, msg->data.len) > 0) {
- return false;
- }
+}
+
+static bool injector_req_sdcard(ECS_Client* ccli, ECS__InjectorReq* msg, char *cmd)
+{
+ if (msg->has_data) {
+ TRACE("msg(%zu) : %s\n", msg->data.len, msg->data.data);
- return injector_send(ccli, msg, cmd);
++ handle_sdcard((char*) msg->data.data, msg->data.len);
+ } else {
+ ERR("has no msg\n");
+ }
+
- if (!do_virtfs_detach()) {
++ injector_send(ccli, msg, cmd);
++
++ return true;
+}
+
+static void send_status_injector_ntf(const char* cmd, int cmdlen, int act, char* on)
+{
+ int msglen = 0, datalen = 0;
+ type_length length = 0;
+ type_group group = MSG_GROUP_STATUS;
+ type_action action = act;
+
+ if (cmd == NULL || cmdlen > 10)
+ return;
+
+ if (on == NULL) {
+ msglen = 14;
+ } else {
+ datalen = strlen(on);
+ length = (unsigned short)datalen;
+
+ msglen = datalen + 15;
+ }
+
+ char* status_msg = (char*) malloc(msglen);
+ if(!status_msg)
+ return;
+
+ memset(status_msg, 0, msglen);
+
+ memcpy(status_msg, cmd, cmdlen);
+ memcpy(status_msg + 10, &length, sizeof(unsigned short));
+ memcpy(status_msg + 12, &group, sizeof(unsigned char));
+ memcpy(status_msg + 13, &action, sizeof(unsigned char));
+
+ if (on != NULL) {
+ memcpy(status_msg + 14, on, datalen);
+ }
+
+ send_injector_ntf(status_msg, msglen);
+
+ if (status_msg)
+ free(status_msg);
+}
+
+static bool injector_req_sensor(ECS_Client* ccli, ECS__InjectorReq* msg, char *cmd)
+{
+ char data[MAX_INJECTOR_REQ_DATA];
+ type_group group;
+ type_action action;
+
+ memset(data, 0, MAX_INJECTOR_REQ_DATA);
+ group = (type_group) (msg->group & 0xff);
+ action = (type_action) (msg->action & 0xff);
+
+ if (group == MSG_GROUP_STATUS) {
+ switch (action) {
+ case MSG_ACT_BATTERY_LEVEL:
+ sprintf(data, "%d", get_power_capacity());
+ break;
+ case MSG_ACT_BATTERY_CHARGER:
+ sprintf(data, "%d", get_jack_charger());
+ break;
+ case MSG_ACT_USB:
+ sprintf(data, "%d", get_jack_usb());
+ break;
+ case MSG_ACT_EARJACK:
+ sprintf(data, "%d", get_jack_earjack());
+ break;
+ case MSG_ACT_LOCATION:
+ qemu_mutex_lock(&mutex_location_data);
+ sprintf(data, "%s", location_data);
+ qemu_mutex_unlock(&mutex_location_data);
+ break;
+ default:
+ return injector_send(ccli, msg, cmd);
+ }
+ TRACE("status : %s\n", data);
+ send_status_injector_ntf(MSG_TYPE_SENSOR, 6, action, data);
+ return true;
+ } else if (msg->data.data && msg->data.len > 0) {
+ set_injector_data((char*) msg->data.data);
+ return injector_send(ccli, msg, cmd);
+ }
+
+ return false;
+}
+
+static bool injector_req_guest(void)
+{
+ int value = 0;
+ qemu_mutex_lock(&mutex_guest_connection);
+ value = guest_connection;
+ qemu_mutex_unlock(&mutex_guest_connection);
+ send_status_injector_ntf(MSG_TYPE_GUEST, 5, value, NULL);
+ return true;
+}
+
+static bool injector_req_location(ECS_Client* ccli, ECS__InjectorReq* msg, char *cmd)
+{
+ if (msg->data.data != NULL && msg->data.len > 0) {
+ qemu_mutex_lock(&mutex_location_data);
+ snprintf(location_data, msg->data.len + 1, "%s", (char*)msg->data.data);
+ qemu_mutex_unlock(&mutex_location_data);
+ return injector_send(ccli, msg, cmd);
+ }
+
+ return false;
+}
+
+bool msgproc_injector_req(ECS_Client* ccli, ECS__InjectorReq* msg)
+{
+ char cmd[11];
+ bool ret = false;
+
+ strncpy(cmd, msg->category, sizeof(cmd) - 1);
+
+ if (!strcmp(cmd, MSG_TYPE_SDCARD)) {
+ ret = injector_req_sdcard(ccli, msg, cmd);
+ } else if (!strcmp(cmd, MSG_TYPE_SENSOR)) {
+ ret = injector_req_sensor(ccli, msg, cmd);
+ } else if (!strcmp(cmd, MSG_TYPE_GUEST)) {
+ ret = injector_req_guest();
+ } else if (!strcmp(cmd, MSG_TYPE_LOCATION)) {
+ ret = injector_req_location(ccli, msg, cmd);
+ } else {
+ ret = injector_send(ccli, msg, cmd);
+ }
+
+ return ret;
+}
+
+void ecs_suspend_lock_state(int state)
+{
+ int catlen;
+
+ ECS__InjectorReq msg = ECS__INJECTOR_REQ__INIT;
+ const char* category = "suspend";
+
+ catlen = strlen(category);
+ msg.category = (char*) g_malloc0(catlen + 1);
+ memcpy(msg.category, category, catlen);
+
+ msg.group = 5;
+ msg.action = state;
+
+ msgproc_injector_req(NULL, &msg);
+}
+
+#define MSG_GROUP_HDS 100
+static bool injector_req_handle(char* cat, type_action action)
+{
+ /*SD CARD msg process*/
+ if (!strcmp(cat, MSG_TYPE_SDCARD)) {
+ return false;
+ } else if (!strcmp(cat, "suspend")) {
+ ecs_suspend_lock_state(ecs_get_suspend_state());
+ return true;
+ } else if (!strcmp(cat, MSG_TYPE_GUEST)) {
+ INFO("emuld connection is %d\n", action);
+ qemu_mutex_lock(&mutex_guest_connection);
+ guest_connection = action;
+ qemu_mutex_unlock(&mutex_guest_connection);
+ return false;
+ } else if (!strcmp(cat, "hds")) {
+ INFO("hds status is %d\n", action);
+ switch (action) {
+ case 1:
+ make_send_device_ntf(cat, MSG_GROUP_HDS, action, NULL);
+ break;
+ case 2:
+ make_send_device_ntf(cat, MSG_GROUP_HDS, action, NULL);
+ break;
+ case 3:
++ do_hotplug(DETACH_HDS, NULL, 0);
++ if (!is_hds_attached()) {
+ make_send_device_ntf(cat, MSG_GROUP_HDS, 5, NULL);
+ } else {
+ make_send_device_ntf(cat, MSG_GROUP_HDS, action, NULL);
+ }
+ break;
+ case 4:
+ make_send_device_ntf(cat, MSG_GROUP_HDS, action, NULL);
+ break;
+ default:
+ ERR("unknown action: %s.\n", action);
+ break;
+ }
+ return true;
+ } else {
+ ERR("unknown command: %s.\n", cat);
+ }
+
+ return false;
+}
+
+bool send_injector_ntf(const char* data, const int len)
+{
+ type_length length = 0;
+ type_group group = 0;
+ type_action action = 0;
+
+ const int catsize = 10;
+ char cat[catsize + 1];
+ memset(cat, 0, catsize + 1);
+
+ read_val_str(data, cat, catsize);
+ read_val_short(data + catsize, &length);
+ read_val_char(data + catsize + 2, &group);
+ read_val_char(data + catsize + 2 + 1, &action);
+
+ if (injector_req_handle(cat, action)) {
+ return true;
+ }
+
+ const char* ijdata = (data + catsize + 2 + 1 + 1);
+
+ TRACE("<< header cat = %s, length = %d, action=%d, group=%d\n", cat, length,action, group);
+
+ ECS__Master master = ECS__MASTER__INIT;
+ ECS__InjectorNtf ntf = ECS__INJECTOR_NTF__INIT;
+
+ ntf.category = (char*) g_malloc(catsize + 1);
+ strncpy(ntf.category, cat, 10);
+
+ ntf.length = length;
+ ntf.group = group;
+ ntf.action = action;
+
+ if (length > 0)
+ {
+ ntf.has_data = 1;
+
+ ntf.data.data = g_malloc(length);
+ ntf.data.len = length;
+ memcpy(ntf.data.data, ijdata, length);
+ }
+
+ master.type = ECS__MASTER__TYPE__INJECTOR_NTF;
+ master.injector_ntf = &ntf;
+
+ pb_to_all_clients(&master);
+
+ if (ntf.data.len > 0)
+ {
+ g_free(ntf.data.data);
+ }
+
+ g_free(ntf.category);
+
+ return true;
+}
+
--- /dev/null
- #include "hw/maru_virtio_nfc.h"
+/* Emulator Control Server
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * Jinhyung choi <jinhyung2.choi@samsung.com>
+ * MunKyu Im <munkyu.im@samsung.com>
+ * Daiyoung Kim <daiyoung777.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#include "qemu-common.h"
+
++#include "hw/virtio/maru_virtio_nfc.h"
+
+#include "ecs.h"
+
+#include "debug_ch.h"
+
+MULTI_DEBUG_CHANNEL(qemu, ecs);
+
+bool msgproc_nfc_req(ECS_Client* ccli, ECS__NfcReq* msg)
+{
+ int datalen = msg->data.len;
+ void* data = (void*)g_malloc(datalen);
+ if(!data) {
+ ERR("g_malloc failed!\n");
+ return false;
+ }
+
+ memset(data, 0, datalen);
+ memcpy(data, msg->data.data, msg->data.len);
+
+ if (msg->has_data && msg->data.len > 0)
+ {
+ TRACE("recv from nfc injector: %s, %z\n", msg->has_data, msg->data.len);
+ print_binary(data, datalen);
+ }
+
+ send_to_nfc(ccli->client_id, ccli->client_type, data, msg->data.len);
+ g_free(data);
+ return true;
+}
+
+bool send_nfc_ntf(struct nfc_msg_info* msg)
+{
+ const int catsize = 10;
+ char cat[catsize + 1];
+ ECS_Client *clii;
+ memset(cat, 0, catsize + 1);
+
+ print_binary((char*)msg->buf, msg->use);
+ TRACE("id: %02x, type: %02x, use: %d\n", msg->client_id, msg->client_type, msg->use);
+ clii = find_client(msg->client_id, msg->client_type);
+ if (clii) {
+ if(clii->client_type == TYPE_SIMUL_NFC) {
+ strncpy(cat, MSG_TYPE_NFC, 3);
+ } else if (clii->client_type == TYPE_ECP) {
+ strncpy(cat, MSG_TYPE_SIMUL_NFC, 9);
+ }else {
+ ERR("cannot find type! : %d\n", clii->client_type);
+ }
+ TRACE("header category = %s\n", cat);
+ }
+ else {
+ ERR("cannot find client!\n");
+ }
+
+ ECS__Master master = ECS__MASTER__INIT;
+ ECS__NfcNtf ntf = ECS__NFC_NTF__INIT;
+
+ ntf.category = (char*) g_malloc(catsize + 1);
+ strncpy(ntf.category, cat, 10);
+
+ ntf.has_data = 1;
+
+ ntf.data.data = g_malloc(NFC_MAX_BUF_SIZE);
+ ntf.data.len = NFC_MAX_BUF_SIZE;
+ memcpy(ntf.data.data, msg->buf, NFC_MAX_BUF_SIZE);
+
+ TRACE("send to nfc injector: \n");
+ master.type = ECS__MASTER__TYPE__NFC_NTF;
+ master.nfc_ntf = &ntf;
+
+ pb_to_all_clients(&master);
+
+ if (ntf.data.data && ntf.data.len > 0)
+ {
+ g_free(ntf.data.data);
+ }
+
+ if (ntf.category)
+ g_free(ntf.category);
+
+ return true;
+}
+
+
#ifndef __EMUL_STATE_H__
#define __EMUL_STATE_H__
- #include "maru_common.h"
- #include "maru_finger.h"
+
+ #include "display/maru_finger.h"
+
+ #define SUPPORT_LEGACY_ARGS
+ #define MAX_ADDR_LEN 256
+ #define MAX_PORT_LEN 256
+#define MAX_ADDR_LEN 256
+#define MAX_PORT_LEN 256
+
enum {
RESET = 0,
BOOT_COMPLETED = 1,
--- /dev/null
- // FIXME: improve error handling
- // return false;
+ /*
+ * Virtual Codec Device
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * Kitae Kim <kt920.kim@samsung.com>
+ * SeokYeon Hwang <syeon.hwang@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+ #include "maru_brillcodec.h"
+
+ #include "libavresample/avresample.h"
+ #include "libavutil/mathematics.h"
+ #include "libavutil/opt.h"
+ #include "libavformat/avformat.h"
+
+ #include "debug_ch.h"
+
+ /* define debug channel */
+ MULTI_DEBUG_CHANNEL(qemu, brillcodec);
+
+ // device memory
+ #define CODEC_META_DATA_SIZE (256)
+
+ // libav
+ #define GEN_MASK(x) ((1 << (x)) - 1)
+ #define ROUND_UP_X(v, x) (((v) + GEN_MASK(x)) & ~GEN_MASK(x))
+ #define ROUND_UP_2(x) ROUND_UP_X(x, 1)
+ #define ROUND_UP_4(x) ROUND_UP_X(x, 2)
+ #define ROUND_UP_8(x) ROUND_UP_X(x, 3)
+ #define DIV_ROUND_UP_X(v, x) (((v) + GEN_MASK(x)) >> (x))
+
+ #define DEFAULT_VIDEO_GOP_SIZE 15
+
+ enum codec_api_type {
+ CODEC_INIT = 0,
+ CODEC_DECODE_VIDEO,
+ CODEC_ENCODE_VIDEO,
+ CODEC_DECODE_AUDIO,
+ CODEC_ENCODE_AUDIO,
+ CODEC_PICTURE_COPY,
+ CODEC_DEINIT,
+ CODEC_FLUSH_BUFFERS,
+ };
+
+ enum codec_type {
+ CODEC_TYPE_UNKNOWN = -1,
+ CODEC_TYPE_DECODE,
+ CODEC_TYPE_ENCODE,
+ };
+
+ struct video_data {
+ int32_t width;
+ int32_t height;
+ int32_t fps_n;
+ int32_t fps_d;
+ int32_t par_n;
+ int32_t par_d;
+ int32_t pix_fmt;
+ int32_t bpp;
+ int32_t ticks_per_frame;
+ };
+
+ struct audio_data {
+ int32_t channels;
+ int32_t sample_rate;
+ int32_t block_align;
+ int32_t depth;
+ int32_t sample_fmt;
+ int32_t frame_size;
+ int32_t bits_per_smp_fmt;
+ int32_t reserved;
+ int64_t channel_layout;
+ };
+
+ DeviceMemEntry *entry[CODEC_CONTEXT_MAX];
+
+ // define a queue to manage ioparam, context data
+ typedef struct CodecDataStg {
+ CodecParam *param_buf;
+ DeviceMemEntry *data_buf;
+
+ QTAILQ_ENTRY(CodecDataStg) node;
+ } CodecDataStg;
+
+ // define two queue to store input and output buffers.
+ struct codec_wq codec_wq = QTAILQ_HEAD_INITIALIZER(codec_wq);
+ static QTAILQ_HEAD(codec_rq, CodecDataStg) codec_rq =
+ QTAILQ_HEAD_INITIALIZER(codec_rq);
+
+ // codec functions
+ static bool codec_init(MaruBrillCodecState *, int, void *);
+ static bool codec_deinit(MaruBrillCodecState *, int, void *);
+ static bool codec_decode_video(MaruBrillCodecState *, int, void *);
+ static bool codec_encode_video(MaruBrillCodecState *, int, void *);
+ static bool codec_decode_audio(MaruBrillCodecState *, int, void *);
+ static bool codec_encode_audio(MaruBrillCodecState *, int, void *);
+ static bool codec_picture_copy(MaruBrillCodecState *, int, void *);
+ static bool codec_flush_buffers(MaruBrillCodecState *, int, void *);
+
+ typedef bool (*CodecFuncEntry)(MaruBrillCodecState *, int, void *);
+ static CodecFuncEntry codec_func_handler[] = {
+ codec_init,
+ codec_decode_video,
+ codec_encode_video,
+ codec_decode_audio,
+ codec_encode_audio,
+ codec_picture_copy,
+ codec_deinit,
+ codec_flush_buffers,
+ };
+
+ static AVCodecParserContext *maru_brill_codec_parser_init(AVCodecContext *avctx);
+
+ static void maru_brill_codec_push_readqueue(MaruBrillCodecState *s, CodecParam *ioparam);
+ static void maru_brill_codec_push_writequeue(MaruBrillCodecState *s, void* opaque,
+ size_t data_size, int ctx_id,
+ DataHandler *handler);
+
+ static void *maru_brill_codec_store_inbuf(uint8_t *mem_base, CodecParam *ioparam);
+
+ // default handler
+ static void default_get_data(void *dst, void *src, size_t size, enum AVPixelFormat pix_fmt) {
+ memcpy(dst, src, size);
+ }
+
+ static void default_release(void *opaque) {
+ g_free(opaque);
+ }
+
+ static DataHandler default_data_handler = {
+ .get_data = default_get_data,
+ .release = default_release,
+ };
+
+
+ // default video decode data handler
+ static void extract(void *dst, void *src, size_t size, enum AVPixelFormat pix_fmt) {
+ AVFrame *frame = (AVFrame *)src;
+ avpicture_layout((AVPicture *)src, pix_fmt, frame->width, frame->height, dst, size);
+ }
+
+ static void release(void *buf) {}
+
+ static DataHandler default_video_decode_data_handler = {
+ .get_data = extract,
+ .release = release,
+ };
+
+ static void maru_brill_codec_thread_exit(MaruBrillCodecState *s)
+ {
+ int index;
+
+ TRACE("enter: %s\n", __func__);
+
+ /* stop to run dedicated threads. */
+ s->is_thread_running = false;
+
+ for (index = 0; index < s->worker_thread_cnt; index++) {
+ qemu_thread_join(&s->threadpool.threads[index]);
+ }
+
+ TRACE("destroy mutex and conditional.\n");
+ qemu_mutex_destroy(&s->threadpool.mutex);
+ qemu_cond_destroy(&s->threadpool.cond);
+
+ if (s->threadpool.threads) {
+ g_free(s->threadpool.threads);
+ s->threadpool.threads = NULL;
+ }
+
+ TRACE("leave: %s\n", __func__);
+ }
+
+ void maru_brill_codec_wakeup_threads(MaruBrillCodecState *s, int api_index)
+ {
+ CodecParam *ioparam = NULL;
+
+ ioparam = g_malloc0(sizeof(CodecParam));
+ if (!ioparam) {
+ ERR("failed to allocate ioparam\n");
+ return;
+ }
+
+ memcpy(ioparam, &s->ioparam, sizeof(CodecParam));
+
+ TRACE("wakeup thread. ctx_id: %u, api_id: %u, mem_offset: 0x%x\n",
+ ioparam->ctx_index, ioparam->api_index, ioparam->mem_offset);
+
+ qemu_mutex_lock(&s->context_mutex);
+
+ if (ioparam->api_index != CODEC_INIT) {
+ if (!CONTEXT(s, ioparam->ctx_index).opened_context) {
+ INFO("abandon api %d for context %d\n",
+ ioparam->api_index, ioparam->ctx_index);
+ qemu_mutex_unlock(&s->context_mutex);
+ return;
+ }
+ }
+
+ qemu_mutex_unlock(&s->context_mutex);
+
+ maru_brill_codec_push_readqueue(s, ioparam);
+
+ qemu_mutex_lock(&s->context_mutex);
+ // W/A for threads starvation.
+ while (s->idle_thread_cnt == 0) {
+ qemu_mutex_unlock(&s->context_mutex);
+ TRACE("Worker threads are exhausted\n");
+ usleep(2000); // wait 2ms.
+ qemu_mutex_lock(&s->context_mutex);
+ }
+ qemu_cond_signal(&s->threadpool.cond);
+ qemu_mutex_unlock(&s->context_mutex);
+
+ TRACE("after sending conditional signal\n");
+ }
+
+ void *maru_brill_codec_threads(void *opaque)
+ {
+ MaruBrillCodecState *s = (MaruBrillCodecState *)opaque;
+ bool ret = false;
+
+ TRACE("enter: %s\n", __func__);
+
+ while (s->is_thread_running) {
+ int ctx_id = 0, api_id = 0;
+ CodecDataStg *elem = NULL;
+ DeviceMemEntry *indata_buf = NULL;
+
+ qemu_mutex_lock(&s->context_mutex);
+ ++(s->idle_thread_cnt); // protected under mutex.
+ qemu_cond_wait(&s->threadpool.cond, &s->context_mutex);
+ --(s->idle_thread_cnt); // protected under mutex.
+ qemu_mutex_unlock(&s->context_mutex);
+
+ qemu_mutex_lock(&s->ioparam_queue_mutex);
+ elem = QTAILQ_FIRST(&codec_rq);
+ if (elem) {
+ QTAILQ_REMOVE(&codec_rq, elem, node);
+ qemu_mutex_unlock(&s->ioparam_queue_mutex);
+ } else {
+ qemu_mutex_unlock(&s->ioparam_queue_mutex);
+ continue;
+ }
+
+ if (!elem->param_buf) {
+ continue;
+ }
+
+ api_id = elem->param_buf->api_index;
+ ctx_id = elem->param_buf->ctx_index;
+
+ indata_buf = elem->data_buf;
+
+ TRACE("api_id: %d ctx_id: %d\n", api_id, ctx_id);
+
+ qemu_mutex_lock(&s->context_mutex);
+ CONTEXT(s, ctx_id).occupied_thread = true;
+ qemu_mutex_unlock(&s->context_mutex);
+
+ ret = codec_func_handler[api_id](s, ctx_id, indata_buf);
+ if (!ret) {
+ ERR("fail api %d for context %d\n", api_id, ctx_id);
+ g_free(elem->param_buf);
+ continue;
+ }
+
+ TRACE("release a buffer of CodecParam\n");
+ g_free(elem->param_buf);
+ elem->param_buf = NULL;
+
+ if (elem->data_buf) {
+ if (elem->data_buf->opaque) {
+ TRACE("release inbuf\n");
+ g_free(elem->data_buf->opaque);
+ elem->data_buf->opaque = NULL;
+ }
+
+ TRACE("release a buffer indata_buf\n");
+ g_free(elem->data_buf);
+ elem->data_buf = NULL;
+ }
+
+ TRACE("release an element of CodecDataStg\n");
+ g_free(elem);
+
+ qemu_mutex_lock(&s->context_mutex);
+ if (CONTEXT(s, ctx_id).requested_close) {
+ INFO("make worker thread to handle deinit\n");
+ // codec_deinit(s, ctx_id, NULL);
+ maru_brill_codec_release_context(s, ctx_id);
+ CONTEXT(s, ctx_id).requested_close = false;
+ }
+ qemu_mutex_unlock(&s->context_mutex);
+
+ TRACE("switch context to raise interrupt.\n");
+ qemu_bh_schedule(s->codec_bh);
+
+ qemu_mutex_lock(&s->context_mutex);
+ CONTEXT(s, ctx_id).occupied_thread = false;
+ qemu_mutex_unlock(&s->context_mutex);
+ }
+
+ maru_brill_codec_thread_exit(s);
+
+ TRACE("leave: %s\n", __func__);
+ return NULL;
+ }
+
+ // queue
+ static void maru_brill_codec_push_readqueue(MaruBrillCodecState *s,
+ CodecParam *ioparam)
+ {
+ CodecDataStg *elem = NULL;
+ DeviceMemEntry *data_buf = NULL;
+
+ elem = g_malloc0(sizeof(CodecDataStg));
+ if (!elem) {
+ ERR("failed to allocate ioparam_queue. %d\n", sizeof(CodecDataStg));
+ return;
+ }
+
+ elem->param_buf = ioparam;
+
+ switch(ioparam->api_index) {
+ case CODEC_INIT ... CODEC_ENCODE_AUDIO:
+ data_buf = maru_brill_codec_store_inbuf((uint8_t *)s->vaddr, ioparam);
+ break;
+ default:
+ TRACE("no buffer from guest\n");
+ break;
+ }
+
+ elem->data_buf = data_buf;
+
+ qemu_mutex_lock(&s->ioparam_queue_mutex);
+ QTAILQ_INSERT_TAIL(&codec_rq, elem, node);
+ qemu_mutex_unlock(&s->ioparam_queue_mutex);
+ }
+
+ static void *maru_brill_codec_store_inbuf(uint8_t *mem_base,
+ CodecParam *ioparam)
+ {
+ DeviceMemEntry *elem = NULL;
+ int readbuf_size, size = 0;
+ uint8_t *readbuf = NULL;
+ uint8_t *device_mem = mem_base + ioparam->mem_offset;
+
+ elem = g_malloc0(sizeof(DeviceMemEntry));
+ if (!elem) {
+ ERR("failed to allocate readqueue node. size: %d\n",
+ sizeof(DeviceMemEntry));
+ return NULL;
+ }
+
+ memcpy(&readbuf_size, device_mem, sizeof(readbuf_size));
+ size = sizeof(readbuf_size);
+
+ TRACE("readbuf size: %d\n", readbuf_size);
+ if (readbuf_size <= 0) {
+ TRACE("inbuf size is 0. api_id %d, ctx_id %d, mem_offset %x\n",
+ ioparam->api_index, ioparam->ctx_index, ioparam->mem_offset);
+ } else {
+ readbuf = g_malloc0(readbuf_size);
+ if (!readbuf) {
+ ERR("failed to allocate a read buffer. size: %d\n", readbuf_size);
+ } else {
+ TRACE("copy input buffer from guest. ctx_id: %d, mem_offset: %x\n",
+ ioparam->ctx_index, ioparam->mem_offset);
+ memcpy(readbuf, device_mem + size, readbuf_size);
+ }
+ }
+ // memset(device_mem, 0x00, sizeof(readbuf_size));
+
+ elem->opaque = readbuf;
+ elem->data_size = readbuf_size;
+ elem->ctx_id = ioparam->ctx_index;
+
+ return elem;
+ }
+
+ static void maru_brill_codec_push_writequeue(MaruBrillCodecState *s, void* opaque,
+ size_t data_size, int ctx_id,
+ DataHandler *handler)
+ {
+ DeviceMemEntry *elem = NULL;
+ elem = g_malloc0(sizeof(DeviceMemEntry));
+
+ elem->opaque = opaque;
+ elem->data_size = data_size;
+ elem->ctx_id = ctx_id;
+
+ if (handler) {
+ elem->handler = handler;
+ } else {
+ elem->handler = &default_data_handler;
+ }
+
+ qemu_mutex_lock(&s->context_queue_mutex);
+ QTAILQ_INSERT_TAIL(&codec_wq, elem, node);
+ qemu_mutex_unlock(&s->context_queue_mutex);
+ }
+
+ void maru_brill_codec_pop_writequeue(MaruBrillCodecState *s, uint32_t ctx_idx)
+ {
+ DeviceMemEntry *elem = NULL;
+ uint32_t mem_offset = 0;
+
+ TRACE("enter: %s\n", __func__);
+
+ if (ctx_idx < 1 || ctx_idx > (CODEC_CONTEXT_MAX - 1)) {
+ ERR("invalid buffer index. %d\n", ctx_idx);
+ return;
+ }
+
+ TRACE("pop_writeqeue. context index: %d\n", ctx_idx);
+ elem = entry[ctx_idx];
+ if (elem) {
+ mem_offset = s->ioparam.mem_offset;
+
+ // check corrupted mem_offset
+ if (mem_offset < CODEC_MEM_SIZE) {
+ elem->handler->get_data(s->vaddr + mem_offset, elem->opaque, elem->data_size, s->context[ctx_idx].avctx->pix_fmt);
+ elem->handler->release(elem->opaque);
+ } else {
+ TRACE("mem_offset is corrupted!!\n");
+ }
+
+ TRACE("pop_writequeue. release elem: %p\n", elem);
+ g_free(elem);
+
+ entry[ctx_idx] = NULL;
+ } else {
+ TRACE("there is no buffer to copy data to guest\n");
+ }
+
+ TRACE("leave: %s\n", __func__);
+ }
+
+ static void serialize_video_data(const struct video_data *video,
+ AVCodecContext *avctx)
+ {
+ if (video->width) {
+ avctx->width = video->width;
+ }
+ if (video->height) {
+ avctx->height = video->height;
+ }
+ if (video->fps_n) {
+ avctx->time_base.num = video->fps_n;
+ }
+ if (video->fps_d) {
+ avctx->time_base.den = video->fps_d;
+ }
+ if (video->pix_fmt > PIX_FMT_NONE) {
+ avctx->pix_fmt = video->pix_fmt;
+ }
+ if (video->par_n) {
+ avctx->sample_aspect_ratio.num = video->par_n;
+ }
+ if (video->par_d) {
+ avctx->sample_aspect_ratio.den = video->par_d;
+ }
+ if (video->bpp) {
+ avctx->bits_per_coded_sample = video->bpp;
+ }
+ if (video->ticks_per_frame) {
+ avctx->ticks_per_frame = video->ticks_per_frame;
+ }
+
+ INFO("codec_init. video, resolution: %dx%d, framerate: %d/%d "
+ "pixel_fmt: %d sample_aspect_ratio: %d/%d bpp %d\n",
+ avctx->width, avctx->height, avctx->time_base.num,
+ avctx->time_base.den, avctx->pix_fmt, avctx->sample_aspect_ratio.num,
+ avctx->sample_aspect_ratio.den, avctx->bits_per_coded_sample);
+ }
+
+ static void deserialize_video_data (const AVCodecContext *avctx,
+ struct video_data *video)
+ {
+ memset(video, 0x00, sizeof(struct video_data));
+
+ video->width = avctx->width;
+ video->height = avctx->height;
+ video->fps_n = avctx->time_base.num;
+ video->fps_d = avctx->time_base.den;
+ video->pix_fmt = avctx->pix_fmt;
+ video->par_n = avctx->sample_aspect_ratio.num;
+ video->par_d = avctx->sample_aspect_ratio.den;
+ video->bpp = avctx->bits_per_coded_sample;
+ video->ticks_per_frame = avctx->ticks_per_frame;
+ }
+
+ static void serialize_audio_data (const struct audio_data *audio,
+ AVCodecContext *avctx)
+ {
+ if (audio->channels) {
+ avctx->channels = audio->channels;
+ }
+ if (audio->sample_rate) {
+ avctx->sample_rate = audio->sample_rate;
+ }
+ if (audio->block_align) {
+ avctx->block_align = audio->block_align;
+ }
+
+ if (audio->sample_fmt > AV_SAMPLE_FMT_NONE) {
+ avctx->sample_fmt = audio->sample_fmt;
+ }
+
+ INFO("codec_init. audio, channel %d sample_rate %d sample_fmt %d ch_layout %lld\n",
+ avctx->channels, avctx->sample_rate, avctx->sample_fmt, avctx->channel_layout);
+ }
+
+ void maru_brill_codec_release_context(MaruBrillCodecState *s, int32_t ctx_id)
+ {
+ DeviceMemEntry *wq_elem = NULL, *wnext = NULL;
+ CodecDataStg *rq_elem = NULL, *rnext = NULL;
+
+ TRACE("enter: %s\n", __func__);
+
+ TRACE("release %d of context\n", ctx_id);
+
+ qemu_mutex_lock(&s->threadpool.mutex);
+ if (CONTEXT(s, ctx_id).opened_context) {
+ // qemu_mutex_unlock(&s->threadpool.mutex);
+ codec_deinit(s, ctx_id, NULL);
+ // qemu_mutex_lock(&s->threadpool.mutex);
+ }
+ CONTEXT(s, ctx_id).occupied_context = false;
+ qemu_mutex_unlock(&s->threadpool.mutex);
+
+ // TODO: check if foreach statment needs lock or not.
+ QTAILQ_FOREACH_SAFE(rq_elem, &codec_rq, node, rnext) {
+ if (rq_elem && rq_elem->data_buf &&
+ (rq_elem->data_buf->ctx_id == ctx_id)) {
+
+ TRACE("remove unused node from codec_rq. ctx_id: %d\n", ctx_id);
+ qemu_mutex_lock(&s->context_queue_mutex);
+ QTAILQ_REMOVE(&codec_rq, rq_elem, node);
+ qemu_mutex_unlock(&s->context_queue_mutex);
+ if (rq_elem && rq_elem->data_buf) {
+ TRACE("release rq_buffer: %p\n", rq_elem->data_buf);
+ g_free(rq_elem->data_buf);
+ }
+
+ TRACE("release rq_elem: %p\n", rq_elem);
+ g_free(rq_elem);
+ } else {
+ TRACE("no elem of %d context in the codec_rq.\n", ctx_id);
+ }
+ }
+
+ QTAILQ_FOREACH_SAFE(wq_elem, &codec_wq, node, wnext) {
+ if (wq_elem && wq_elem->ctx_id == ctx_id) {
+ TRACE("remove unused node from codec_wq. ctx_id: %d\n", ctx_id);
+ qemu_mutex_lock(&s->context_queue_mutex);
+ QTAILQ_REMOVE(&codec_wq, wq_elem, node);
+ qemu_mutex_unlock(&s->context_queue_mutex);
+
+ if (wq_elem && wq_elem->opaque) {
+ TRACE("release wq_buffer: %p\n", wq_elem->opaque);
+ g_free(wq_elem->opaque);
+ wq_elem->opaque = NULL;
+ }
+
+ TRACE("release wq_elem: %p\n", wq_elem);
+ g_free(wq_elem);
+ } else {
+ TRACE("no elem of %d context in the codec_wq.\n", ctx_id);
+ }
+ }
+
+ TRACE("leave: %s\n", __func__);
+ }
+
+ int maru_brill_codec_query_list (MaruBrillCodecState *s)
+ {
+ AVCodec *codec = NULL;
+ uint32_t size = 0, mem_size = 0;
+ uint32_t data_len = 0, length = 0;
+ int32_t codec_type, media_type;
+ int32_t codec_fmts[4], i;
+
+ /* register avcodec */
+ TRACE("register avcodec\n");
+ av_register_all();
+
+ codec = av_codec_next(NULL);
+ if (!codec) {
+ ERR("failed to get codec info.\n");
+ return -1;
+ }
+
+ // a region to store the number of codecs.
+ length = 32 + 64 + 6 * sizeof(int32_t);
+ mem_size = size = sizeof(uint32_t);
+
+ while (codec) {
+ codec_type =
+ codec->decode ? CODEC_TYPE_DECODE : CODEC_TYPE_ENCODE;
+ media_type = codec->type;
+
+ memset(codec_fmts, -1, sizeof(codec_fmts));
+ if (media_type == AVMEDIA_TYPE_VIDEO) {
+ if (codec->pix_fmts) {
+ for (i = 0; codec->pix_fmts[i] != -1 && i < 4; i++) {
+ codec_fmts[i] = codec->pix_fmts[i];
+ }
+ }
+ } else if (media_type == AVMEDIA_TYPE_AUDIO) {
+ if (codec->sample_fmts) {
+ for (i = 0; codec->sample_fmts[i] != -1; i++) {
+ codec_fmts[i] = codec->sample_fmts[i];
+ }
+ }
+ } else {
+ ERR("unknown media type: %d\n", media_type);
+ }
+
+ memset(s->vaddr + mem_size, 0x00, length);
+ mem_size += length;
+
+ data_len += length;
+ memcpy(s->vaddr, &data_len, sizeof(data_len));
+
+ memcpy(s->vaddr + size, &codec_type, sizeof(codec_type));
+ size += sizeof(codec_type);
+ memcpy(s->vaddr + size, &media_type, sizeof(media_type));
+ size += sizeof(media_type);
+ memcpy(s->vaddr + size, codec->name, strlen(codec->name));
+ size += 32;
+ memcpy(s->vaddr + size,
+ codec->long_name, strlen(codec->long_name));
+ size += 64;
+ memcpy(s->vaddr + size, codec_fmts, sizeof(codec_fmts));
+ size += sizeof(codec_fmts);
+
+ TRACE("register %s %s\n", codec->name, codec->decode ? "decoder" : "encoder");
+ codec = av_codec_next(codec);
+ }
+
+ return 0;
+ }
+
+ int maru_brill_codec_get_context_index(MaruBrillCodecState *s)
+ {
+ int ctx_id;
+
+ TRACE("enter: %s\n", __func__);
+
+ // requires mutex_lock? its function is protected by critical section.
+ qemu_mutex_lock(&s->threadpool.mutex);
+ for (ctx_id = 1; ctx_id < CODEC_CONTEXT_MAX; ctx_id++) {
+ if (CONTEXT(s, ctx_id).occupied_context == false) {
+ TRACE("get %d of codec context successfully.\n", ctx_id);
+ CONTEXT(s, ctx_id).occupied_context = true;
+ break;
+ }
+ }
+ qemu_mutex_unlock(&s->threadpool.mutex);
+
+ if (ctx_id == CODEC_CONTEXT_MAX) {
+ ERR("failed to get available codec context. ");
+ ERR("try to run codec again.\n");
+ ctx_id = -1;
+ }
+
+ TRACE("leave: %s\n", __func__);
+
+ return ctx_id;
+ }
+
+
+ // allocate avcontext and avframe struct.
+ static AVCodecContext *maru_brill_codec_alloc_context(MaruBrillCodecState *s, int ctx_id)
+ {
+ TRACE("enter: %s\n", __func__);
+
+ TRACE("allocate %d of context and frame.\n", ctx_id);
+ CONTEXT(s, ctx_id).avctx = avcodec_alloc_context3(NULL);
+ CONTEXT(s, ctx_id).frame = avcodec_alloc_frame();
+ CONTEXT(s, ctx_id).opened_context = false;
+
+ TRACE("leave: %s\n", __func__);
+
+ return CONTEXT(s, ctx_id).avctx;
+ }
+
+ static AVCodec *maru_brill_codec_find_avcodec(uint8_t *mem_buf)
+ {
+ AVCodec *codec = NULL;
+ int32_t encode, size = 0;
+ char codec_name[32] = {0, };
+
+ memcpy(&encode, mem_buf, sizeof(encode));
+ size = sizeof(encode);
+ memcpy(codec_name, mem_buf + size, sizeof(codec_name));
+ size += sizeof(codec_name);
+
+ TRACE("type: %d, name: %s\n", encode, codec_name);
+
+ if (encode) {
+ codec = avcodec_find_encoder_by_name (codec_name);
+ } else {
+ codec = avcodec_find_decoder_by_name (codec_name);
+ }
+ INFO("%s!! find %s %s\n", codec ? "success" : "failure",
+ codec_name, encode ? "encoder" : "decoder");
+
+ return codec;
+ }
+
+ static void read_codec_init_data(AVCodecContext *avctx, uint8_t *mem_buf)
+ {
+ struct video_data video = { 0, };
+ struct audio_data audio = { 0, };
+ int bitrate = 0, size = 0;
+
+ memcpy(&video, mem_buf + size, sizeof(video));
+ size = sizeof(video);
+ serialize_video_data(&video, avctx);
+
+ memcpy(&audio, mem_buf + size, sizeof(audio));
+ size += sizeof(audio);
+ serialize_audio_data(&audio, avctx);
+
+ memcpy(&bitrate, mem_buf + size, sizeof(bitrate));
+ size += sizeof(bitrate);
+ if (bitrate) {
+ avctx->bit_rate = bitrate;
+ }
+
+ memcpy(&avctx->codec_tag, mem_buf + size, sizeof(avctx->codec_tag));
+ size += sizeof(avctx->codec_tag);
+ memcpy(&avctx->extradata_size,
+ mem_buf + size, sizeof(avctx->extradata_size));
+ size += sizeof(avctx->extradata_size);
+ INFO("extradata size: %d.\n", avctx->extradata_size);
+
+ if (avctx->extradata_size > 0) {
+ avctx->extradata =
+ av_mallocz(ROUND_UP_X(avctx->extradata_size +
+ FF_INPUT_BUFFER_PADDING_SIZE, 4));
+ if (avctx->extradata) {
+ memcpy(avctx->extradata, mem_buf + size, avctx->extradata_size);
+ }
+ } else {
+ TRACE("no extra data.\n");
+ avctx->extradata =
+ av_mallocz(ROUND_UP_X(FF_INPUT_BUFFER_PADDING_SIZE, 4));
+ }
+ }
+
+ // write the result of codec_init
+ static int write_codec_init_data(AVCodecContext *avctx, uint8_t *mem_buf)
+ {
+ int size = 0;
+
+ if (avctx->codec->type == AVMEDIA_TYPE_AUDIO) {
+ int osize = av_get_bytes_per_sample(avctx->sample_fmt);
+
+ INFO("avcodec_open. sample_fmt %d, bytes_per_sample %d\n", avctx->sample_fmt, osize);
+
+ if ((avctx->codec_id == AV_CODEC_ID_AAC) && avctx->codec->encode2) {
+ osize = av_get_bytes_per_sample(AV_SAMPLE_FMT_S16);
+ }
+ memcpy(mem_buf, &avctx->sample_fmt, sizeof(avctx->sample_fmt));
+ size = sizeof(avctx->sample_fmt);
+
+ // frame_size: samples per packet, initialized when calling 'init'
+ memcpy(mem_buf + size, &avctx->frame_size, sizeof(avctx->frame_size));
+ size += sizeof(avctx->frame_size);
+
+ memcpy(mem_buf + size, &osize, sizeof(osize));
+ size += sizeof(osize);
+ }
+
+ return size;
+ }
+
+ static int convert_audio_sample_fmt(const AVCodec *codec, int codec_type, bool encode)
+ {
+ int audio_sample_fmt = AV_SAMPLE_FMT_NONE;
+
+ if (!codec) {
+ return audio_sample_fmt;
+ }
+
+ if (codec_type != AVMEDIA_TYPE_AUDIO) {
+ ERR("this codec_type is invalid %d\n", codec_type);
+ return audio_sample_fmt;
+ }
+
+ if (!strcmp(codec->name, "aac")) {
+ // FLOAT format
+ if (encode) {
+ audio_sample_fmt = AV_SAMPLE_FMT_FLTP;
+ } else {
+ audio_sample_fmt = AV_SAMPLE_FMT_FLT;
+ }
+ } else if (!strcmp(codec->name, "mp3") || !strcmp(codec->name, "mp3adu")) {
+ // S16 format
+ if (encode) {
+ audio_sample_fmt = AV_SAMPLE_FMT_S16P;
+ } else {
+ audio_sample_fmt = AV_SAMPLE_FMT_S16;
+ }
+ } else if (!strcmp(codec->name, "wmav1") || !strcmp(codec->name, "wmav2")) {
+ if (encode) {
+ audio_sample_fmt = AV_SAMPLE_FMT_FLTP;
+ } else {
+ audio_sample_fmt = AV_SAMPLE_FMT_FLT;
+ }
+ } else {
+ INFO("cannot handle %s codec\n", codec->name);
+ }
+
+ TRACE("convert audio sample_fmt %d\n", audio_sample_fmt);
+ return audio_sample_fmt;
+ }
+
+ static int fill_audio_into_frame(AVCodecContext *avctx, AVFrame *frame,
+ uint8_t *samples, int samples_size,
+ int nb_samples, int audio_sample_fmt)
+ {
+ int result = 0;
+
+ if (!avctx) {
+ ERR("fill_audio. AVCodecContext is NULL!!\n");
+ return -1;
+ }
+
+ if (!frame) {
+ ERR("fill_audio. AVFrame is NULL!!\n");
+ return -1;
+ }
+
+ frame->nb_samples = nb_samples;
+ frame->format = audio_sample_fmt;
+ frame->channel_layout = avctx->channel_layout;
+
+ result =
+ avcodec_fill_audio_frame(frame, avctx->channels, audio_sample_fmt, (const uint8_t *)samples, samples_size, 0);
+ TRACE("fill audio in_frame. ret: %d in_frame->ch_layout %lld\n", result, frame->channel_layout);
+
+ return result;
+ }
+
+ static AVFrame *resample_audio(AVCodecContext *avctx, AVFrame *sample_frame,
+ int sample_buffer_size, int in_sample_fmt,
+ AVFrame *resample_frame, int *resample_buffer_size,
+ int resample_sample_fmt)
+ {
+ AVAudioResampleContext *avr = NULL;
+ uint8_t *resample_buffer = NULL;
+ int buffer_size = 0;
+ int resample_nb_samples = sample_frame->nb_samples;
+
+ avr = avresample_alloc_context();
+ if (!avr) {
+ ERR("failed to allocate avresample context\n");
+ return NULL;
+ }
+
+ TRACE("channel_layout %lld sample_rate %d in_sample_fmt %d resample_sample_fmt %d\n",
+ avctx->channel_layout, avctx->sample_rate, avctx->sample_fmt, resample_sample_fmt);
+
+ av_opt_set_int(avr, "in_channel_layout", avctx->channel_layout, 0);
+ av_opt_set_int(avr, "in_sample_fmt", in_sample_fmt, 0);
+ av_opt_set_int(avr, "in_sample_rate", avctx->sample_rate, 0);
+
+ av_opt_set_int(avr, "out_channel_layout", avctx->channel_layout, 0);
+ av_opt_set_int(avr, "out_sample_fmt", resample_sample_fmt, 0);
+ av_opt_set_int(avr, "out_sample_rate", avctx->sample_rate, 0);
+
+ TRACE("open avresample context\n");
+ if (avresample_open(avr) < 0) {
+ ERR("failed to open avresample context\n");
+ avresample_free(&avr);
+ return NULL;
+ }
+
+ resample_frame = avcodec_alloc_frame();
+ TRACE("resample audio. nb_samples %d sample_fmt %d\n", resample_nb_samples, resample_sample_fmt);
+
+ *resample_buffer_size = av_samples_get_buffer_size(NULL, avctx->channels, resample_nb_samples, resample_sample_fmt, 0);
+ if (*resample_buffer_size < 0) {
+ ERR("failed to get size of resample buffer %d\n", *resample_buffer_size);
+ avresample_close(avr);
+ avresample_free(&avr);
+ return NULL;
+ }
+
+ resample_buffer = av_mallocz(*resample_buffer_size);
+ if (!resample_buffer) {
+ ERR("failed to allocate resample buffer\n");
+ avresample_close(avr);
+ avresample_free(&avr);
+ return NULL;
+ }
+
+ fill_audio_into_frame(avctx, resample_frame, resample_buffer,
+ *resample_buffer_size, resample_nb_samples, resample_sample_fmt);
+
+ buffer_size = avresample_convert(avr, resample_frame->data,
+ *resample_buffer_size, resample_nb_samples,
+ sample_frame->data, sample_buffer_size,
+ sample_frame->nb_samples);
+
+ TRACE("resample_audio buffer_size %d\n", buffer_size);
+
+ avresample_close(avr);
+ avresample_free(&avr);
+
+ return resample_frame;
+ }
+
+ static int parse_and_decode_video(AVCodecContext *avctx, AVFrame *picture,
+ AVCodecParserContext *pctx, int ctx_id,
+ AVPacket *packet, int *got_picture,
+ int idx, int64_t in_offset)
+ {
+ uint8_t *parser_outbuf = NULL;
+ int parser_outbuf_size = 0;
+ uint8_t *parser_buf = packet->data;
+ int parser_buf_size = packet->size;
+ int ret = 0, len = -1;
+ int64_t pts = 0, dts = 0, pos = 0;
+
+ pts = dts = idx;
+ pos = in_offset;
+
+ do {
+ if (pctx) {
+ ret = av_parser_parse2(pctx, avctx, &parser_outbuf,
+ &parser_outbuf_size, parser_buf, parser_buf_size,
+ pts, dts, pos);
+
+ if (ret) {
+ parser_buf_size -= ret;
+ parser_buf += ret;
+ }
+
+ TRACE("after parsing ret: %d parser_outbuf_size %d parser_buf_size %d pts %lld\n",
+ ret, parser_outbuf_size, parser_buf_size, pctx->pts);
+
+ /* if there is no output, we must break and wait for more data.
+ * also the timestamp in the context is not updated.
+ */
+ if (parser_outbuf_size == 0) {
+ if (parser_buf_size > 0) {
+ TRACE("parsing data have been left\n");
+ continue;
+ } else {
+ TRACE("finish parsing data\n");
+ break;
+ }
+ }
+
+ packet->data = parser_outbuf;
+ packet->size = parser_outbuf_size;
+ } else {
+ TRACE("not using parser %s\n", avctx->codec->name);
+ }
+
+ len = avcodec_decode_video2(avctx, picture, got_picture, packet);
+ TRACE("decode_video. len %d, got_picture %d\n", len, *got_picture);
+
+ if (!pctx) {
+ if (len == 0 && (*got_picture) == 0) {
+ ERR("decoding video didn't return any data! ctx_id %d len %d\n", ctx_id, len);
+ break;
+ } else if (len < 0) {
+ ERR("decoding video error! ctx_id %d len %d\n", ctx_id, len);
+ break;
+ }
+ parser_buf_size -= len;
+ parser_buf += len;
+ } else {
+ if (len == 0) {
+ ERR("decoding video didn't return any data! ctx_id %d len %d\n", ctx_id, len);
+ *got_picture = 0;
+ break;
+ } else if (len < 0) {
+ ERR("decoding video error! trying next ctx_id %d len %d\n", ctx_id, len);
+ break;
+ }
+ }
+ } while (parser_buf_size > 0);
+
+ return len;
+ }
+
+ // codec functions
+ static bool codec_init(MaruBrillCodecState *s, int ctx_id, void *data_buf)
+ {
+ AVCodecContext *avctx = NULL;
+ AVCodec *codec = NULL;
+ int size = 0, ret = -1;
+ DeviceMemEntry *elem = NULL;
+ uint8_t *tempbuf = NULL;
+ int tempbuf_size = 0;
+
+ TRACE("enter: %s\n", __func__);
+
+ elem = (DeviceMemEntry *)data_buf;
+
+ // allocate AVCodecContext
+ avctx = maru_brill_codec_alloc_context(s, ctx_id);
+ if (!avctx) {
+ ERR("[%d] failed to allocate context.\n", __LINE__);
+ ret = -1;
+ } else {
+ codec = maru_brill_codec_find_avcodec(elem->opaque);
+ if (codec) {
+ size = sizeof(int32_t) + 32; // buffer size of codec_name
+ read_codec_init_data(avctx, elem->opaque + size);
+
+ // in case of aac encoder, sample format is float
+ if (!strcmp(codec->name, "aac") && codec->encode2) {
+ TRACE("convert sample format into SAMPLE_FMT_FLTP\n");
+ avctx->sample_fmt = AV_SAMPLE_FMT_FLTP;
+
+ avctx->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
+
+ INFO("aac encoder!! channels %d channel_layout %lld\n",
+ avctx->channels, avctx->channel_layout);
+ avctx->channel_layout = av_get_default_channel_layout(avctx->channels);
+ }
+
+ TRACE("audio sample format %d\n", avctx->sample_fmt);
+ TRACE("strict_std_compliance %d\n", avctx->strict_std_compliance);
+
++ // in case of aac encoder, sample format is float
++ if (!strcmp(codec->name, "aac") && codec->encode2) {
++ TRACE("convert sample format into SAMPLE_FMT_FLTP\n");
++ avctx->sample_fmt = AV_SAMPLE_FMT_FLTP;
++
++ avctx->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
++
++ INFO("aac encoder!! channels %d channel_layout %lld\n", avctx->channels, avctx->channel_layout);
++ avctx->channel_layout = av_get_default_channel_layout(avctx->channels);
++ }
++
++ TRACE("audio sample format %d\n", avctx->sample_fmt);
++ TRACE("strict_std_compliance %d\n", avctx->strict_std_compliance);
++
+ ret = avcodec_open2(avctx, codec, NULL);
+ INFO("avcodec_open. ret 0x%x ctx_id %d\n", ret, ctx_id);
+
+ INFO("channels %d sample_rate %d sample_fmt %d "
+ "channel_layout %lld frame_size %d\n",
+ avctx->channels, avctx->sample_rate, avctx->sample_fmt,
+ avctx->channel_layout, avctx->frame_size);
+
+ tempbuf_size = (sizeof(avctx->sample_fmt) + sizeof(avctx->frame_size)
+ + sizeof(avctx->extradata_size) + avctx->extradata_size)
+ + sizeof(int);
+
+ CONTEXT(s, ctx_id).opened_context = true;
+ CONTEXT(s, ctx_id).parser_ctx =
+ maru_brill_codec_parser_init(avctx);
+ } else {
+ ERR("failed to find codec. ctx_id: %d\n", ctx_id);
+ ret = -1;
+ }
+ }
+
+ tempbuf_size += sizeof(ret);
+
+ tempbuf = g_malloc(tempbuf_size);
+ if (!tempbuf) {
+ ERR("failed to allocate a buffer\n");
+ tempbuf_size = 0;
+ } else {
+ memcpy(tempbuf, &ret, sizeof(ret));
+ size = sizeof(ret);
+ if (ret < 0) {
+ ERR("failed to open codec contex.\n");
+ } else {
+ size += write_codec_init_data(avctx, tempbuf + size);
+ TRACE("codec_init. copyback!! size %d\n", size);
+ {
+ memcpy(tempbuf + size, &avctx->extradata_size, sizeof(avctx->extradata_size));
+ size += sizeof(avctx->extradata_size);
+
+ INFO("codec_init. extradata_size: %d\n", avctx->extradata_size);
+ if (avctx->extradata) {
+ memcpy(tempbuf + size, avctx->extradata, avctx->extradata_size);
+ size += avctx->extradata_size;
+ }
+ }
+ }
+ }
+
+ maru_brill_codec_push_writequeue(s, tempbuf, tempbuf_size, ctx_id, NULL);
+
+ TRACE("leave: %s\n", __func__);
+
+ return true;
+ }
+
+ static bool codec_deinit(MaruBrillCodecState *s, int ctx_id, void *data_buf)
+ {
+ AVCodecContext *avctx = NULL;
+ AVFrame *frame = NULL;
+ AVCodecParserContext *parserctx = NULL;
+
+ TRACE("enter: %s\n", __func__);
+
+ avctx = CONTEXT(s, ctx_id).avctx;
+ frame = CONTEXT(s, ctx_id).frame;
+ parserctx = CONTEXT(s, ctx_id).parser_ctx;
+ if (!avctx || !frame) {
+ TRACE("%d of AVCodecContext or AVFrame is NULL. "
+ " Those resources have been released before.\n", ctx_id);
+ return false;
+ }
+
+ INFO("close avcontext of %d\n", ctx_id);
+ // qemu_mutex_lock(&s->threadpool.mutex);
+ avcodec_close(avctx);
+ CONTEXT(s, ctx_id).opened_context = false;
+ // qemu_mutex_unlock(&s->threadpool.mutex);
+
+ if (avctx->extradata) {
+ TRACE("free context extradata\n");
+ av_free(avctx->extradata);
+ CONTEXT(s, ctx_id).avctx->extradata = NULL;
+ }
+
+ if (frame) {
+ TRACE("free frame\n");
+ avcodec_free_frame(&frame);
+ CONTEXT(s, ctx_id).frame = NULL;
+ }
+
+ if (avctx) {
+ TRACE("free codec context\n");
+ av_free(avctx);
+ CONTEXT(s, ctx_id).avctx = NULL;
+ }
+
+ if (parserctx) {
+ INFO("close parser context\n");
+ av_parser_close(parserctx);
+ CONTEXT(s, ctx_id).parser_ctx = NULL;
+ }
+
+ maru_brill_codec_push_writequeue(s, NULL, 0, ctx_id, NULL);
+
+ TRACE("leave: %s\n", __func__);
+
+ return true;
+ }
+
+ static bool codec_flush_buffers(MaruBrillCodecState *s, int ctx_id, void *data_buf)
+ {
+ AVCodecContext *avctx = NULL;
+ bool ret = true;
+
+ TRACE("enter: %s\n", __func__);
+
+ avctx = CONTEXT(s, ctx_id).avctx;
+ if (!avctx) {
+ ERR("%d of AVCodecContext is NULL.\n", ctx_id);
+ ret = false;
+ } else if (!avctx->codec) {
+ ERR("%d of AVCodec is NULL.\n", ctx_id);
+ ret = false;
+ } else {
+ TRACE("flush %d context of buffers.\n", ctx_id);
+ AVCodecParserContext *pctx = NULL;
+ uint8_t *poutbuf = NULL;
+ int poutbuf_size = 0;
+ int res = 0;
+
+ uint8_t p_inbuf[FF_INPUT_BUFFER_PADDING_SIZE];
+ int p_inbuf_size = FF_INPUT_BUFFER_PADDING_SIZE;
+
+ memset(&p_inbuf, 0x00, p_inbuf_size);
+
+ pctx = CONTEXT(s, ctx_id).parser_ctx;
+ if (pctx) {
+ res = av_parser_parse2(pctx, avctx, &poutbuf, &poutbuf_size,
+ p_inbuf, p_inbuf_size, -1, -1, -1);
+ INFO("before flush buffers, using parser. res: %d\n", res);
+ }
+
+ avcodec_flush_buffers(avctx);
+ }
+
+ maru_brill_codec_push_writequeue(s, NULL, 0, ctx_id, NULL);
+
+ TRACE("leave: %s\n", __func__);
+
+ return ret;
+ }
+
+ static bool codec_decode_video(MaruBrillCodecState *s, int ctx_id, void *data_buf)
+ {
+ AVCodecContext *avctx = NULL;
+ AVFrame *picture = NULL;
+ AVCodecParserContext *pctx = NULL;
+ AVPacket avpkt;
+
+ int got_picture = 0, len = -1;
+ int idx = 0, size = 0;
+ int64_t in_offset = 0;
+ uint8_t *inbuf = NULL;
+ int inbuf_size = 0;
+ DeviceMemEntry *elem = NULL;
+ uint8_t *tempbuf = NULL;
+ int tempbuf_size = 0;
+
+ TRACE("enter: %s\n", __func__);
+
+ elem = (DeviceMemEntry *)data_buf;
+ if (elem && elem->opaque) {
+ memcpy(&inbuf_size, elem->opaque, sizeof(inbuf_size));
+ size += sizeof(inbuf_size);
+ memcpy(&idx, elem->opaque + size, sizeof(idx));
+ size += sizeof(idx);
+ memcpy(&in_offset, elem->opaque + size, sizeof(in_offset));
+ size += sizeof(in_offset);
+ TRACE("decode_video. inbuf_size %d\n", inbuf_size);
+
+ if (inbuf_size > 0) {
+ inbuf = elem->opaque + size;
+ }
+ } else {
+ TRACE("decode_video. no input buffer\n");
+ // FIXME: improve error handling
+ // return false;
+ }
+
+ av_init_packet(&avpkt);
+ avpkt.data = inbuf;
+ avpkt.size = inbuf_size;
+
+
+ avctx = CONTEXT(s, ctx_id).avctx;
+ picture = CONTEXT(s, ctx_id).frame;
+ if (!avctx) {
+ ERR("decode_video. %d of AVCodecContext is NULL.\n", ctx_id);
+ } else if (!avctx->codec) {
+ ERR("decode_video. %d of AVCodec is NULL.\n", ctx_id);
+ } else if (!picture) {
+ ERR("decode_video. %d of AVFrame is NULL.\n", ctx_id);
+ } else {
+ pctx = CONTEXT(s, ctx_id).parser_ctx;
+
+ len = parse_and_decode_video(avctx, picture, pctx, ctx_id,
+ &avpkt, &got_picture, idx, in_offset);
+ }
+
+ tempbuf_size = sizeof(len) + sizeof(got_picture) + sizeof(struct video_data);
+
+ tempbuf = g_malloc(tempbuf_size);
+ if (!tempbuf) {
+ ERR("failed to allocate decoded audio buffer\n");
+ tempbuf_size = 0;
+ } else {
+ struct video_data video;
+
+ memcpy(tempbuf, &len, sizeof(len));
+ size = sizeof(len);
+ memcpy(tempbuf + size, &got_picture, sizeof(got_picture));
+ size += sizeof(got_picture);
+ if (avctx) {
+ deserialize_video_data(avctx, &video);
+ memcpy(tempbuf + size, &video, sizeof(struct video_data));
+ }
+ }
+
+ maru_brill_codec_push_writequeue(s, tempbuf, tempbuf_size, ctx_id, NULL);
+
+ TRACE("leave: %s\n", __func__);
+
+ return true;
+ }
+
+ static bool codec_picture_copy (MaruBrillCodecState *s, int ctx_id, void *elem)
+ {
+ AVCodecContext *avctx = NULL;
+ AVPicture *src = NULL;
+ int pict_size = 0;
+ bool ret = true;
+
+ TRACE("enter: %s\n", __func__);
+
+ TRACE("copy decoded image of %d context.\n", ctx_id);
+
+ avctx = CONTEXT(s, ctx_id).avctx;
+ src = (AVPicture *)CONTEXT(s, ctx_id).frame;
+ if (!avctx) {
+ ERR("picture_copy. %d of AVCodecContext is NULL.\n", ctx_id);
+ ret = false;
+ } else if (!avctx->codec) {
+ ERR("picture_copy. %d of AVCodec is NULL.\n", ctx_id);
+ ret = false;
+ } else if (!src) {
+ ERR("picture_copy. %d of AVFrame is NULL.\n", ctx_id);
+ ret = false;
+ } else {
+ TRACE("decoded image. pix_fmt: %d width: %d, height: %d\n",
+ avctx->pix_fmt, avctx->width, avctx->height);
+ pict_size = avpicture_get_size(avctx->pix_fmt, avctx->width, avctx->height);
+
+ if ((pict_size) < 0) {
+ ERR("picture size: %d\n", pict_size);
+ ret = false;
+ } else {
+ TRACE("picture size: %d\n", pict_size);
+ maru_brill_codec_push_writequeue(s, src, pict_size, ctx_id, &default_video_decode_data_handler);
+ }
+ }
+
+ TRACE("leave: %s\n", __func__);
+
+ return ret;
+ }
+
+ /*
+ * decode_audio >> raw audio_buffer >> resample
+ *
+ * audios sink cannot handle planar format, so it is required
+ * to resample audio buffer into linear format.
+ */
+ static bool codec_decode_audio(MaruBrillCodecState *s, int ctx_id, void *data_buf)
+ {
+ AVCodecContext *avctx;
+ AVPacket avpkt;
+ AVFrame *audio_out = NULL;
+ uint8_t *inbuf = NULL;
+ int inbuf_size = 0, size = 0;
+ int len = -1, got_frame = 0;
+
+ DeviceMemEntry *elem = NULL;
+ uint8_t *tempbuf = NULL;
+ int tempbuf_size = 0;
+
+ AVFrame *resample_frame = NULL;
+ uint8_t *resample_buf = NULL;
+ int resample_buf_size = 0;
+ int out_sample_fmt = -1;
+
+ TRACE("enter: %s\n", __func__);
+
+ elem = (DeviceMemEntry *)data_buf;
+ if (elem && elem->opaque) {
+ memcpy(&inbuf_size, elem->opaque, sizeof(inbuf_size));
+ size = sizeof(inbuf_size);
+ TRACE("decode_audio. inbuf_size %d\n", inbuf_size);
+
+ if (inbuf_size > 0) {
+ inbuf = elem->opaque + size;
+ }
+ } else {
+ ERR("decode_audio. no input buffer\n");
+ // FIXME: improve error handling
+ // return false;
+ }
+
+ av_init_packet(&avpkt);
+ avpkt.data = inbuf;
+ avpkt.size = inbuf_size;
+
+ avctx = CONTEXT(s, ctx_id).avctx;
+ audio_out = CONTEXT(s, ctx_id).frame;
+ if (!avctx) {
+ ERR("decode_audio. %d of AVCodecContext is NULL\n", ctx_id);
+ } else if (!avctx->codec) {
+ ERR("decode_audio. %d of AVCodec is NULL\n", ctx_id);
+ } else if (!audio_out) {
+ ERR("decode_audio. %d of AVFrame is NULL\n", ctx_id);
+ } else {
+ len = avcodec_decode_audio4(avctx, audio_out, &got_frame, &avpkt);
+ TRACE("decode_audio. len %d, channel_layout %lld got_frame %d\n",
+ len, avctx->channel_layout, got_frame);
+
+ if (got_frame) {
+ if (av_sample_fmt_is_planar(avctx->sample_fmt)) {
+ out_sample_fmt = convert_audio_sample_fmt(avctx->codec, avctx->codec_type, 0);
+
+ if (avctx->channel_layout == 0) {
+ avctx->channel_layout = av_get_default_channel_layout(avctx->channels);
+ TRACE("decode_audio. channel_layout %lld channels %d\n",
+ avctx->channel_layout, avctx->channels);
+ }
+ resample_frame = resample_audio(avctx, audio_out, audio_out->linesize[0],
+ avctx->sample_fmt, NULL, &resample_buf_size,
+ out_sample_fmt);
+ if (resample_frame) {
+ resample_buf = resample_frame->data[0];
+ } else {
+ ERR("failed to resample decoded audio buffer\n");
+ len = -1;
+ got_frame = 0;
+ }
+ } else {
+ INFO("decode_audio. linear audio format\n");
+ resample_buf = audio_out->data[0];
+ resample_buf_size = audio_out->linesize[0];
+ }
+ }
+ }
+
+ tempbuf_size = (sizeof(len) + sizeof(got_frame));
+ if (len < 0) {
+ ERR("failed to decode audio. ctx_id: %d len: %d got_frame: %d\n",
+ ctx_id, len, got_frame);
+ got_frame = 0;
+ } else {
+ tempbuf_size += (sizeof(out_sample_fmt) + sizeof(avctx->sample_rate)
+ + sizeof(avctx->channels) + sizeof(avctx->channel_layout)
+ + sizeof(resample_buf_size) + resample_buf_size);
+ }
+
+ tempbuf = g_malloc(tempbuf_size);
+ if (!tempbuf) {
+ ERR("failed to allocate decoded audio buffer\n");
+ } else {
+ memcpy(tempbuf, &len, sizeof(len));
+ size = sizeof(len);
+ memcpy(tempbuf + size, &got_frame, sizeof(got_frame));
+ size += sizeof(got_frame);
+ if (got_frame) {
+ memcpy(tempbuf + size, &out_sample_fmt, sizeof(out_sample_fmt));
+ size += sizeof(out_sample_fmt);
+ memcpy(tempbuf + size, &avctx->sample_rate, sizeof(avctx->sample_rate));
+ size += sizeof(avctx->sample_rate);
+ memcpy(tempbuf + size, &avctx->channels, sizeof(avctx->channels));
+ size += sizeof(avctx->channels);
+ memcpy(tempbuf + size, &avctx->channel_layout, sizeof(avctx->channel_layout));
+ size += sizeof(avctx->channel_layout);
+
+ memcpy(tempbuf + size, &resample_buf_size, sizeof(resample_buf_size));
+ size += sizeof(resample_buf_size);
+ if (resample_buf) {
+ TRACE("copy resampled audio buffer\n");
+ memcpy(tempbuf + size, resample_buf, resample_buf_size);
+ }
+ }
+ }
+
+ maru_brill_codec_push_writequeue(s, tempbuf, tempbuf_size, ctx_id, NULL);
+
+ if (resample_frame) {
+ TRACE("release decoded frame\n");
+ av_free(resample_buf);
+ av_free(resample_frame);
+ }
+
++ if (audio_out) {
++ avcodec_free_frame(&audio_out);
++ }
++
+ TRACE("leave: %s\n", __func__);
+ return true;
+ }
+
+ static bool codec_encode_video(MaruBrillCodecState *s, int ctx_id, void *data_buf)
+ {
+ AVCodecContext *avctx = NULL;
+ AVFrame *pict = NULL;
+ AVPacket avpkt;
+ uint8_t *inbuf = NULL, *outbuf = NULL;
+ int inbuf_size = 0, outbuf_size = 0;
+ int got_frame = 0, ret = 0, size = 0;
+ int64_t in_timestamp = 0;
+ int coded_frame = 0, key_frame = 0;
+
+ DeviceMemEntry *elem = NULL;
+ uint8_t *tempbuf = NULL;
+ int tempbuf_size = 0;
+
+ TRACE("enter: %s\n", __func__);
+
+ elem = (DeviceMemEntry *)data_buf;
+ if (elem && elem->opaque) {
+ memcpy(&inbuf_size, elem->opaque, sizeof(inbuf_size));
+ size += sizeof(inbuf_size);
+ memcpy(&in_timestamp, elem->opaque + size, sizeof(in_timestamp));
+ size += sizeof(in_timestamp);
+ TRACE("encode video. inbuf_size %d\n", inbuf_size);
+
+ if (inbuf_size > 0) {
+ inbuf = elem->opaque + size;
+ }
+ } else {
+ TRACE("encode video. no input buffer.\n");
+ // FIXME: improve error handling
+ // return false;
+ }
+
+ // initialize AVPacket
+ av_init_packet(&avpkt);
+ avpkt.data = NULL;
+ avpkt.size = 0;
+
+ avctx = CONTEXT(s, ctx_id).avctx;
+ pict = CONTEXT(s, ctx_id).frame;
+ if (!avctx || !pict) {
+ ERR("%d of context or frame is NULL\n", ctx_id);
+ } else if (!avctx->codec) {
+ ERR("%d of AVCodec is NULL.\n", ctx_id);
+ } else {
+ TRACE("pixel format: %d inbuf: %p, picture data: %p\n",
+ avctx->pix_fmt, inbuf, pict->data[0]);
+
+ ret = avpicture_fill((AVPicture *)pict, inbuf, avctx->pix_fmt,
+ avctx->width, avctx->height);
+ if (ret < 0) {
+ ERR("after avpicture_fill, ret:%d\n", ret);
+ } else {
+ if (avctx->time_base.num == 0) {
+ pict->pts = AV_NOPTS_VALUE;
+ } else {
+ AVRational bq =
+ {1, (G_USEC_PER_SEC * G_GINT64_CONSTANT(1000))};
+ pict->pts = av_rescale_q(in_timestamp, bq, avctx->time_base);
+ }
+ TRACE("encode video. ticks_per_frame:%d, pts:%lld\n",
+ avctx->ticks_per_frame, pict->pts);
+
+ outbuf_size =
+ (avctx->width * avctx->height * 6) + FF_MIN_BUFFER_SIZE;
+
+ outbuf = g_malloc0(outbuf_size);
+
+ avpkt.data = outbuf;
+ avpkt.size = outbuf_size;
+
+ if (!outbuf) {
+ ERR("failed to allocate a buffer of encoding video.\n");
+ } else {
+ ret = avcodec_encode_video2(avctx, &avpkt, pict, &got_frame);
+
+ TRACE("encode video. ret %d got_picture %d outbuf_size %d\n", ret, got_frame, avpkt.size);
+ if (avctx->coded_frame) {
+ TRACE("encode video. keyframe %d\n", avctx->coded_frame->key_frame);
+ }
+ }
+ }
+ }
+
+ tempbuf_size = sizeof(ret);
+ if (ret < 0) {
+ ERR("failed to encode video. ctx_id %d ret %d\n", ctx_id, ret);
+ } else {
+ tempbuf_size += avpkt.size + sizeof(coded_frame) + sizeof(key_frame);
+ }
+
+ // write encoded video data
+ tempbuf = g_malloc0(tempbuf_size);
+ if (!tempbuf) {
+ ERR("encode video. failed to allocate encoded out buffer.\n");
+ } else {
+ memcpy(tempbuf, &avpkt.size, sizeof(avpkt.size));
+ size = sizeof(avpkt.size);
+
+ if ((got_frame) && outbuf) {
+ // inform gstreamer plugin about the status of encoded frames
+ // A flag for output buffer in gstreamer is depending on the status.
+ if (avctx->coded_frame) {
+ coded_frame = 1;
+ // if key_frame is 0, this frame cannot be decoded independently.
+ key_frame = avctx->coded_frame->key_frame;
+ }
+ memcpy(tempbuf + size, &coded_frame, sizeof(coded_frame));
+ size += sizeof(coded_frame);
+ memcpy(tempbuf + size, &key_frame, sizeof(key_frame));
+ size += sizeof(key_frame);
+ memcpy(tempbuf + size, outbuf, avpkt.size);
+ }
+ }
+
+ if (outbuf) {
+ TRACE("release encoded output buffer. %p\n", outbuf);
+ g_free(outbuf);
+ }
+
+ maru_brill_codec_push_writequeue(s, tempbuf, tempbuf_size, ctx_id, NULL);
+
+ TRACE("leave: %s\n", __func__);
+ return true;
+ }
+
+ static bool codec_encode_audio(MaruBrillCodecState *s, int ctx_id, void *data_buf)
+ {
+ AVCodecContext *avctx = NULL;
+ AVPacket avpkt;
+ uint8_t *audio_in = NULL;
+ int32_t audio_in_size = 0;
+ int ret = -1, got_pkt = 0, size = 0;
+
+ DeviceMemEntry *elem = NULL;
+ uint8_t *tempbuf = NULL;
+ int tempbuf_size = 0;
+
+ AVFrame *in_frame = NULL;
+ AVFrame *resample_frame = NULL;
+ int64_t in_timestamp = 0;
+
+ TRACE("enter: %s\n", __func__);
+
+ /*
+ * copy raw audio data from gstreamer encoder plugin
+ * audio_in_size: size of raw audio data
+ * audio_in : raw audio data
+ */
+ elem = (DeviceMemEntry *)data_buf;
+ if (elem && elem->opaque) {
+ memcpy(&audio_in_size, elem->opaque, sizeof(audio_in_size));
+ size += sizeof(audio_in_size);
+
+ memcpy(&in_timestamp, elem->opaque + size, sizeof(in_timestamp));
+ size += sizeof(in_timestamp);
+
+ TRACE("encode_audio. audio_in_size %d\n", audio_in_size);
+ if (audio_in_size > 0) {
+ // audio_in = g_malloc0(audio_in_size);
+ // memcpy(audio_in, elem->buf + size, audio_in_size);
+ audio_in = elem->opaque + size;
+ }
+ } else {
+ TRACE("encode_audio. no input buffer\n");
+ }
+
+ avctx = CONTEXT(s, ctx_id).avctx;
+ if (!avctx) {
+ ERR("encode_audio. %d of Context is NULL\n", ctx_id);
+ } else if (!avctx->codec) {
+ ERR("encode_audio. %d of AVCodec is NULL\n", ctx_id);
+ } else {
+ int bytes_per_sample = 0;
+ int nb_samples = 0;
+ int audio_in_sample_fmt = AV_SAMPLE_FMT_S16;
+ // audio input src can generate a buffer as an int format.
+
+ int resample_buf_size = 0;
+ int resample_sample_fmt = 0;
+
+ bytes_per_sample = av_get_bytes_per_sample(audio_in_sample_fmt);
+ TRACE("bytes per sample %d, sample format %d\n", bytes_per_sample, audio_in_sample_fmt);
+
+ nb_samples = audio_in_size / (bytes_per_sample * avctx->channels);
+ TRACE("nb_samples %d\n", nb_samples);
+
+ in_frame = avcodec_alloc_frame();
+ if (!in_frame) {
+ ERR("encode_audio. failed to allocate in_frame\n");
+ } else {
+ // prepare audio_in frame
+ ret = fill_audio_into_frame(avctx, in_frame, audio_in, audio_in_size, nb_samples, audio_in_sample_fmt);
+ if (ret < 0) {
+ ERR("failed to fill audio into frame\n");
+ } else {
+ resample_sample_fmt =
+ convert_audio_sample_fmt(avctx->codec, avctx->codec_type, 1);
+ resample_frame = resample_audio(avctx, in_frame, audio_in_size,
+ audio_in_sample_fmt, NULL, &resample_buf_size,
+ resample_sample_fmt);
+
+ if (resample_frame) {
+ av_init_packet(&avpkt);
+ avpkt.data = NULL;
+ avpkt.size = 0;
+
+ ret = avcodec_encode_audio2(avctx, &avpkt, (const AVFrame *)resample_frame, &got_pkt);
+ TRACE("encode audio. ret %d got_pkt %d avpkt.size %d frame_number %d\n",
+ ret, got_pkt, avpkt.size, avctx->frame_number);
+ }
+ }
+ }
+ }
+
+ tempbuf_size = sizeof(ret);
+ if (ret < 0) {
+ ERR("failed to encode audio. ctx_id %d ret %d\n", ctx_id, ret);
+ } else {
+ tempbuf_size += (sizeof(avpkt.size) + avpkt.size);
+ }
+ TRACE("encode_audio. writequeue elem buffer size %d\n", tempbuf_size);
+
+ // write encoded audio data
+ tempbuf = g_malloc0(tempbuf_size);
+ if (!tempbuf) {
+ ERR("encode audio. failed to allocate encoded out buffer.\n");
+ } else {
+ memcpy(tempbuf, &ret, sizeof(ret));
+ size = sizeof(ret);
+ if (ret == 0) {
+ memcpy(tempbuf + size, &avpkt.size, sizeof(avpkt.size));
+ size += sizeof(avpkt.size);
+
+ if (got_pkt) {
+ memcpy(tempbuf + size, avpkt.data, avpkt.size);
+ av_free_packet(&avpkt);
+ }
+ }
+ }
+
+ maru_brill_codec_push_writequeue(s, tempbuf, tempbuf_size, ctx_id, NULL);
+
+ if (in_frame) {
+ av_free(in_frame);
+ }
+
+ if (resample_frame) {
+ av_free(resample_frame->data[0]);
+ av_free(resample_frame);
+ }
+
+ TRACE("[%s] leave:\n", __func__);
+
+ return true;
+ }
+
+ static AVCodecParserContext *maru_brill_codec_parser_init(AVCodecContext *avctx)
+ {
+ AVCodecParserContext *parser = NULL;
+
+ if (!avctx) {
+ ERR("context is NULL\n");
+ return NULL;
+ }
+
+ switch (avctx->codec_id) {
+ case CODEC_ID_MPEG4:
+ case CODEC_ID_VC1:
+ TRACE("not using parser\n");
+ break;
+ case CODEC_ID_H264:
+ if (avctx->extradata_size == 0) {
+ TRACE("H.264 with no extradata, creating parser.\n");
+ parser = av_parser_init (avctx->codec_id);
+ }
+ break;
+ default:
+ parser = av_parser_init(avctx->codec_id);
+ if (parser) {
+ INFO("using parser: %s\n", avctx->codec->name);
+ }
+ break;
+ }
+
+ return parser;
+ }
--- /dev/null
+ /*
+ * Maru device hotplug
+ *
+ * Copyright (C) 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * SeokYeon Hwang <syeon.hwang@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+ #include "qemu/main-loop.h"
+ #include "qemu/config-file.h"
+ #include "hw/qdev.h"
+ #include "monitor/qdev.h"
++#include "fsdev/qemu-fsdev.h"
+ #include "qmp-commands.h"
+ #include "sysemu/blockdev.h"
+ #include "qemu/event_notifier.h"
+
+ #include "emulator.h"
+ #include "maru_device_hotplug.h"
+
+ #define HOST_KEYBOARD_DRIVER "virtio-keyboard-pci"
+ #define HOST_KEYBOARD_DEFAULT_ID "HOSTKBD0"
+
+ #define SDCARD_DRIVE_DEFAULT_ID "SDCARD_DRIVE0"
+ #define SDCARD_DRIVER "virtio-blk-pci"
+ #define SDCARD_DEFAULT_ID "SDCARD0"
+
++#define FS_MOUNT_TAG "fileshare"
++
+ struct maru_device_hotplug {
+ EventNotifier notifier;
+
+ char *opaque;
+ int command;
+
+ // FIXME: Should we query device every time ??
+ bool host_keyboard_attached;
+ bool sdcard_attached;
++ bool hds_attached;
+ };
+
+ static struct maru_device_hotplug *state;
+
+ static bool do_host_keyboard_attach(void)
+ {
+ QDict *qdict = qdict_new();
+ qdict_put(qdict, "driver", qstring_from_str(HOST_KEYBOARD_DRIVER));
+ qdict_put(qdict, "id", qstring_from_str(HOST_KEYBOARD_DEFAULT_ID));
+
+ if (do_device_add(default_mon, qdict, NULL)) {
+ QDECREF(qdict);
+ // TODO error reporting
+ return false;
+ }
+
+ QDECREF(qdict);
+
+ state->host_keyboard_attached = true;
+
+ return true;
+ }
+
+ static bool do_host_keyboard_detach(void)
+ {
+ QDict *qdict = qdict_new();
+ qdict_put(qdict, "id", qstring_from_str(HOST_KEYBOARD_DEFAULT_ID));
+
+ if (qmp_marshal_input_device_del(default_mon, qdict, NULL)) {
+ QDECREF(qdict);
+ // TODO error reporting
+ return false;
+ }
+
+ QDECREF(qdict);
+
+ state->host_keyboard_attached = false;
+
+ return true;
+ }
+
+ static bool do_sdcard_attach(const char * const file)
+ {
+ QDict *qdict = qdict_new();
+ QDict *qdict_file = qdict_new();
+ QDict *qdict_options = qdict_new();
+
+ qdict_put(qdict_file, "driver", qstring_from_str("file"));
+ qdict_put(qdict_file, "filename", qstring_from_str(file));
+ qdict_put(qdict_options, "file", qdict_file);
+ qdict_put(qdict_options, "driver", qstring_from_str("qcow2"));
+ qdict_put(qdict_options, "id", qstring_from_str(SDCARD_DRIVE_DEFAULT_ID));
+ qdict_put(qdict, "options", qdict_options);
+
+ if (qmp_marshal_input_blockdev_add(default_mon, qdict, NULL)) {
+ QDECREF(qdict);
+ }
+
+ QDECREF(qdict);
+
+ qdict = qdict_new();
+ qdict_put(qdict, "driver", qstring_from_str(SDCARD_DRIVER));
+ qdict_put(qdict, "drive", qstring_from_str(SDCARD_DRIVE_DEFAULT_ID));
+ qdict_put(qdict, "id", qstring_from_str(SDCARD_DEFAULT_ID));
+
+ if (do_device_add(default_mon, qdict, NULL)) {
+ QDECREF(qdict);
+ // TODO error reporting
+ return false;
+ }
+
+ QDECREF(qdict);
+
+ state->sdcard_attached = true;
+
+ return true;
+ }
+
+ static bool do_sdcard_detach(void) {
+ QDict *qdict = qdict_new();
+ qdict_put(qdict, "id", qstring_from_str(SDCARD_DEFAULT_ID));
+
+ if (qmp_marshal_input_device_del(cur_mon, qdict, NULL)) {
+ QDECREF(qdict);
+ // TODO error reporting
+ return false;
+ }
+
+ QDECREF(qdict);
+
+ state->sdcard_attached = false;
+
+ return true;
+ }
+
++static bool do_hds_attach(const char * const file)
++{
++ QemuOpts *fsdev;
++ int ret;
++ QDict *qdict = qdict_new();
++
++ fsdev = qemu_opts_create(qemu_find_opts("fsdev"),
++ FS_MOUNT_TAG, 0, NULL);
++ if (!fsdev) {
++ return false;
++ }
++
++ qemu_opt_set(fsdev, "fsdriver", "local");
++ qemu_opt_set(fsdev, "path", file);
++ qemu_opt_set(fsdev, "security_model", "none");
++
++ ret = qemu_fsdev_add(fsdev);
++ if (ret != 0) {
++ return false;
++ }
++
++ qdict = qdict_new();
++ qdict_put(qdict, "driver", qstring_from_str("virtio-9p-pci"));
++ qdict_put(qdict, "fsdev", qstring_from_str(FS_MOUNT_TAG));
++ qdict_put(qdict, "mount_tag", qstring_from_str(FS_MOUNT_TAG));
++ qdict_put(qdict, "id", qstring_from_str(FS_MOUNT_TAG));
++
++ if (do_device_add(default_mon, qdict, NULL)) {
++ QDECREF(qdict);
++ return false;
++ }
++
++ QDECREF(qdict);
++
++ state->hds_attached = true;
++
++ return true;
++}
++
++static bool do_hds_detach(void)
++{
++ QDict *qdict = qdict_new();
++ qemu_fsdev_remove(FS_MOUNT_TAG);
++
++ qdict_put(qdict, "id", qstring_from_str(FS_MOUNT_TAG));
++
++ if (qmp_marshal_input_device_del(cur_mon, qdict, NULL)) {
++ QDECREF(qdict);
++ return false;
++ }
++
++ QDECREF(qdict);
++
++ state->hds_attached = false;
++
++ return true;
++}
++
+ void do_hotplug(int command, void *opaque, size_t size)
+ {
+ if (command == ATTACH_SDCARD) {
+ state->opaque = g_malloc(size);
+ memcpy(state->opaque, opaque, size);
+ }
+ state->command = command;
+
+ event_notifier_set(&state->notifier);
+ }
+
+ static void device_hotplug_handler(EventNotifier *e)
+ {
+ event_notifier_test_and_clear(e);
+
+ switch(state->command) {
+ case ATTACH_HOST_KEYBOARD:
+ do_host_keyboard_attach();
+ break;
+ case DETACH_HOST_KEYBOARD:
+ do_host_keyboard_detach();
+ break;
+ case ATTACH_SDCARD:
+ do_sdcard_attach(state->opaque);
+ g_free(state->opaque);
+ break;
+ case DETACH_SDCARD:
+ do_sdcard_detach();
+ break;
++ case ATTACH_HDS:
++ do_hds_attach(state->opaque);
++ break;
++ case DETACH_HDS:
++ do_hds_detach();
++ break;
+ default:
+ break;
+ }
+ }
+
+ static void maru_device_hotplug_deinit(Notifier *notifier, void *data)
+ {
+ event_notifier_cleanup(&state->notifier);
+
+ g_free(state);
+ }
+
+ static Notifier maru_device_hotplug_exit = { .notify = maru_device_hotplug_deinit };
+
+ void maru_device_hotplug_init(void)
+ {
+ state = g_malloc0(sizeof(struct maru_device_hotplug));
+
+ event_notifier_init(&state->notifier, 0);
+ event_notifier_set_handler(&state->notifier, device_hotplug_handler);
+
+ emulator_add_exit_notifier(&maru_device_hotplug_exit);
+ }
+
+ bool is_host_keyboard_attached(void)
+ {
+ return state->host_keyboard_attached;
+ }
+
+ bool is_sdcard_attached(void)
+ {
+ return state->sdcard_attached;
+ }
+
++bool is_hds_attached(void)
++{
++ return state->hds_attached;
++}
++
--- /dev/null
+ /*
+ * Maru device hotplug
+ *
+ * Copyright (C) 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * SeokYeon Hwang <syeon.hwang@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+ #ifndef _MARU_DEVICE_HOTPLUG_H_
+ #define _MARU_DEVICE_HOTPLUG_H_
+
+ enum command {
+ ATTACH_HOST_KEYBOARD,
+ DETACH_HOST_KEYBOARD,
+ ATTACH_SDCARD,
+ DETACH_SDCARD,
++ ATTACH_HDS,
++ DETACH_HDS,
+ };
+
+ void maru_device_hotplug_init(void);
+
+ void do_hotplug(int command, void *opaque, size_t size);
+
+ bool is_host_keyboard_attached(void);
+ bool is_sdcard_attached(void);
++bool is_hds_attached(void);
+
+ #endif // _MARU_DEVICE_HOTPLUG_H_
--- /dev/null
- return make_sdcard_lock(sdcard);
+ /*
+ * Emulator
+ *
+ * Copyright (C) 2012, 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * SeokYeon Hwang <syeon.hwang@samsung.com>
+ * MunKyu Im <munkyu.im@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ * HyunJun Son
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+ /**
+ @file osutil-darwin.c
+ @brief Collection of utilities for darwin
+ */
+
+ #include "emulator_common.h"
+ #include "osutil.h"
+ #include "emulator.h"
+ #include "emul_state.h"
+ #include "debug_ch.h"
+ #include "maru_err_table.h"
+ #include "sdb.h"
+
+ #ifndef CONFIG_DARWIN
+ #error
+ #endif
+
+ #include <string.h>
+ #include <unistd.h>
+ #include <sys/shm.h>
+ #include <sys/sysctl.h>
+ #include <SystemConfiguration/SystemConfiguration.h>
+
+ MULTI_DEBUG_CHANNEL(qemu, osutil);
+
+ static int g_shmid;
+ static CFDictionaryRef proxySettings;
+
+ extern char tizen_target_img_path[];
+
+ static char *cfstring_to_cstring(CFStringRef str) {
+ if (str == NULL) {
+ return NULL;
+ }
+
+ CFIndex length = CFStringGetLength(str);
+ CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8);
+ char *buffer = (char *)malloc(maxSize);
+ if (CFStringGetCString(str, buffer, maxSize, kCFStringEncodingUTF8))
+ return buffer;
+ return NULL;
+ }
+
+ static int cfnumber_to_int(CFNumberRef num) {
+ if (!num)
+ return 0;
+
+ int value;
+ CFNumberGetValue(num, kCFNumberIntType, &value);
+ return value;
+ }
+
+ void check_vm_lock_os(void)
+ {
+ /* TODO: */
+ }
+
+ void make_vm_lock_os(void)
+ {
+ char *shared_memory;
+ int base_port;
+ base_port = get_emul_vm_base_port();
+ g_shmid = shmget((key_t)base_port, getpagesize(), 0666|IPC_CREAT);
+ if (g_shmid == -1) {
+ ERR("shmget failed\n");
+ perror("osutil-darwin: ");
+ return;
+ }
+
+ shared_memory = shmat(g_shmid, (char *)0x00, 0);
+ if (shared_memory == (void *)-1) {
+ ERR("shmat failed\n");
+ perror("osutil-darwin: ");
+ return;
+ }
+ g_sprintf(shared_memory, "%s", tizen_target_img_path);
+ INFO("shared memory key: %d, value: %s\n", base_port, (char *)shared_memory);
+
+ if (shmdt(shared_memory) == -1) {
+ ERR("shmdt failed\n");
+ perror("osutil-darwin: ");
+ }
+
+ }
+
+ void remove_vm_lock_os(void)
+ {
+ if (shmctl(g_shmid, IPC_RMID, 0) == -1) {
+ ERR("shmctl failed\n");
+ perror("osutil-linux: ");
+ }
+ }
+
+ void set_bin_path_os(char const *const exec_argv)
+ {
+ gchar *file_name = NULL;
+
+ if (!exec_argv) {
+ return;
+ }
+
+ char *data = g_strdup(exec_argv);
+ if (!data) {
+ ERR("Fail to strdup for paring a binary directory.\n");
+ return;
+ }
+
+ file_name = g_strrstr(data, "/");
+ if (!file_name) {
+ free(data);
+ return;
+ }
+
+ g_strlcpy(bin_path, data, strlen(data) - strlen(file_name) + 1);
+
+ g_strlcat(bin_path, "/", PATH_MAX);
+ free(data);
+ }
+
+ int get_number_of_processors(void)
+ {
+ int mib[2], sys_num = 0;
+ size_t len;
+
+ mib[0] = CTL_HW;
+ mib[1] = HW_AVAILCPU;
+
+ sysctl(mib, 2, &sys_num, &len, NULL, 0);
+ if (sys_num < 1) {
+ mib[1] = HW_NCPU;
+ sysctl(mib, 2, &sys_num, &len, NULL, 0);
+
+ if (sys_num < 1) {
+ sys_num = 1;
+ }
+ }
+ INFO("* Number of processors : %d\n", sys_num);
+
+ return sys_num;
+ }
+
+ void print_system_info_os(void)
+ {
+ INFO("* Mac\n");
+
+ /* uname */
+ INFO("* Host machine uname :\n");
+ char const *const uname_cmd = "uname -a";
+ if(system(uname_cmd) < 0) {
+ INFO("system function command '%s' \
+ returns error !", uname_cmd);
+ }
+
+ /* hw information */
+ int mib[2];
+ size_t len;
+ char *sys_info;
+ int sys_num = 0;
+
+ mib[0] = CTL_HW;
+ mib[1] = HW_MODEL;
+ sysctl(mib, 2, NULL, &len, NULL, 0);
+ sys_info = malloc(len * sizeof(char));
+ if (sysctl(mib, 2, sys_info, &len, NULL, 0) >= 0) {
+ INFO("* Machine model : %s\n", sys_info);
+ }
+ free(sys_info);
+
+ mib[0] = CTL_HW;
+ mib[1] = HW_MACHINE;
+ sysctl(mib, 2, NULL, &len, NULL, 0);
+ sys_info = malloc(len * sizeof(char));
+ if (sysctl(mib, 2, sys_info, &len, NULL, 0) >= 0) {
+ INFO("* Machine class : %s\n", sys_info);
+ }
+ free(sys_info);
+
+ #if 0
+ mib[0] = CTL_HW;
+ mib[1] = HW_NCPU;
+ len = sizeof(sys_num);
+ if (sysctl(mib, 2, &sys_num, &len, NULL, 0) >= 0) {
+ INFO("* Number of processors : %d\n", sys_num);
+ }
+ #endif
+ get_number_of_processors();
+
+ mib[0] = CTL_HW;
+ mib[1] = HW_PHYSMEM;
+ len = sizeof(sys_num);
+ if (sysctl(mib, 2, &sys_num, &len, NULL, 0) >= 0) {
+ INFO("* Total memory : %llu bytes\n", sys_num);
+ }
+
+ /* java version */
+ INFO("* Java version :\n");
+ char const *const lspci_cmd = "java -version";
+
+ fflush(stdout);
+ if(system(lspci_cmd) < 0) {
+ INFO("system function command '%s' \
+ returns error !", lspci_cmd);
+ }
+ }
+
+ static int get_auto_proxy(char *http_proxy, char *https_proxy, char *ftp_proxy, char *socks_proxy)
+ {
+ char type[DEFAULTBUFLEN];
+ char proxy[DEFAULTBUFLEN];
+ char line[DEFAULTBUFLEN];
+ FILE *fp_pacfile;
+ char *p = NULL;
+
+ CFStringRef pacURL = (CFStringRef)CFDictionaryGetValue(proxySettings,
+ kSCPropNetProxiesProxyAutoConfigURLString);
+ if (pacURL) {
+ char url[DEFAULTBUFLEN] = {};
+ CFStringGetCString(pacURL, url, sizeof url, kCFStringEncodingASCII);
+ INFO("pac address: %s\n", (char*)url);
+ download_url(url);
+ }
+
+ fp_pacfile = fopen(pac_tempfile, "r");
+ if(fp_pacfile != NULL) {
+ while(fgets(line, DEFAULTBUFLEN, fp_pacfile) != NULL) {
+ if( (strstr(line, "return") != NULL) && (strstr(line, "if") == NULL)) {
+ INFO("line found %s", line);
+ sscanf(line, "%*[^\"]\"%s %s", type, proxy);
+ }
+ }
+
+ if(g_str_has_prefix(type, DIRECT)) {
+ INFO("auto proxy is set to direct mode\n");
+ fclose(fp_pacfile);
+ }
+ else if(g_str_has_prefix(type, PROXY)) {
+ INFO("auto proxy is set to proxy mode\n");
+ INFO("type: %s, proxy: %s\n", type, proxy);
+ p = strtok(proxy, "\";");
+ if(p != NULL) {
+ INFO("auto proxy to set: %s\n",p);
+ strcpy(http_proxy, p);
+ strcpy(https_proxy, p);
+ strcpy(ftp_proxy, p);
+ strcpy(socks_proxy, p);
+ }
+ fclose(fp_pacfile);
+ }
+ else
+ {
+ ERR("pac file is not wrong! It could be the wrong pac address or pac file format\n");
+ fclose(fp_pacfile);
+ }
+ }
+ else {
+ ERR("fail to get pacfile fp\n");
+ return -1;
+ }
+
+ remove(pac_tempfile);
+ return 0;
+ }
+
+ static void get_proxy(char *http_proxy, char *https_proxy, char *ftp_proxy, char *socks_proxy)
+ {
+ char *hostname;
+ int port;
+ CFNumberRef isEnable;
+ CFStringRef proxyHostname;
+ CFNumberRef proxyPort;
+ CFDictionaryRef proxySettings;
+ proxySettings = SCDynamicStoreCopyProxies(NULL);
+
+ isEnable = CFDictionaryGetValue(proxySettings, kSCPropNetProxiesHTTPEnable);
+ if (cfnumber_to_int(isEnable)) {
+ // Get proxy hostname
+ proxyHostname = CFDictionaryGetValue(proxySettings, kSCPropNetProxiesHTTPProxy);
+ hostname = cfstring_to_cstring(proxyHostname);
+ // Get proxy port
+ proxyPort = CFDictionaryGetValue(proxySettings, kSCPropNetProxiesHTTPPort);
+ port = cfnumber_to_int(proxyPort);
+ // Save hostname & port
+ snprintf(http_proxy, DEFAULTBUFLEN, "%s:%d", hostname, port);
+
+ free(hostname);
+ } else {
+ INFO("http proxy is null\n");
+ }
+
+ isEnable = CFDictionaryGetValue(proxySettings, kSCPropNetProxiesHTTPSEnable);
+ if (cfnumber_to_int(isEnable)) {
+ // Get proxy hostname
+ proxyHostname = CFDictionaryGetValue(proxySettings, kSCPropNetProxiesHTTPSProxy);
+ hostname = cfstring_to_cstring(proxyHostname);
+ // Get proxy port
+ proxyPort = CFDictionaryGetValue(proxySettings, kSCPropNetProxiesHTTPSPort);
+ port = cfnumber_to_int(proxyPort);
+ // Save hostname & port
+ snprintf(https_proxy, DEFAULTBUFLEN, "%s:%d", hostname, port);
+
+ free(hostname);
+ } else {
+ INFO("https proxy is null\n");
+ }
+
+ isEnable = CFDictionaryGetValue(proxySettings, kSCPropNetProxiesFTPEnable);
+ if (cfnumber_to_int(isEnable)) {
+ // Get proxy hostname
+ proxyHostname = CFDictionaryGetValue(proxySettings, kSCPropNetProxiesFTPProxy);
+ hostname = cfstring_to_cstring(proxyHostname);
+ // Get proxy port
+ proxyPort = CFDictionaryGetValue(proxySettings, kSCPropNetProxiesFTPPort);
+ port = cfnumber_to_int(proxyPort);
+ // Save hostname & port
+ snprintf(ftp_proxy, DEFAULTBUFLEN, "%s:%d", hostname, port);
+
+ free(hostname);
+ } else {
+ INFO("ftp proxy is null\n");
+ }
+
+ isEnable = CFDictionaryGetValue(proxySettings, kSCPropNetProxiesSOCKSEnable);
+ if (cfnumber_to_int(isEnable)) {
+ // Get proxy hostname
+ proxyHostname = CFDictionaryGetValue(proxySettings, kSCPropNetProxiesSOCKSProxy);
+ hostname = cfstring_to_cstring(proxyHostname);
+ // Get proxy port
+ proxyPort = CFDictionaryGetValue(proxySettings, kSCPropNetProxiesSOCKSPort);
+ port = cfnumber_to_int(proxyPort);
+ // Save hostname & port
+ snprintf(socks_proxy, DEFAULTBUFLEN, "%s:%d", hostname, port);
+
+ free(hostname);
+ } else {
+ INFO("socks proxy is null\n");
+ }
+ CFRelease(proxySettings);
+ }
+
+ void get_host_proxy_os(char *http_proxy, char *https_proxy, char *ftp_proxy, char *socks_proxy)
+ {
+ int ret;
+ proxySettings = SCDynamicStoreCopyProxies(NULL);
+ if(proxySettings) {
+ INFO("AUTO PROXY MODE\n");
+ ret = get_auto_proxy(http_proxy, https_proxy, ftp_proxy, socks_proxy);
+ if(strlen(http_proxy) == 0 && ret < 0) {
+ INFO("MANUAL PROXY MODE\n");
+ get_proxy(http_proxy, https_proxy, ftp_proxy, socks_proxy);
+ }
+ }
+ }
+
+ bool make_sdcard_lock_os(char *sdcard)
+ {
- return remove_sdcard_lock(sdcard);
++ return make_sdcard_lock_posix(sdcard);
+ }
+
+ int remove_sdcard_lock_os(char *sdcard)
+ {
++ return remove_sdcard_lock_posix(sdcard);
+ }
--- /dev/null
- return make_sdcard_lock(sdcard);
+ /*
+ * Emulator
+ *
+ * Copyright (C) 2012 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * SeokYeon Hwang <syeon.hwang@samsung.com>
+ * MunKyu Im <munkyu.im@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ * HyunJun Son
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+ /**
+ @file osutil-linux.c
+ @brief Collection of utilities for linux
+ */
+
+ #include <png.h>
+ #include "osutil.h"
+ #include "emulator.h"
+ #include "emul_state.h"
+ #include "debug_ch.h"
+ #include "maru_err_table.h"
+ #include "sdb.h"
+
+ #ifndef CONFIG_LINUX
+ #error
+ #endif
+ #include <string.h>
+ #include <unistd.h>
+ #include <sys/shm.h>
+ #include <sys/ipc.h>
+ #include <linux/version.h>
+ #include <sys/utsname.h>
+ #include <sys/sysinfo.h>
+ #ifdef CONFIG_SPICE
+ #include <dirent.h>
+ #endif
+
+ MULTI_DEBUG_CHANNEL(emulator, osutil);
+
+ static int g_shmid;
+ static char *g_shared_memory;
+ static int gproxytool = GSETTINGS;
+
+ extern char tizen_target_img_path[];
+
+ /* Getting proxy commands */
+ static const char* gproxycmds[][2] = {
+ { "gconftool-2 -g /system/proxy/mode" , "gsettings get org.gnome.system.proxy mode" },
+ { "gconftool-2 -g /system/proxy/autoconfig_url", "gsettings get org.gnome.system.proxy autoconfig-url" },
+ { "gconftool-2 -g /system/http_proxy/host", "gsettings get org.gnome.system.proxy.http host" },
+ { "gconftool-2 -g /system/http_proxy/port", "gsettings get org.gnome.system.proxy.http port"},
+ { "gconftool-2 -g /system/proxy/secure_host", "gsettings get org.gnome.system.proxy.https host" },
+ { "gconftool-2 -g /system/proxy/secure_port", "gsettings get org.gnome.system.proxy.https port" },
+ { "gconftool-2 -g /system/proxy/ftp_host", "gsettings get org.gnome.system.proxy.ftp host" },
+ { "gconftool-2 -g /system/proxy/ftp_port", "gsettings get org.gnome.system.proxy.ftp port" },
+ { "gconftool-2 -g /system/proxy/socks_host", "gsettings get org.gnome.system.proxy.socks host" },
+ { "gconftool-2 -g /system/proxy/socks_port", "gsettings get org.gnome.system.proxy.socks port" },
+ };
+
+ void check_vm_lock_os(void)
+ {
+ int shm_id;
+ void *shm_addr;
+ uint32_t port;
+ int val;
+ struct shmid_ds shm_info;
+
+ for (port = 26100; port < 26200; port += 10) {
+ shm_id = shmget((key_t)port, 0, 0);
+ if (shm_id != -1) {
+ shm_addr = shmat(shm_id, (void *)0, 0);
+ if ((void *)-1 == shm_addr) {
+ ERR("error occured at shmat()\n");
+ break;
+ }
+
+ val = shmctl(shm_id, IPC_STAT, &shm_info);
+ if (val != -1) {
+ INFO("count of process that use shared memory : %d\n",
+ shm_info.shm_nattch);
+ if ((shm_info.shm_nattch > 0) &&
+ g_strcmp0(tizen_target_img_path, (char *)shm_addr) == 0) {
+ if (check_port_bind_listen(port + 1) > 0) {
+ shmdt(shm_addr);
+ continue;
+ }
+ shmdt(shm_addr);
+ maru_register_exit_msg(MARU_EXIT_UNKNOWN,
+ "Can not execute this VM.\n"
+ "The same name is running now.");
+ exit(0);
+ } else {
+ shmdt(shm_addr);
+ }
+ }
+ }
+ }
+ }
+
+ void make_vm_lock_os(void)
+ {
+ int base_port;
+
+ base_port = get_emul_vm_base_port();
+
+ g_shmid = shmget((key_t)base_port, getpagesize(), 0666|IPC_CREAT);
+ if (g_shmid == -1) {
+ ERR("shmget failed\n");
+ perror("osutil-linux: ");
+ return;
+ }
+
+ g_shared_memory = shmat(g_shmid, (char *)0x00, 0);
+ if (g_shared_memory == (void *)-1) {
+ ERR("shmat failed\n");
+ perror("osutil-linux: ");
+ return;
+ }
+
+ g_sprintf(g_shared_memory, "%s", tizen_target_img_path);
+ INFO("shared memory key: %d value: %s\n",
+ base_port, (char *)g_shared_memory);
+
+ if (shmdt(g_shared_memory) == -1) {
+ ERR("shmdt failed\n");
+ perror("osutil-linux: ");
+ }
+ }
+
+ void remove_vm_lock_os(void)
+ {
+ if (shmctl(g_shmid, IPC_RMID, 0) == -1) {
+ ERR("shmctl failed\n");
+ perror("osutil-linux: ");
+ }
+ }
+
+ void set_bin_path_os(char const *const exec_argv)
+ {
+ gchar link_path[PATH_MAX] = { 0, };
+ char *file_name = NULL;
+
+ ssize_t len = readlink("/proc/self/exe", link_path, sizeof(link_path) - 1);
+
+ if (len < 0 || len > (sizeof(link_path) - 1)) {
+ perror("set_bin_path error : ");
+ return;
+ }
+
+ link_path[len] = '\0';
+
+ file_name = g_strrstr(link_path, "/");
+ g_strlcpy(bin_path, link_path, strlen(link_path) - strlen(file_name) + 1);
+
+ g_strlcat(bin_path, "/", PATH_MAX);
+
+ #ifdef CONFIG_SPICE
+ g_strlcpy(remote_bin_path, link_path, strlen(link_path) - strlen(file_name) - 2);
+ g_strlcat(remote_bin_path, "remote/bin/", PATH_MAX);
+ #endif
+ }
+
+ int get_number_of_processors(void)
+ {
+ int num_processors = 0;
+
+ num_processors = sysconf(_SC_NPROCESSORS_ONLN);
+ if (num_processors < 1) {
+ num_processors = 1;
+ }
+ TRACE("Number of processors : %d\n", num_processors);
+
+ return num_processors;
+ }
+
+ void print_system_info_os(void)
+ {
+ INFO("* Linux\n");
+
+ INFO("* LibPNG Version : %s\n", PNG_LIBPNG_VER_STRING);
+
+ /* depends on building */
+ INFO("* QEMU build machine linux kernel version : (%d, %d, %d)\n",
+ LINUX_VERSION_CODE >> 16,
+ (LINUX_VERSION_CODE >> 8) & 0xff,
+ LINUX_VERSION_CODE & 0xff);
+
+ /* depends on launching */
+ struct utsname host_uname_buf;
+ if (uname(&host_uname_buf) == 0) {
+ INFO("* Host machine uname : %s %s %s %s %s\n",
+ host_uname_buf.sysname, host_uname_buf.nodename,
+ host_uname_buf.release, host_uname_buf.version,
+ host_uname_buf.machine);
+ }
+
+ struct sysinfo sys_info;
+ if (sysinfo(&sys_info) == 0) {
+ INFO("* Total Ram : %llu kB, Free: %llu kB\n",
+ sys_info.totalram * (unsigned long long)sys_info.mem_unit / 1024,
+ sys_info.freeram * (unsigned long long)sys_info.mem_unit / 1024);
+ }
+
+ /* get linux distribution information */
+ INFO("* Linux distribution infomation :\n");
+ char const *const lsb_release_cmd = "lsb_release -d -r -c";
+ gchar *buffer = NULL;
+ gint buffer_size = strlen(lsb_release_cmd) + 1;
+
+ buffer = g_malloc(buffer_size);
+
+ g_snprintf(buffer, buffer_size, "%s", lsb_release_cmd);
+
+ if (system(buffer) < 0) {
+ INFO("system function command '%s' \
+ returns error !", buffer);
+ }
+ g_free(buffer);
+
+ /* pci device description */
+ INFO("* Host PCI devices :\n");
+ char const *const lspci_cmd = "lspci";
+ buffer_size = strlen(lspci_cmd) + 1;
+
+ buffer = g_malloc(buffer_size);
+
+ g_snprintf(buffer, buffer_size, "%s", lspci_cmd);
+
+ fflush(stdout);
+ if (system(buffer) < 0) {
+ INFO("system function command '%s' \
+ returns error !", buffer);
+ }
+ g_free(buffer);
+ }
+
+ static void process_string(char *buf)
+ {
+ char tmp_buf[DEFAULTBUFLEN];
+
+ /* remove single quotes of strings gotten by gsettings */
+ if (gproxytool == GSETTINGS) {
+ remove_string(buf, tmp_buf, "\'");
+ memset(buf, 0, DEFAULTBUFLEN);
+ strncpy(buf, tmp_buf, strlen(tmp_buf)-1);
+ }
+ }
+
+ static int get_auto_proxy(char *http_proxy, char *https_proxy, char *ftp_proxy, char *socks_proxy)
+ {
+ char type[DEFAULTBUFLEN];
+ char proxy[DEFAULTBUFLEN];
+ char line[DEFAULTBUFLEN];
+ FILE *fp_pacfile;
+ char *p = NULL;
+ FILE *output;
+ char buf[DEFAULTBUFLEN];
+
+ output = popen(gproxycmds[GNOME_PROXY_AUTOCONFIG_URL][gproxytool], "r");
+ if (fscanf(output, "%s", buf) > 0) {
+ process_string(buf);
+ INFO("pac address: %s\n", buf);
+ download_url(buf);
+ }
+
+ pclose(output);
+ fp_pacfile = fopen(pac_tempfile, "r");
+ if (fp_pacfile != NULL) {
+ while (fgets(line, DEFAULTBUFLEN, fp_pacfile) != NULL) {
+ if ((strstr(line, "return") != NULL) && (strstr(line, "if") == NULL)) {
+ INFO("line found %s", line);
+ sscanf(line, "%*[^\"]\"%s %s", type, proxy);
+ }
+ }
+
+ if (g_str_has_prefix(type, DIRECT)) {
+ INFO("auto proxy is set to direct mode\n");
+ fclose(fp_pacfile);
+ } else if (g_str_has_prefix(type, PROXY)) {
+ INFO("auto proxy is set to proxy mode\n");
+ INFO("type: %s, proxy: %s\n", type, proxy);
+
+ p = strtok(proxy, "\";");
+ if (p != NULL) {
+ INFO("auto proxy to set: %s\n",p);
+ strcpy(http_proxy, p);
+ strcpy(https_proxy, p);
+ strcpy(ftp_proxy, p);
+ strcpy(socks_proxy, p);
+ }
+ fclose(fp_pacfile);
+ } else {
+ ERR("pac file is not wrong! It could be the wrong pac address or pac file format\n");
+ fclose(fp_pacfile);
+ }
+ } else {
+ ERR("fail to get pacfile fp\n");
+ return -1;
+ }
+
+ if (remove(pac_tempfile) < 0) {
+ WARN("fail to remove the temporary pacfile\n");
+ }
+
+ return 0;
+ }
+
+ static void get_proxy(char *http_proxy, char *https_proxy, char *ftp_proxy, char *socks_proxy)
+ {
+ char buf[DEFAULTBUFLEN] = {0,};
+ char buf_port[MAXPORTLEN] = {0,};
+ char buf_proxy[DEFAULTBUFLEN] = {0,};
+ char *buf_proxy_bak;
+ char *proxy;
+ FILE *output;
+ int MAXPROXYLEN = DEFAULTBUFLEN + MAXPORTLEN;
+
+ output = popen(gproxycmds[GNOME_PROXY_HTTP_HOST][gproxytool], "r");
+ if(fscanf(output, "%s", buf) > 0) {
+ process_string(buf);
+ snprintf(buf_proxy, DEFAULTBUFLEN, "%s", buf);
+ }
+ pclose(output);
+
+ output = popen(gproxycmds[GNOME_PROXY_HTTP_PORT][gproxytool], "r");
+ if(fscanf(output, "%s", buf_port) <= 0) {
+ //for abnormal case: if can't find the key of http port, get from environment value.
+ buf_proxy_bak = getenv("http_proxy");
+ INFO("http_proxy from env: %s\n", buf_proxy_bak);
+ if(buf_proxy_bak != NULL) {
+ proxy = malloc(DEFAULTBUFLEN);
+ remove_string(buf_proxy_bak, proxy, HTTP_PREFIX);
+ strncpy(http_proxy, proxy, strlen(proxy)-1);
+ INFO("final http_proxy value: %s\n", http_proxy);
+ free(proxy);
+ }
+ else {
+ INFO("http_proxy is not set on env.\n");
+ pclose(output);
+ return;
+ }
+
+ }
+ else {
+ snprintf(http_proxy, MAXPROXYLEN, "%s:%s", buf_proxy, buf_port);
+ memset(buf_proxy, 0, DEFAULTBUFLEN);
+ INFO("http_proxy: %s\n", http_proxy);
+ }
+ pclose(output);
+
+ memset(buf, 0, DEFAULTBUFLEN);
+
+ output = popen(gproxycmds[GNOME_PROXY_HTTPS_HOST][gproxytool], "r");
+ if(fscanf(output, "%s", buf) > 0) {
+ process_string(buf);
+ snprintf(buf_proxy, DEFAULTBUFLEN, "%s", buf);
+ }
+ pclose(output);
+
+ output = popen(gproxycmds[GNOME_PROXY_HTTPS_PORT][gproxytool], "r");
+ if(fscanf(output, "%s", buf) > 0) {
+ snprintf(https_proxy, MAXPROXYLEN, "%s:%s", buf_proxy, buf);
+ }
+ pclose(output);
+ memset(buf, 0, DEFAULTBUFLEN);
+ memset(buf_proxy, 0, DEFAULTBUFLEN);
+ INFO("https_proxy : %s\n", https_proxy);
+
+ output = popen(gproxycmds[GNOME_PROXY_FTP_HOST][gproxytool], "r");
+ if(fscanf(output, "%s", buf) > 0) {
+ process_string(buf);
+ snprintf(buf_proxy, DEFAULTBUFLEN, "%s", buf);
+ }
+ pclose(output);
+
+ output = popen(gproxycmds[GNOME_PROXY_FTP_PORT][gproxytool], "r");
+ if(fscanf(output, "%s", buf) > 0) {
+ snprintf(ftp_proxy, MAXPROXYLEN, "%s:%s", buf_proxy, buf);
+ }
+ pclose(output);
+ memset(buf, 0, DEFAULTBUFLEN);
+ memset(buf_proxy, 0, DEFAULTBUFLEN);
+ INFO("ftp_proxy : %s\n", ftp_proxy);
+
+ output = popen(gproxycmds[GNOME_PROXY_SOCKS_HOST][gproxytool], "r");
+ if(fscanf(output, "%s", buf) > 0) {
+ process_string(buf);
+ snprintf(buf_proxy, DEFAULTBUFLEN, "%s", buf);
+ }
+ pclose(output);
+
+ output = popen(gproxycmds[GNOME_PROXY_SOCKS_PORT][gproxytool], "r");
+ if(fscanf(output, "%s", buf) > 0) {
+ snprintf(socks_proxy, MAXPROXYLEN, "%s:%s", buf_proxy, buf);
+ }
+ pclose(output);
+ INFO("socks_proxy : %s\n", socks_proxy);
+ }
+
+
+ void get_host_proxy_os(char *http_proxy, char *https_proxy, char *ftp_proxy, char *socks_proxy)
+ {
+ char buf[DEFAULTBUFLEN];
+ FILE *output;
+ int ret;
+
+ output = popen(gproxycmds[GNOME_PROXY_MODE][gproxytool], "r");
+ ret = fscanf(output, "%s", buf);
+ if (ret <= 0) {
+ pclose(output);
+ INFO("Try to use gsettings to get proxy\n");
+ gproxytool = GSETTINGS;
+ output = popen(gproxycmds[GNOME_PROXY_MODE][gproxytool], "r");
+ ret = fscanf(output, "%s", buf);
+ }
+ if (ret > 0) {
+ process_string(buf);
+ //priority : auto > manual > none
+ if (strcmp(buf, "auto") == 0) {
+ INFO("AUTO PROXY MODE\n");
+ get_auto_proxy(http_proxy, https_proxy, ftp_proxy, socks_proxy);
+ }
+ else if (strcmp(buf, "manual") == 0) {
+ INFO("MANUAL PROXY MODE\n");
+ get_proxy(http_proxy, https_proxy, ftp_proxy, socks_proxy);
+ }
+ else if (strcmp(buf, "none") == 0) {
+ INFO("DIRECT PROXY MODE\n");
+ }
+ }
+ pclose(output);
+ }
+
+ #ifdef CONFIG_SPICE
+ #define PID_MAX_COUNT 256
+ const char *execution_file_websocket = "websockify.py";
+ const char *execution_file_node = "node";
+ const char *node_proc_name = "emulator-x86-web";
+
+ void get_process_id(char const *process_name, char *first_param, int *pid, int *pscount)
+ {
+ char cmdline[2048], dir_name[255];
+ int total_len = 0, current_len = 0;
+ struct dirent *dir_entry_p;
+ DIR *dir_p;
+ FILE *fp;
+ char *mptr;
+
+ dir_p = opendir("/proc/");
+ while (NULL != (dir_entry_p = readdir(dir_p))) {
+ /* Checking for numbered directories */
+ if (strspn(dir_entry_p->d_name, "0123456789") == strlen(dir_entry_p->d_name)) {
+ strcpy(dir_name, "/proc/");
+ strcat(dir_name, dir_entry_p->d_name);
+ strcat(dir_name, "/cmdline");
+
+ fp = fopen(dir_name, "rb");
+ if (fp == NULL) {
+ continue;
+ }
+
+ total_len = 0;
+ memset(cmdline, 0, sizeof(cmdline));
+ while (!feof(fp)) {
+ cmdline[total_len++] = fgetc(fp);
+ }
+
+ fclose(fp);
+ current_len = strlen(cmdline);
+ mptr = cmdline;
+ do {
+ if (strstr(mptr, process_name) != NULL) {
+ if (!first_param || strstr(&cmdline[current_len + 1], first_param) != NULL) {
+ if (sizeof(pid) < *pscount + 1) {
+ WARN("PID array size is not enough.\n");
+ return;
+ }
+ pid[*pscount] = atoi(dir_entry_p->d_name);
+ INFO("get_process_id(%s %s) :Found. id = %d\n", process_name, first_param, pid[*pscount]);
+ (*pscount)++;
+ }
+ break;
+ }
+
+ mptr = &cmdline[current_len + 1];
+ current_len += strlen(mptr) + 1;
+ } while (current_len < total_len);
+ }
+ }
+
+ closedir(dir_p);
+ if (*pscount == 0) {
+ INFO("get_process_id(%s %s) : id = 0 (could not find process)\n", process_name, first_param);
+ }
+ }
+
+ void execute_websocket(int port)
+ {
+ char const *remote_bin_dir = get_remote_bin_path();
+ char const *relative_path = "../websocket/";
+ char websocket_path[strlen(remote_bin_dir) + strlen(execution_file_websocket) + strlen(relative_path) + 1];
+ int ret = -1;
+ char local_port[32];
+ char websocket_port[16];
+
+ memset(websocket_port, 0, sizeof(websocket_port));
+ sprintf(websocket_port, "%d", port);
+
+ memset(local_port, 0, sizeof(local_port));
+ sprintf(local_port, "localhost:%d", get_emul_spice_port());
+
+ memset(websocket_path, 0, sizeof(websocket_path));
+ sprintf(websocket_path, "%s%s%s", remote_bin_dir, relative_path, execution_file_websocket);
+
+ INFO("Exec [%s %s %s]\n", websocket_path, websocket_port, local_port);
+
+ ret = execl(websocket_path, execution_file_websocket, websocket_port, local_port, (char *)0);
+ if (ret == 127) {
+ WARN("Can't execute websocket.\n");
+ } else if (ret == -1) {
+ WARN("Fork error!\n");
+ }
+ }
+
+ void execute_nodejs(void)
+ {
+ char const *remote_bin_dir = get_remote_bin_path();
+ char const *relative_path = "../web-viewer/bin/emul";
+ char webviewer_script[strlen(remote_bin_dir) + strlen(relative_path) + 1];
+ char nodejs_path[strlen(remote_bin_dir) + strlen(execution_file_node) + 1];
+ int ret = -1;
+
+ memset(webviewer_script, 0, sizeof(webviewer_script));
+ sprintf(webviewer_script, "%s%s", remote_bin_dir, relative_path);
+
+ memset(nodejs_path, 0, sizeof(nodejs_path));
+ sprintf(nodejs_path, "%s%s", remote_bin_dir, execution_file_node);
+
+ INFO("Exec [%s %s]\n", nodejs_path, webviewer_script);
+
+ ret = execl(nodejs_path, execution_file_node, webviewer_script, (char *)0);
+ if (ret == 127) {
+ WARN("Can't execute node server.\n");
+ } else if (ret == -1) {
+ WARN("Fork error!\n");
+ }
+ }
+
+ void clean_websocket_port(int signal)
+ {
+ char websocket_port[16];
+ memset(websocket_port, 0, sizeof(websocket_port));
+ sprintf(websocket_port, "%d", get_emul_websocket_port());
+
+ int pscount = 0, i = 0;
+ int pid[PID_MAX_COUNT];
+
+ memset(pid, 0, PID_MAX_COUNT);
+ get_process_id(execution_file_websocket, websocket_port, pid, &pscount);
+ if (pscount > 0) {
+ for (i = 0; i < pscount; i++) {
+ INFO("Will be killed PID: %d\n", pid[i]);
+ kill(pid[i], signal);
+ }
+ }
+ }
+
+ static void websocket_notify_exit(Notifier *notifier, void *data)
+ {
+ clean_websocket_port(SIGTERM);
+ }
+
+ static void nodejs_notify_exit(Notifier *notifier, void *data)
+ {
+ int pscount = 0, i = 0;
+ int pid[PID_MAX_COUNT];
+
+ memset(pid, 0, sizeof(pid));
+ get_process_id("spicevmc", NULL, pid, &pscount);
+ if (pscount == 1) {
+ INFO("Detected the last spice emulator.\n");
+ pid[0] = 0;
+ pscount = 0;
+ get_process_id(node_proc_name, NULL, pid, &pscount);
+ for (i = 0; i < pscount; i++) {
+ INFO("Will be killed %s, PID: %d\n", node_proc_name, pid[i]);
+ kill(pid[i], SIGTERM);
+ }
+ }
+ }
+
+ static Notifier websocket_exit = { .notify = websocket_notify_exit };
+ static Notifier nodejs_exit = { .notify = nodejs_notify_exit };
+
+ void websocket_init(void)
+ {
+ int pscount = 0;
+ char websocket_port[16];
+ int pid[PID_MAX_COUNT];
+
+ memset(websocket_port, 0, sizeof(websocket_port));
+ sprintf(websocket_port, "%d", get_emul_websocket_port());
+
+ memset(pid, 0, sizeof(pid));
+ get_process_id(execution_file_websocket, websocket_port, pid, &pscount);
+ emulator_add_exit_notifier(&websocket_exit);
+
+ if (pscount == 0) {
+ int pid = fork();
+ if (pid == 0) {
+ setsid();
+ execute_websocket(get_emul_websocket_port());
+ }
+ } else {
+ INFO("Aleady running websokify %s localhost:%d\n", websocket_port, get_emul_spice_port());
+ }
+ }
+
+ void nodejs_init(void)
+ {
+ int pscount = 0;
+ int pid[PID_MAX_COUNT];
+
+ memset(pid, 0, sizeof(pid));
+ get_process_id(node_proc_name, NULL, pid, &pscount);
+ emulator_add_exit_notifier(&nodejs_exit);
+
+ if (pscount == 0) {
+ int pid = fork();
+ if (pid == 0) {
+ setsid();
+ execute_nodejs();
+ }
+ } else {
+ INFO("Aleady running node server.\n");
+ }
+ }
+ #endif
++
+ bool make_sdcard_lock_os(char *sdcard)
+ {
- return remove_sdcard_lock(sdcard);
++ return make_sdcard_lock_posix(sdcard);
+ }
+
+
+ int remove_sdcard_lock_os(char *sdcard)
+ {
++ return remove_sdcard_lock_posix(sdcard);
+ }
--- /dev/null
-inline bool make_sdcard_lock(char *sdcard)
+ /*
+ * Emulator
+ *
+ * Copyright (C) 2012, 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * SeokYeon Hwang <syeon.hwang@samsung.com>
+ * MunKyu Im <munkyu.im@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ * HyunJun Son
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+ /**
+ @file osutil.c
+ @brief Common functions for osutil
+ */
+
+ #include "osutil.h"
+ #include "debug_ch.h"
+
+ #include <curl/curl.h>
+ #include <string.h>
+
+ MULTI_DEBUG_CHANNEL(emulator, osutil);
+
+
+ const char *pac_tempfile = ".autoproxy";
+ #ifndef CONFIG_WIN32
+ static int g_fd;
+ #endif
+ inline size_t write_data(void *ptr, size_t size, size_t nmemb, FILE *stream)
+ {
+ size_t written;
+ written = fwrite(ptr, size, nmemb, stream);
+ return written;
+ }
+
+ void download_url(char *url)
+ {
+ CURL *curl;
+ FILE *fp;
+ CURLcode res;
+
+ curl = curl_easy_init();
+ if (curl) {
+ fp = fopen(pac_tempfile, "wb");
+ if(fp == NULL) {
+ ERR("failed to fopen(): %s\n", pac_tempfile);
+ return;
+ }
+ curl_easy_setopt(curl, CURLOPT_URL, url);
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
+ /* just in case network does not work */
+ curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, 3000);
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
+
+ res = curl_easy_perform(curl);
+ if (res != 0) {
+ ERR("Fail to download pac file: %s\n", url);
+ }
+
+ curl_easy_cleanup(curl);
+ fclose(fp);
+ }
+
+ return;
+ }
+
+ inline void remove_string(char *src, char *dst, const char *toremove)
+ {
+ int len = strlen(toremove);
+ int i, j;
+ int max_len = strlen(src);
+
+ for(i = len, j = 0; i < max_len; i++)
+ {
+ dst[j++] = src[i];
+ }
+
+ dst[j] = '\0';
+ }
+
+ #ifndef CONFIG_WIN32
+ static int fd_lock(int fd)
+ {
+ struct flock lock;
+
+ lock.l_type = F_WRLCK;
+ lock.l_start = 0;
+ lock.l_whence = SEEK_SET;
+ lock.l_len = 0;
+ lock.l_pid = getpid();
+
+ return fcntl(fd, F_SETLK, &lock);
+ }
+
+ static int fd_unlock(int fd)
+ {
+ struct flock lock;
+
+ lock.l_type = F_UNLCK;
+ lock.l_start = 0;
+ lock.l_whence = SEEK_SET;
+ lock.l_len = 0;
+
+ return fcntl(fd, F_SETLK, &lock);
+ }
+
-inline int remove_sdcard_lock(char *sdcard)
++inline bool make_sdcard_lock_posix(char *sdcard)
+ {
+ char *lock_file = g_strdup_printf("%s.lck", sdcard);
+ int fd = open(lock_file, O_CREAT|O_RDWR, 0666);
+ if (fd == -1)
+ {
+ perror("file open error : ");
+ return false;
+ }
+ if (fd_lock(fd) == -1)
+ {
+ perror("file is lock ");
+ close(fd);
+ return false;
+ }
+
+ INFO("Get file lock: %s\n", lock_file);
+ g_fd = fd;
+ close(fd);
+ return true;
+
+ }
+
++inline int remove_sdcard_lock_posix(char *sdcard)
+ {
+ errno = 0;
+ char *lock_file = g_strdup_printf("%s.lck", sdcard);
+ int fd = open(lock_file, O_RDWR, 0666);
+ if (fd == -1)
+ {
+ perror("file open error : ");
+ if(errno == ENOENT) {
+ return ERR_NOENT;
+ }
+ return ERR_UNLCK;
+ }
+
+ if (fd_unlock(fd) == -1)
+ {
+ perror("file unlock error ");
+ close(fd);
+ return ERR_UNLCK;
+ }
+
+ if (unlink(lock_file) < 0) {
+ perror("unlink error ");
+ close(fd);
+ return ERR_UNLCK;
+ }
+
+ INFO("unlock success: %s\n", lock_file);
+ close(fd);
+ close(g_fd);
+ return ERR_SUCCESS;
+ }
+ #endif
--- /dev/null
-bool make_sdcard_lock(char *sdcard);
-int remove_sdcard_lock(char *sdcard);
+ /*
+ * Emulator
+ *
+ * Copyright (C) 2011, 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * SeokYeon Hwang <syeon.hwang@samsung.com>
+ * MunKyu Im <munkyu.im@samsung.com>
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ * HyunJun Son
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+ #ifndef __OSUTIL_H__
+ #define __OSUTIL_H__
+
+ #include "qemu-common.h"
+
+ #define HTTP_PROTOCOL "http="
+ #define HTTP_PREFIX "http://"
+ #define HTTPS_PROTOCOL "https="
+ #define FTP_PROTOCOL "ftp="
+ #define SOCKS_PROTOCOL "socks="
+ #define DIRECT "DIRECT"
+ #define PROXY "PROXY"
+ #define MAXPORTLEN 6
+ #define DEFAULTBUFLEN 512
+
+ #define GNOME_PROXY_MODE 0
+ #define GNOME_PROXY_AUTOCONFIG_URL 1
+ #define GNOME_PROXY_HTTP_HOST 2
+ #define GNOME_PROXY_HTTP_PORT 3
+ #define GNOME_PROXY_HTTPS_HOST 4
+ #define GNOME_PROXY_HTTPS_PORT 5
+ #define GNOME_PROXY_FTP_HOST 6
+ #define GNOME_PROXY_FTP_PORT 7
+ #define GNOME_PROXY_SOCKS_HOST 8
+ #define GNOME_PROXY_SOCKS_PORT 9
+ #define GCONFTOOL 0
+ #define GSETTINGS 1
+
+ #define ERR_SUCCESS 0
+ #define ERR_UNLCK 4
+ #define ERR_LCK 5
+ #define ERR_NOENT 6
+
+ extern const char *pac_tempfile;
+
+ void check_vm_lock_os(void);
+ void make_vm_lock_os(void);
+ void remove_vm_lock_os(void);
+ bool make_sdcard_lock_os(char *sdcard);
+ int remove_sdcard_lock_os(char *sdcard);
+
+ void set_bin_path_os(char const *const);
+ #ifndef CONFIG_WIN32
++bool make_sdcard_lock_posix(char *sdcard);
++int remove_sdcard_lock_posix(char *sdcard);
+ #endif
+
+ void print_system_info_os(void);
+
+ void get_host_proxy_os(char *, char *, char *, char *);
+
+ void download_url(char *);
+ size_t write_data(void *, size_t, size_t, FILE *);
+ void remove_string(char *, char *, const char *);
+
+ #if defined(CONFIG_SPICE) && defined(CONFIG_LINUX)
+ void get_process_id(char const *process_name, char *first_param, int *pid, int *pscount);
+ void execute_websocket(int port);
+ void execute_nodejs(void);
+ void clean_websocket_port(int signal);
+ void nodejs_init(void);
+ void websocket_init(void);
+ #endif
+
+ static inline int get_timeofday(char *buf, size_t size)
+ {
+ qemu_timeval tv;
+ time_t ti;
+ struct tm *ptm = NULL;
+ int ret;
+
+ qemu_gettimeofday(&tv);
+ ti = tv.tv_sec;
+
+ /* In this case, localtime_r() function is not necessary. */
+ ptm = localtime(&ti);
+ ret = strftime(buf, size, "%H:%M:%S", ptm);
+
+ return ret + g_snprintf(buf + ret, size - ret, ".%06ld", (long)tv.tv_usec);
+ }
+
+ int get_number_of_processors(void);
+
+ #endif // __OS_UTIL_H__
+