ecs: sync with 2.3 development
[sdk/emulator/qemu.git] / tizen / src / ecs / ecs_msg_injector.c
1 /* Emulator Control Server
2  *
3  * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
4  *
5  * Contact:
6  *  Jinhyung choi   <jinhyung2.choi@samsung.com>
7  *  MunKyu Im       <munkyu.im@samsung.com>
8  *  Daiyoung Kim    <daiyoung777.kim@samsung.com>
9  *  YeongKyoon Lee  <yeongkyoon.lee@samsung.com>
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
24  *
25  * Contributors:
26  * - S-Core Co., Ltd
27  *
28  */
29
30 #include "qemu-common.h"
31
32 #include "hw/virtio/maru_virtio_vmodem.h"
33 #include "hw/virtio/maru_virtio_evdi.h"
34 #include "hw/virtio/maru_virtio_jack.h"
35 #include "hw/virtio/maru_virtio_power.h"
36
37 #include "util/maru_device_hotplug.h"
38 #include "emul_state.h"
39 #include "ecs.h"
40 #include "debug_ch.h"
41 #include "util/osutil.h"
42
43 MULTI_DEBUG_CHANNEL(qemu, ecs);
44
45 extern QemuMutex mutex_guest_connection;
46 static int guest_connection = 0;
47
48 extern QemuMutex mutex_location_data;
49 static char location_data[MAX_INJECTOR_REQ_DATA];
50 static void send_gen_injector_ntf(const char* cmd, int cmdlen, int grp, int act, char* on)
51 {
52     int msglen = 0, datalen = 0;
53     type_length length  = 0;
54     type_group group = grp;
55     type_action action = act;
56
57     if (cmd == NULL || cmdlen > 10)
58         return;
59
60     if (on == NULL) {
61         msglen = 14;
62     } else {
63         datalen = strlen(on);
64         length  = (unsigned short)datalen;
65
66         msglen = datalen + 15;
67     }
68
69     char* status_msg = (char*) malloc(msglen);
70     if(!status_msg)
71         return;
72
73     memset(status_msg, 0, msglen);
74
75     memcpy(status_msg, cmd, cmdlen);
76     memcpy(status_msg + 10, &length, sizeof(unsigned short));
77     memcpy(status_msg + 12, &group, sizeof(unsigned char));
78     memcpy(status_msg + 13, &action, sizeof(unsigned char));
79
80     if (on != NULL) {
81         memcpy(status_msg + 14, on, datalen);
82     }
83
84     send_injector_ntf(status_msg, msglen);
85
86     free(status_msg);
87 }
88
89 static void msgproc_injector_ans(ECS_Client* ccli, const char* category, bool succeed)
90 {
91     if (ccli == NULL) {
92         return;
93     }
94     int catlen = 0;
95     ECS__Master master = ECS__MASTER__INIT;
96     ECS__InjectorAns ans = ECS__INJECTOR_ANS__INIT;
97
98     TRACE("injector ans - category : %s, succed : %d\n", category, succeed);
99
100     catlen = strlen(category);
101     ans.category = (char*) g_malloc0(catlen + 1);
102     memcpy(ans.category, category, catlen);
103
104     ans.errcode = !succeed;
105     master.type = ECS__MASTER__TYPE__INJECTOR_ANS;
106     master.injector_ans = &ans;
107
108     pb_to_all_clients(&master);
109
110     if (ans.category)
111         g_free(ans.category);
112 }
113
114 static bool injector_send(ECS_Client* ccli, ECS__InjectorReq* msg, char* cmd)
115 {
116     int sndlen = 15; // HEADER(CMD + LENGTH + GROUP + ACTION) + 1
117     const char* msg_data;
118     char* sndbuf;
119     bool ret = false;
120     type_group group;
121
122     group = (type_group) (msg->group & 0xff);
123
124     if (msg->has_data && msg->data.data && msg->data.len > 0)
125         sndlen += msg->data.len;
126
127     sndbuf = (char*) g_malloc0(sndlen);
128     if (!sndbuf) {
129         msgproc_injector_ans(ccli, cmd, false);
130         return false;
131     }
132
133     memcpy(sndbuf, cmd, 10);
134     memcpy(sndbuf + 10, &msg->length, 2);
135     memcpy(sndbuf + 12, &msg->group, 1);
136     memcpy(sndbuf + 13, &msg->action, 1);
137
138     if (msg->has_data && msg->data.data && msg->data.len > 0) {
139         msg_data = (const char*)msg->data.data;
140         memcpy(sndbuf + 14, msg_data, msg->data.len);
141         TRACE(">> print len = %zd, data\" %s\"\n", msg->data.len, msg_data);
142     }
143
144     if(strcmp(cmd, "telephony") == 0) {
145         TRACE("telephony msg >>");
146         ret = send_to_vmodem(route_ij, sndbuf, sndlen);
147     } else {
148         TRACE("evdi msg >> %s", cmd);
149         ret = send_to_evdi(route_ij, sndbuf, sndlen);
150     }
151
152     g_free(sndbuf);
153
154     if (group != MSG_GROUP_STATUS) {
155         msgproc_injector_ans(ccli, cmd, ret);
156     }
157
158     if (!ret) {
159         return false;
160     }
161
162     return true;
163 }
164
165 static char* get_emulator_sdcard_path(void)
166 {
167     char *emulator_sdcard_path = NULL;
168     char *tizen_sdk_data = NULL;
169
170 #ifndef CONFIG_WIN32
171     char emulator_sdcard[] = "/emulator/sdcard/";
172 #else
173     char emulator_sdcard[] = "\\emulator\\sdcard\\";
174 #endif
175
176     TRACE("emulator_sdcard: %s, %zu\n", emulator_sdcard, sizeof(emulator_sdcard));
177
178     tizen_sdk_data = get_tizen_sdk_data_path();
179     if (!tizen_sdk_data) {
180         ERR("failed to get tizen-sdk-data path.\n");
181         return NULL;
182     }
183
184     emulator_sdcard_path =
185         g_malloc(strlen(tizen_sdk_data) + sizeof(emulator_sdcard) + 1);
186     if (!emulator_sdcard_path) {
187         ERR("failed to allocate memory.\n");
188         return NULL;
189     }
190
191     g_snprintf(emulator_sdcard_path, strlen(tizen_sdk_data) + sizeof(emulator_sdcard),
192              "%s%s", tizen_sdk_data, emulator_sdcard);
193
194     g_free(tizen_sdk_data);
195
196     TRACE("sdcard path: %s\n", emulator_sdcard_path);
197     return emulator_sdcard_path;
198 }
199
200 static char *get_old_tizen_sdk_data_path(void)
201 {
202     char *tizen_sdk_data_path = NULL;
203
204     INFO("try to search tizen-sdk-data path in another way.\n");
205
206 #ifndef CONFIG_WIN32
207     char tizen_sdk_data[] = "/tizen-sdk-data";
208     int tizen_sdk_data_len = 0;
209     char *home_dir;
210
211     home_dir = (char *)g_getenv("HOME");
212     if (!home_dir) {
213         home_dir = (char *)g_get_home_dir();
214     }
215
216     tizen_sdk_data_len = strlen(home_dir) + sizeof(tizen_sdk_data) + 1;
217     tizen_sdk_data_path = g_malloc(tizen_sdk_data_len);
218     if (!tizen_sdk_data_path) {
219         ERR("failed to allocate memory.\n");
220         return NULL;
221     }
222     g_strlcpy(tizen_sdk_data_path, home_dir, tizen_sdk_data_len);
223     g_strlcat(tizen_sdk_data_path, tizen_sdk_data, tizen_sdk_data_len);
224
225 #else
226     char tizen_sdk_data[] = "\\tizen-sdk-data\\";
227     gint tizen_sdk_data_len = 0;
228     HKEY hKey;
229     char strLocalAppDataPath[1024] = { 0 };
230     DWORD dwBufLen = 1024;
231
232     RegOpenKeyEx(HKEY_CURRENT_USER,
233         "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders",
234         0, KEY_QUERY_VALUE, &hKey);
235
236     RegQueryValueEx(hKey, "Local AppData", NULL,
237                     NULL, (LPBYTE)strLocalAppDataPath, &dwBufLen);
238     RegCloseKey(hKey);
239
240     tizen_sdk_data_len = strlen(strLocalAppDataPath) + sizeof(tizen_sdk_data) + 1;
241     tizen_sdk_data_path = g_malloc(tizen_sdk_data_len);
242     if (!tizen_sdk_data_path) {
243         ERR("failed to allocate memory.\n");
244         return NULL;
245     }
246
247     g_strlcpy(tizen_sdk_data_path, strLocalAppDataPath, tizen_sdk_data_len);
248     g_strlcat(tizen_sdk_data_path, tizen_sdk_data, tizen_sdk_data_len);
249 #endif
250
251     INFO("tizen-sdk-data path: %s\n", tizen_sdk_data_path);
252     return tizen_sdk_data_path;
253 }
254
255 /*
256  *  get tizen-sdk-data path from sdk.info.
257  */
258 char *get_tizen_sdk_data_path(void)
259 {
260     char const *emul_bin_path = NULL;
261     char *sdk_info_file_path = NULL;
262     char *tizen_sdk_data_path = NULL;
263 #ifndef CONFIG_WIN32
264     const char *sdk_info = "../../../sdk.info";
265 #else
266     const char *sdk_info = "..\\..\\..\\sdk.info";
267 #endif
268     const char sdk_data_var[] = "TIZEN_SDK_DATA_PATH";
269
270     FILE *sdk_info_fp = NULL;
271     int sdk_info_path_len = 0;
272
273     TRACE("%s\n", __func__);
274
275     emul_bin_path = get_bin_path();
276     if (!emul_bin_path) {
277         ERR("failed to get emulator path.\n");
278         return NULL;
279     }
280
281     sdk_info_path_len = strlen(emul_bin_path) + strlen(sdk_info) + 1;
282     sdk_info_file_path = g_malloc(sdk_info_path_len);
283     if (!sdk_info_file_path) {
284         ERR("failed to allocate sdk-data buffer.\n");
285         return NULL;
286     }
287
288     g_snprintf(sdk_info_file_path, sdk_info_path_len, "%s%s",
289                 emul_bin_path, sdk_info);
290     INFO("sdk.info path: %s\n", sdk_info_file_path);
291
292     sdk_info_fp = fopen(sdk_info_file_path, "r");
293     g_free(sdk_info_file_path);
294
295     if (sdk_info_fp) {
296         TRACE("Succeeded to open [sdk.info].\n");
297
298         char tmp[256] = { '\0', };
299         char *tmpline = NULL;
300         while (fgets(tmp, sizeof(tmp), sdk_info_fp) != NULL) {
301             if ((tmpline = g_strstr_len(tmp, sizeof(tmp), sdk_data_var))) {
302                 tmpline += strlen(sdk_data_var) + 1; // 1 for '='
303                 break;
304             }
305         }
306
307         if (tmpline) {
308             if (tmpline[strlen(tmpline) - 1] == '\n') {
309                 tmpline[strlen(tmpline) - 1] = '\0';
310             }
311             if (tmpline[strlen(tmpline) - 1] == '\r') {
312                 tmpline[strlen(tmpline) - 1] = '\0';
313             }
314
315             tizen_sdk_data_path = g_malloc(strlen(tmpline) + 1);
316             g_strlcpy(tizen_sdk_data_path, tmpline, strlen(tmpline) + 1);
317
318             INFO("tizen-sdk-data path: %s\n", tizen_sdk_data_path);
319
320             fclose(sdk_info_fp);
321             return tizen_sdk_data_path;
322         }
323
324         fclose(sdk_info_fp);
325     }
326
327     // legacy mode
328     ERR("Failed to open [sdk.info].\n");
329
330     return get_old_tizen_sdk_data_path();
331 }
332
333 static char* get_sdcard_img_path(char* sdcard_img_name, size_t dataLen) {
334     char* sdcard_img_path = NULL;
335     char* sdcard_path = NULL;
336     if (sdcard_img_name == NULL || dataLen < 3) {
337         return NULL;
338     }
339     dataLen = dataLen - 3;
340     if (sdcard_img_name[dataLen] == '\n') {
341         sdcard_img_name[dataLen] = '\0';
342         TRACE("sdcard_img_name: %s\n", sdcard_img_name);
343     } else {
344         ERR("wrong sdcard message!\n");
345         return NULL;
346     }
347
348     sdcard_path = get_emulator_sdcard_path();
349     if (sdcard_path != NULL) {
350         sdcard_img_path = g_malloc(DEFAULTBUFLEN);
351         g_strlcpy(sdcard_img_path, sdcard_path, DEFAULTBUFLEN);
352         g_strlcat(sdcard_img_path, sdcard_img_name, DEFAULTBUFLEN);
353         TRACE("sdcard img path: [%s] length: %d\n", sdcard_img_path, strlen(sdcard_img_path));
354         g_free(sdcard_path);
355         return sdcard_img_path;
356     }
357     return NULL;
358 }
359
360 static int handle_sdcard(char* dataBuf, size_t dataLen)
361 {
362     int err_no = 0;
363     char ret = 0;
364     if (dataBuf != NULL){
365         ret = dataBuf[0];
366
367         if (ret == '0' ) {
368             /* umount sdcard */
369             INFO("datalen: %d\n", dataLen);
370             char* sdcard_img_path = get_sdcard_img_path(dataBuf + 2, dataLen);
371             err_no = remove_sdcard_lock_os(sdcard_img_path);
372             if (errno == 0 && is_sdcard_attached()) {
373                 do_hotplug(DETACH_SDCARD, NULL, 0);
374             } else {
375                 ERR("failed to umount: %s\n", sdcard_img_path);
376                 send_gen_injector_ntf(MSG_TYPE_SDCARD, 6, 11, err_no, NULL);
377                 return err_no;
378             }
379             g_free(sdcard_img_path);
380         } else if (ret == '1') {
381             /* mount sdcard */
382             INFO("datalen: %d\n", dataLen);
383             char* sdcard_img_path = get_sdcard_img_path(dataBuf + 2, dataLen);
384             if ( !is_sdcard_attached() && make_sdcard_lock_os(sdcard_img_path)) {
385                 do_hotplug(ATTACH_SDCARD, sdcard_img_path, strlen(sdcard_img_path) + 1);
386                 send_gen_injector_ntf(MSG_TYPE_SDCARD, 6, 11, 0, NULL);
387             } else {
388                 send_gen_injector_ntf(MSG_TYPE_SDCARD, 6, 11, 5, NULL);
389                 return ERR_LCK;
390             }
391             g_free(sdcard_img_path);
392
393         } else if (ret == '2') {
394             TRACE("sdcard status 2 bypass\n" );
395         } else {
396             ERR("!!! unknown command : %c\n", ret);
397             return ret;
398         }
399     } else {
400         ERR("!!! unknown data : %c\n", ret);
401         return ret;
402     }
403     return ERR_SUCCESS;
404 }
405
406 static bool injector_req_sdcard(ECS_Client* ccli, ECS__InjectorReq* msg, char *cmd)
407 {
408     if (msg->has_data) {
409         TRACE("msg(%zu) : %s\n", msg->data.len, msg->data.data);
410         if (handle_sdcard((char*) msg->data.data, msg->data.len) > 0) {
411             return false;
412         }
413     } else {
414         ERR("has no msg\n");
415     }
416
417     injector_send(ccli, msg, cmd);
418
419     return true;
420 }
421
422 static void send_status_injector_ntf(const char* cmd, int cmdlen, int act, char* on)
423 {
424     int msglen = 0, datalen = 0;
425     type_length length  = 0;
426     type_group group = MSG_GROUP_STATUS;
427     type_action action = act;
428
429     if (cmd == NULL || cmdlen > 10)
430         return;
431
432     if (on == NULL) {
433         msglen = 14;
434     } else {
435         datalen = strlen(on);
436         length  = (unsigned short)datalen;
437
438         msglen = datalen + 15;
439     }
440
441     char* status_msg = (char*) malloc(msglen);
442     if(!status_msg)
443         return;
444
445     memset(status_msg, 0, msglen);
446
447     memcpy(status_msg, cmd, cmdlen);
448     memcpy(status_msg + 10, &length, sizeof(unsigned short));
449     memcpy(status_msg + 12, &group, sizeof(unsigned char));
450     memcpy(status_msg + 13, &action, sizeof(unsigned char));
451
452     if (on != NULL) {
453         memcpy(status_msg + 14, on, datalen);
454     }
455
456     send_injector_ntf(status_msg, msglen);
457
458     free(status_msg);
459 }
460
461 static bool injector_req_sensor(ECS_Client* ccli, ECS__InjectorReq* msg, char *cmd)
462 {
463     char data[MAX_INJECTOR_REQ_DATA];
464     type_group group;
465     type_action action;
466
467     memset(data, 0, MAX_INJECTOR_REQ_DATA);
468     group = (type_group) (msg->group & 0xff);
469     action = (type_action) (msg->action & 0xff);
470
471     if (group == MSG_GROUP_STATUS) {
472         switch (action) {
473         case MSG_ACT_BATTERY_LEVEL:
474             sprintf(data, "%d", get_power_capacity());
475             break;
476         case MSG_ACT_BATTERY_CHARGER:
477             sprintf(data, "%d", get_jack_charger());
478             break;
479         case MSG_ACT_USB:
480             sprintf(data, "%d", get_jack_usb());
481             break;
482         case MSG_ACT_EARJACK:
483             sprintf(data, "%d", get_jack_earjack());
484             break;
485         case MSG_ACT_LOCATION:
486             qemu_mutex_lock(&mutex_location_data);
487             sprintf(data, "%s", location_data);
488             qemu_mutex_unlock(&mutex_location_data);
489             break;
490         default:
491             return injector_send(ccli, msg, cmd);
492         }
493         TRACE("status : %s\n", data);
494         send_status_injector_ntf(MSG_TYPE_SENSOR, 6, action, data);
495         return true;
496     } else if (msg->data.data && msg->data.len > 0) {
497         set_injector_data((char*) msg->data.data);
498         return injector_send(ccli, msg, cmd);
499     }
500
501     return false;
502 }
503
504 static bool injector_req_guest(void)
505 {
506     int value = 0;
507     qemu_mutex_lock(&mutex_guest_connection);
508     value = guest_connection;
509     qemu_mutex_unlock(&mutex_guest_connection);
510     send_status_injector_ntf(MSG_TYPE_GUEST, 5, value, NULL);
511     return true;
512 }
513
514 static bool injector_req_location(ECS_Client* ccli, ECS__InjectorReq* msg, char *cmd)
515 {
516     if (msg->data.data != NULL && msg->data.len > 0) {
517         qemu_mutex_lock(&mutex_location_data);
518         snprintf(location_data, msg->data.len + 1, "%s", (char*)msg->data.data);
519         qemu_mutex_unlock(&mutex_location_data);
520         return injector_send(ccli, msg, cmd);
521     }
522
523     return false;
524 }
525
526 bool msgproc_injector_req(ECS_Client* ccli, ECS__InjectorReq* msg)
527 {
528     char cmd[11];
529     bool ret = false;
530
531     strncpy(cmd, msg->category, sizeof(cmd) - 1);
532
533     if (!strcmp(cmd, MSG_TYPE_SDCARD)) {
534         ret = injector_req_sdcard(ccli, msg, cmd);
535     } else if (!strcmp(cmd, MSG_TYPE_SENSOR)) {
536         ret = injector_req_sensor(ccli, msg, cmd);
537     } else if (!strcmp(cmd, MSG_TYPE_GUEST)) {
538         ret = injector_req_guest();
539     } else if (!strcmp(cmd, MSG_TYPE_LOCATION)) {
540         ret = injector_req_location(ccli, msg, cmd);
541     } else {
542         ret = injector_send(ccli, msg, cmd);
543     }
544
545     return ret;
546 }
547
548 void ecs_suspend_lock_state(int state)
549 {
550     int catlen;
551
552     ECS__InjectorReq msg = ECS__INJECTOR_REQ__INIT;
553     const char* category = "suspend";
554
555     catlen = strlen(category);
556     msg.category = (char*) g_malloc0(catlen + 1);
557     memcpy(msg.category, category, catlen);
558
559     msg.group = 5;
560     msg.action = state;
561
562     msgproc_injector_req(NULL, &msg);
563 }
564
565 #define MSG_GROUP_HDS   100
566 static bool injector_req_handle(char* cat, type_action action)
567 {
568     /*SD CARD msg process*/
569     if (!strcmp(cat, MSG_TYPE_SDCARD)) {
570         return false;
571     } else if (!strcmp(cat, "suspend")) {
572         ecs_suspend_lock_state(ecs_get_suspend_state());
573         return true;
574     } else if (!strcmp(cat, "boot")) {
575         LOG_INFO("emulator booting done.\n");
576         set_emulator_condition(BOOT_COMPLETED);
577         return true;
578     } else if (!strcmp(cat, MSG_TYPE_GUEST)) {
579         INFO("emuld connection is %d\n", action);
580         qemu_mutex_lock(&mutex_guest_connection);
581         guest_connection = action;
582         if (action == 1) {
583             set_emulator_condition(BOOT_COMPLETED);
584         } else {
585             set_emulator_condition(RESET);
586         }
587         qemu_mutex_unlock(&mutex_guest_connection);
588         return false;
589     } else if (!strcmp(cat, "hds")) {
590         INFO("hds status is %d\n", action);
591         switch (action) {
592             case 1:
593                 make_send_device_ntf(cat, MSG_GROUP_HDS, action, NULL);
594                 break;
595             case 2:
596                 do_hotplug(DETACH_HDS, NULL, 0);
597                 make_send_device_ntf(cat, MSG_GROUP_HDS, action, NULL);
598                 break;
599             case 3:
600                 do_hotplug(DETACH_HDS, NULL, 0);
601                 make_send_device_ntf(cat, MSG_GROUP_HDS, action, NULL);
602                 break;
603             case 4:
604                 make_send_device_ntf(cat, MSG_GROUP_HDS, action, NULL);
605                 break;
606             default:
607                 ERR("unknown action: %s.\n", action);
608                 break;
609         }
610         return true;
611     }
612
613     return false;
614 }
615
616 bool send_injector_ntf(const char* data, const int len)
617 {
618     type_length length = 0;
619     type_group group = 0;
620     type_action action = 0;
621
622     const int catsize = 10;
623     char cat[catsize + 1];
624     memset(cat, 0, catsize + 1);
625
626     read_val_str(data, cat, catsize);
627     read_val_short(data + catsize, &length);
628     read_val_char(data + catsize + 2, &group);
629     read_val_char(data + catsize + 2 + 1, &action);
630
631     if (injector_req_handle(cat, action)) {
632         return true;
633     }
634
635     const char* ijdata = (data + catsize + 2 + 1 + 1);
636
637     TRACE("<< header cat = %s, length = %d, action=%d, group=%d\n", cat, length,action, group);
638
639     ECS__Master master = ECS__MASTER__INIT;
640     ECS__InjectorNtf ntf = ECS__INJECTOR_NTF__INIT;
641
642     ntf.category = (char*) g_malloc(catsize + 1);
643     strncpy(ntf.category, cat, 10);
644
645     ntf.length = length;
646     ntf.group = group;
647     ntf.action = action;
648
649     if (length > 0)
650     {
651         ntf.has_data = 1;
652
653         ntf.data.data = g_malloc(length);
654         ntf.data.len = length;
655         memcpy(ntf.data.data, ijdata, length);
656     }
657
658     master.type = ECS__MASTER__TYPE__INJECTOR_NTF;
659     master.injector_ntf = &ntf;
660
661     pb_to_all_clients(&master);
662
663     if (ntf.data.len > 0)
664     {
665         g_free(ntf.data.data);
666     }
667
668     g_free(ntf.category);
669
670     return true;
671 }
672