2 * operation for emulator skin
4 * Copyright (C) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
7 * GiWoong Kim <giwoong.kim@samsung.com>
8 * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
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.
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.
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.
31 #include "maru_common.h"
36 #include "maruskin_operation.h"
37 #include "hw/maru_brightness.h"
38 #include "maru_display.h"
43 #include "mloop_event.h"
44 #include "emul_state.h"
45 #include "maruskin_keymap.h"
46 #include "maruskin_server.h"
47 #include "emul_state.h"
48 #include "hw/maru_pm.h"
53 #include "guest_debug.h"
55 #include "target-i386/hax-i386.h"
58 #if defined(CONFIG_USE_SHM) && defined(TARGET_I386)
63 MULTI_DEBUG_CHANNEL(qemu, skin_operation);
66 #define RESUME_KEY_SEND_INTERVAL 500 /* milli-seconds */
67 #define CLOSE_POWER_KEY_INTERVAL 1200 /* milli-seconds */
68 #define DATA_DELIMITER "#" /* in detail info data */
69 #define TIMEOUT_FOR_SHUTDOWN 10 /* seconds */
71 static int requested_shutdown_qemu_gracefully = 0;
74 static int guest_x, guest_y;
75 static int pressing_x = -1, pressing_y = -1;
76 static int pressing_origin_x = -1, pressing_origin_y = -1;
78 extern pthread_mutex_t mutex_screenshot;
79 extern pthread_cond_t cond_screenshot;
81 extern int tizen_base_port;
83 static void* run_timed_shutdown_thread(void* args);
84 static void send_to_emuld(const char* request_type,
85 int request_size, const char* send_buf, int buf_size);
88 void start_display(uint64 handle_id,
89 int lcd_size_width, int lcd_size_height,
90 double scale_factor, short rotation_type)
92 INFO("start_display handle_id:%ld, lcd size:%dx%d, scale_factor:%f, rotation_type:%d\n",
93 (long)handle_id, lcd_size_width, lcd_size_height, scale_factor, rotation_type);
95 set_emul_win_scale(scale_factor);
96 maruskin_init(handle_id, lcd_size_width, lcd_size_height, false);
99 void do_mouse_event(int button_type, int event_type,
100 int origin_x, int origin_y, int x, int y, int z)
102 if (brightness_off) {
103 TRACE("reject mouse touch in lcd off = button:%d, type:%d, x:%d, y:%d, z:%d\n",
104 button_type, event_type, x, y, z);
108 TRACE("mouse_event button:%d, type:%d, host:(%d, %d), x:%d, y:%d, z:%d\n",
109 button_type, event_type, origin_x, origin_y, x, y, z);
111 #ifndef CONFIG_USE_SHM
113 if (get_emul_multi_touch_state()->multitouch_enable == 1) {
114 maru_finger_processing_1(event_type, origin_x, origin_y, x, y);
116 } else if (get_emul_multi_touch_state()->multitouch_enable == 2) {
117 maru_finger_processing_2(event_type, origin_x, origin_y, x, y);
126 pressing_x = guest_x = x;
127 pressing_y = guest_y = y;
128 pressing_origin_x = origin_x;
129 pressing_origin_y = origin_y;
131 kbd_mouse_event(x, y, z, 1);
132 TRACE("mouse_event event_type:%d, origin:(%d, %d), x:%d, y:%d, z:%d\n\n",
133 event_type, origin_x, origin_y, x, y, z);
138 pressing_x = pressing_y = -1;
139 pressing_origin_x = pressing_origin_y = -1;
141 kbd_mouse_event(x, y, z, 0);
142 TRACE("mouse_event event_type:%d, origin:(%d, %d), x:%d, y:%d, z:%d\n\n",
143 event_type, origin_x, origin_y, x, y, z);
146 case MOUSE_WHEELDOWN:
152 kbd_mouse_event(x, y, -z, event_type);
153 TRACE("mouse_event event_type:%d, origin:(%d, %d), x:%d, y:%d, z:%d\n\n",
154 event_type, origin_x, origin_y, x, y, z);
157 ERR("undefined mouse event type passed:%d\n", event_type);
170 void do_key_event(int event_type, int keycode, int state_mask, int key_location)
174 TRACE("key_event event_type:%d, keycode:%d, state_mask:%d, key_location:%d\n",
175 event_type, keycode, state_mask, key_location);
177 #ifndef CONFIG_USE_SHM
178 //is multi-touch mode ?
179 if (get_emul_max_touch_point() > 1) {
180 int state_mask_temp = state_mask & ~JAVA_KEYCODE_NO_FOCUS;
182 if ((keycode == JAVA_KEYCODE_BIT_SHIFT &&
183 state_mask_temp == JAVA_KEYCODE_BIT_CTRL) ||
184 (keycode == JAVA_KEYCODE_BIT_CTRL &&
185 state_mask_temp == JAVA_KEYCODE_BIT_SHIFT))
187 if (KEY_PRESSED == event_type) {
188 get_emul_multi_touch_state()->multitouch_enable = 2;
190 /* add a finger before start the multi-touch processing
191 if already exist the pressed touch in display */
192 if (pressing_x != -1 && pressing_y != -1 &&
193 pressing_origin_x != -1 && pressing_origin_y != -1) {
195 pressing_origin_x, pressing_origin_y,
196 pressing_x, pressing_y);
197 pressing_x = pressing_y = -1;
198 pressing_origin_x = pressing_origin_y = -1;
201 INFO("enable multi-touch = mode2\n");
204 else if (keycode == JAVA_KEYCODE_BIT_CTRL ||
205 keycode == JAVA_KEYCODE_BIT_SHIFT)
207 if (KEY_PRESSED == event_type) {
208 get_emul_multi_touch_state()->multitouch_enable = 1;
210 /* add a finger before start the multi-touch processing
211 if already exist the pressed touch in display */
212 if (pressing_x != -1 && pressing_y != -1 &&
213 pressing_origin_x != -1 && pressing_origin_y != -1) {
215 pressing_origin_x, pressing_origin_y,
216 pressing_x, pressing_y);
217 pressing_x = pressing_y = -1;
218 pressing_origin_x = pressing_origin_y = -1;
221 INFO("enable multi-touch = mode1\n");
222 } else if (KEY_RELEASED == event_type) {
223 if (state_mask_temp == (JAVA_KEYCODE_BIT_CTRL | JAVA_KEYCODE_BIT_SHIFT)) {
224 get_emul_multi_touch_state()->multitouch_enable = 1;
225 INFO("enabled multi-touch = mode1\'\n");
227 get_emul_multi_touch_state()->multitouch_enable = 0;
229 INFO("disable multi-touch\n");
237 #if defined(TARGET_I386)
238 if (!mloop_evcmd_get_hostkbd_status()) {
239 TRACE("ignore keyboard input because usb keyboard is dettached.\n");
244 #if defined(TARGET_ARM)
245 if (!mloop_evcmd_get_usbkbd_status()) {
246 TRACE("ignore keyboard input because usb keyboard is dettached.\n");
251 scancode = javakeycode_to_scancode(event_type, keycode, state_mask, key_location);
253 if (scancode == -1) {
254 INFO("cannot find scancode\n");
258 if (KEY_PRESSED == event_type) {
259 TRACE("key pressed: %d\n", scancode);
260 kbd_put_keycode(scancode);
261 } else if (KEY_RELEASED == event_type) {
262 TRACE("key released: %d\n", scancode);
263 kbd_put_keycode(scancode | 0x80);
267 void do_hardkey_event(int event_type, int keycode)
269 INFO("do_hardkey_event event_type:%d, keycode:%d\n",
270 event_type, keycode);
272 if ( is_suspended_state() ) {
273 if ( KEY_PRESSED == event_type ) {
274 if ( kbd_mouse_is_absolute() ) {
275 // home key or power key is used for resume.
276 if ( ( HARD_KEY_HOME == keycode ) || ( HARD_KEY_POWER == keycode ) ) {
277 INFO( "user requests system resume.\n" );
280 Sleep( RESUME_KEY_SEND_INTERVAL );
282 usleep( RESUME_KEY_SEND_INTERVAL * 1000 );
289 maru_hwkey_event(event_type, keycode);
292 void do_scale_event(double scale_factor)
294 INFO("do_scale_event scale_factor:%lf\n", scale_factor);
296 set_emul_win_scale(scale_factor);
306 void do_rotation_event(int rotation_type)
309 INFO( "do_rotation_event rotation_type:%d\n", rotation_type);
311 char send_buf[32] = { 0 };
313 switch ( rotation_type ) {
314 case ROTATION_PORTRAIT:
315 sprintf( send_buf, "1\n3\n0\n9.80665\n0\n" );
317 case ROTATION_LANDSCAPE:
318 sprintf( send_buf, "1\n3\n9.80665\n0\n0\n" );
320 case ROTATION_REVERSE_PORTRAIT:
321 sprintf( send_buf, "1\n3\n0\n-9.80665\n0\n" );
323 case ROTATION_REVERSE_LANDSCAPE:
324 sprintf(send_buf, "1\n3\n-9.80665\n0\n0\n");
331 send_to_emuld( "sensor\n\n\n\n", 10, send_buf, 32 );
333 set_emul_rotation( rotation_type );
337 QemuSurfaceInfo* get_screenshot_info(void)
339 DisplaySurface* qemu_display_surface = get_qemu_display_surface();
341 if ( !qemu_display_surface ) {
342 ERR( "qemu surface is NULL.\n" );
346 QemuSurfaceInfo* info = (QemuSurfaceInfo*) g_malloc0( sizeof(QemuSurfaceInfo) );
348 ERR( "Fail to malloc for QemuSurfaceInfo.\n");
352 int length = qemu_display_surface->linesize * qemu_display_surface->height;
353 INFO( "screenshot data length:%d\n", length );
357 ERR( "screenshot data ( 0 >=length ). length:%d\n", length );
361 info->pixel_data = (unsigned char*) g_malloc0( length );
362 if ( !info->pixel_data ) {
364 ERR("Fail to malloc for pixel data.\n");
368 /* If the LCD is turned off, return empty buffer.
369 Because the empty buffer is seen as a black. */
370 if (brightness_off) {
371 info->pixel_data_length = length;
375 pthread_mutex_lock(&mutex_screenshot);
376 MaruScreenshot* maru_screenshot = get_maru_screenshot();
377 if (!maru_screenshot || maru_screenshot->isReady != 1) {
378 ERR("maru screenshot is NULL or not ready.\n");
379 memset(info->pixel_data, 0x00, length);
381 maru_screenshot->pixel_data = info->pixel_data;
382 maru_screenshot->request_screenshot = 1;
383 pthread_cond_wait(&cond_screenshot, &mutex_screenshot);
385 pthread_mutex_unlock(&mutex_screenshot);
387 info->pixel_data_length = length;
392 void free_screenshot_info(QemuSurfaceInfo* info)
395 if(info->pixel_data) {
396 g_free(info->pixel_data);
403 DetailInfo* get_detail_info(int qemu_argc, char** qemu_argv)
405 DetailInfo* detail_info = g_malloc0( sizeof(DetailInfo) );
406 if ( !detail_info ) {
407 ERR( "Fail to malloc for DetailInfo.\n" );
413 int delimiter_len = strlen( DATA_DELIMITER );
415 /* collect QEMU information */
416 for ( i = 0; i < qemu_argc; i++ ) {
417 total_len += strlen( qemu_argv[i] );
418 total_len += delimiter_len;
422 /* collect HAXM information */
423 const int HAX_LEN = 32;
424 char hax_error[HAX_LEN];
425 memset( hax_error, 0, HAX_LEN );
428 hax_err_len = sprintf( hax_error + hax_err_len, "%s", "hax_error=" );
431 if ( !ret_hax_init ) {
432 if ( -ENOSPC == ret_hax_init ) {
436 hax_err_len += sprintf( hax_error + hax_err_len, "%s#", error ? "true" : "false" );
437 total_len += (hax_err_len + 1);
440 /* collect log path information */
441 #define LOGPATH_TEXT "log_path="
442 const char* log_path = get_log_path();
443 int log_path_len = strlen(LOGPATH_TEXT) + strlen(log_path) + delimiter_len;
444 total_len += (log_path_len + 1);
446 /* memory allocation */
447 char* info_data = g_malloc0( total_len + 1 );
449 g_free( detail_info );
450 ERR( "Fail to malloc for info data.\n" );
455 /* write informations */
457 total_len = 0; //recycle
459 for ( i = 0; i < qemu_argc; i++ ) {
460 len = strlen( qemu_argv[i] );
461 sprintf( info_data + total_len, "%s%s", qemu_argv[i], DATA_DELIMITER );
462 total_len += len + delimiter_len;
466 snprintf( info_data + total_len, hax_err_len + 1, "%s#", hax_error );
467 total_len += hax_err_len;
470 snprintf( info_data + total_len, log_path_len + 1, "%s%s#", LOGPATH_TEXT, log_path );
471 total_len += log_path_len;
473 INFO( "################## detail info data ####################\n" );
474 INFO( "%s\n", info_data );
476 detail_info->data = info_data;
477 detail_info->data_length = total_len;
482 void free_detail_info(DetailInfo* detail_info)
485 if (detail_info->data) {
486 g_free(detail_info->data);
493 void do_open_shell(void)
495 INFO("open shell\n");
500 void onoff_host_kbd(int on)
502 INFO("host kbd on/off: %d.\n", on);
504 #if defined(TARGET_ARM)
505 mloop_evcmd_usbkbd(on);
506 #elif defined(TARGET_I386)
507 mloop_evcmd_hostkbd(on);
511 void do_ram_dump(void)
515 mloop_evcmd_ramdump();
518 void do_guestmemory_dump(void)
520 INFO("dump guest memory!\n");
525 void request_close(void)
527 INFO("request_close\n");
529 /* FIXME: convert to device emulatoion */
530 do_hardkey_event(KEY_PRESSED, HARD_KEY_POWER);
533 Sleep(CLOSE_POWER_KEY_INTERVAL);
535 usleep(CLOSE_POWER_KEY_INTERVAL * 1000);
538 do_hardkey_event(KEY_RELEASED, HARD_KEY_POWER);
542 void shutdown_qemu_gracefully(void)
544 requested_shutdown_qemu_gracefully = 1;
547 if (0 > pthread_create(
548 &thread_id, NULL, run_timed_shutdown_thread, NULL)) {
550 ERR("!!! Fail to create run_timed_shutdown_thread. shutdown qemu right now !!!\n");
551 qemu_system_shutdown_request();
556 int is_requested_shutdown_qemu_gracefully(void)
558 return requested_shutdown_qemu_gracefully;
561 static void* run_timed_shutdown_thread(void* args)
563 send_to_emuld("system\n\n\n\n", 10, "shutdown", 8);
565 int sleep_interval_time = 1000; /* milli-seconds */
568 for (i = 0; i < TIMEOUT_FOR_SHUTDOWN; i++) {
570 Sleep(sleep_interval_time);
572 usleep(sleep_interval_time * 1000);
574 /* do not use logger to help user see log in console */
575 fprintf(stdout, "Wait for shutdown qemu...%d\n", (i + 1));
578 INFO("Shutdown qemu !!!\n");
580 #if defined(CONFIG_USE_SHM) && defined(TARGET_I386)
581 if (shmctl(g_shmid, IPC_RMID, 0) == -1) {
582 ERR("shmctl failed\n");
583 perror("maruskin_operation.c:g_shmid: ");
587 qemu_system_shutdown_request();
593 static void send_to_emuld(const char* request_type,
594 int request_size, const char* send_buf, int buf_size)
596 int s = tcp_socket_outgoing( "127.0.0.1", (uint16_t) ( tizen_base_port + SDB_TCP_EMULD_INDEX ) );
599 ERR( "can't create socket to talk to the sdb forwarding session \n" );
600 ERR( "[127.0.0.1:%d/tcp] connect fail (%d:%s)\n" , tizen_base_port + SDB_TCP_EMULD_INDEX , errno, strerror(errno) );
604 if(send( s, (char*)request_type, request_size, 0 ) < 0) {
605 ERR("failed to send to emuld\n");
607 if(send( s, &buf_size, 4, 0 ) < 0) {
608 ERR("failed to send to emuld\n");
610 if(send( s, (char*)send_buf, buf_size, 0 ) < 0) {
611 ERR("failed to send to emuld\n");
614 INFO( "send to emuld [req_type:%s, send_data:%s, send_size:%d] 127.0.0.1:%d/tcp \n",
615 request_type, send_buf, buf_size, tizen_base_port + SDB_TCP_EMULD_INDEX );