update source for tizen_2.1
[sdk/emulator/qemu.git] / tizen / src / skin / maruskin_operation.c
1 /*
2  * operation for emulator skin
3  *
4  * Copyright (C) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact:
7  * GiWoong Kim <giwoong.kim@samsung.com>
8  * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
9  * HyunJun Son
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
31 #include "maru_common.h"
32
33 #include <unistd.h>
34 #include <stdio.h>
35 #include <pthread.h>
36 #include "maruskin_operation.h"
37 #include "hw/maru_brightness.h"
38 #include "maru_display.h"
39 #include "emulator.h"
40 #include "debug_ch.h"
41 #include "sdb.h"
42 #include "nbd.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"
49 #include "sysemu.h"
50 #include "sysbus.h"
51
52 #ifdef CONFIG_HAX
53 #include "guest_debug.h"
54
55 #include "target-i386/hax-i386.h"
56 #endif
57
58 #if defined(CONFIG_USE_SHM) && defined(TARGET_I386)
59 #include <sys/shm.h>
60 int g_shmid;
61 #endif
62
63 MULTI_DEBUG_CHANNEL(qemu, skin_operation);
64
65
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 */
70
71 static int requested_shutdown_qemu_gracefully = 0;
72
73 /* touch values */
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;
77
78 extern pthread_mutex_t mutex_screenshot;
79 extern pthread_cond_t cond_screenshot;
80
81 extern int tizen_base_port;
82
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);
86
87
88 void start_display(uint64 handle_id,
89     int lcd_size_width, int lcd_size_height,
90     double scale_factor, short rotation_type)
91 {
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);
94
95     set_emul_win_scale(scale_factor);
96     maruskin_init(handle_id, lcd_size_width, lcd_size_height, false);
97 }
98
99 void do_mouse_event(int button_type, int event_type,
100     int origin_x, int origin_y, int x, int y, int z)
101 {
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);
105         return;
106     }
107
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);
110
111 #ifndef CONFIG_USE_SHM
112     /* multi-touch */
113     if (get_emul_multi_touch_state()->multitouch_enable == 1) {
114         maru_finger_processing_1(event_type, origin_x, origin_y, x, y);
115         return;
116     } else if (get_emul_multi_touch_state()->multitouch_enable == 2) {
117         maru_finger_processing_2(event_type, origin_x, origin_y, x, y);
118         return;
119     }
120 #endif
121
122     /* single touch */
123     switch(event_type) {
124         case MOUSE_DOWN:
125         case MOUSE_DRAG:
126             pressing_x = guest_x = x;
127             pressing_y = guest_y = y;
128             pressing_origin_x = origin_x;
129             pressing_origin_y = origin_y;
130
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);
134             break;
135         case MOUSE_UP:
136             guest_x = x;
137             guest_y = y;
138             pressing_x = pressing_y = -1;
139             pressing_origin_x = pressing_origin_y = -1;
140
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);
144             break;
145         case MOUSE_WHEELUP:
146         case MOUSE_WHEELDOWN:
147             x -= guest_x;
148             y -= guest_y;
149             guest_x += x;
150             guest_y += y;
151
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);
155             break;
156         default:
157             ERR("undefined mouse event type passed:%d\n", event_type);
158             break;
159     }
160
161 #if 0
162 #ifdef CONFIG_WIN32
163     Sleep(1);
164 #else
165     usleep(1000);
166 #endif
167 #endif
168 }
169
170 void do_key_event(int event_type, int keycode, int state_mask, int key_location)
171 {
172     int scancode = -1;
173
174     TRACE("key_event event_type:%d, keycode:%d, state_mask:%d, key_location:%d\n",
175         event_type, keycode, state_mask, key_location);
176
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;
181
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))
186         {
187             if (KEY_PRESSED == event_type) {
188                 get_emul_multi_touch_state()->multitouch_enable = 2;
189
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) {
194                     add_finger_point(
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;
199                 }
200
201                 INFO("enable multi-touch = mode2\n");
202             }
203         }
204         else if (keycode == JAVA_KEYCODE_BIT_CTRL ||
205             keycode == JAVA_KEYCODE_BIT_SHIFT)
206         {
207             if (KEY_PRESSED == event_type) {
208                 get_emul_multi_touch_state()->multitouch_enable = 1;
209
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) {
214                     add_finger_point(
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;
219                 }
220
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");
226                 } else {
227                     get_emul_multi_touch_state()->multitouch_enable = 0;
228                     clear_finger_slot();
229                     INFO("disable multi-touch\n");
230                 }
231             }
232         }
233
234     }
235 #endif
236
237 #if defined(TARGET_I386)
238     if (!mloop_evcmd_get_hostkbd_status()) {
239         TRACE("ignore keyboard input because usb keyboard is dettached.\n");
240         return;
241     }
242 #endif
243
244 #if defined(TARGET_ARM)
245     if (!mloop_evcmd_get_usbkbd_status()) {
246         TRACE("ignore keyboard input because usb keyboard is dettached.\n");
247         return;
248     }
249 #endif
250
251     scancode = javakeycode_to_scancode(event_type, keycode, state_mask, key_location);
252
253     if (scancode == -1) {
254         INFO("cannot find scancode\n");
255         return;
256     }
257
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);
264     }
265 }
266
267 void do_hardkey_event(int event_type, int keycode)
268 {
269     INFO("do_hardkey_event event_type:%d, keycode:%d\n",
270         event_type, keycode);
271
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" );
278                     resume();
279 #ifdef CONFIG_WIN32
280                     Sleep( RESUME_KEY_SEND_INTERVAL );
281 #else
282                     usleep( RESUME_KEY_SEND_INTERVAL * 1000 );
283 #endif
284                 }
285             }
286         }
287     }
288
289     maru_hwkey_event(event_type, keycode);
290 }
291
292 void do_scale_event(double scale_factor)
293 {
294     INFO("do_scale_event scale_factor:%lf\n", scale_factor);
295
296     set_emul_win_scale(scale_factor);
297
298 #if 0
299     //TODO: thread safe
300     //qemu refresh
301     vga_hw_invalidate();
302     vga_hw_update();
303 #endif
304 }
305
306 void do_rotation_event(int rotation_type)
307 {
308
309     INFO( "do_rotation_event rotation_type:%d\n", rotation_type);
310
311     char send_buf[32] = { 0 };
312
313     switch ( rotation_type ) {
314         case ROTATION_PORTRAIT:
315             sprintf( send_buf, "1\n3\n0\n9.80665\n0\n" );
316             break;
317         case ROTATION_LANDSCAPE:
318             sprintf( send_buf, "1\n3\n9.80665\n0\n0\n" );
319             break;
320         case ROTATION_REVERSE_PORTRAIT:
321             sprintf( send_buf, "1\n3\n0\n-9.80665\n0\n" );
322             break;
323         case ROTATION_REVERSE_LANDSCAPE:
324             sprintf(send_buf, "1\n3\n-9.80665\n0\n0\n");
325             break;
326
327         default:
328             break;
329     }
330
331     send_to_emuld( "sensor\n\n\n\n", 10, send_buf, 32 );
332
333     set_emul_rotation( rotation_type );
334
335 }
336
337 QemuSurfaceInfo* get_screenshot_info(void)
338 {
339     DisplaySurface* qemu_display_surface = get_qemu_display_surface();
340
341     if ( !qemu_display_surface ) {
342         ERR( "qemu surface is NULL.\n" );
343         return NULL;
344     }
345
346     QemuSurfaceInfo* info = (QemuSurfaceInfo*) g_malloc0( sizeof(QemuSurfaceInfo) );
347     if ( !info ) {
348         ERR( "Fail to malloc for QemuSurfaceInfo.\n");
349         return NULL;
350     }
351
352     int length = qemu_display_surface->linesize * qemu_display_surface->height;
353     INFO( "screenshot data length:%d\n", length );
354
355     if ( 0 >= length ) {
356         g_free( info );
357         ERR( "screenshot data ( 0 >=length ). length:%d\n", length );
358         return NULL;
359     }
360
361     info->pixel_data = (unsigned char*) g_malloc0( length );
362     if ( !info->pixel_data ) {
363         g_free( info );
364         ERR("Fail to malloc for pixel data.\n");
365         return NULL;
366     }
367
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;
372         return info;
373     }
374
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);
380     } else {
381         maru_screenshot->pixel_data = info->pixel_data;
382         maru_screenshot->request_screenshot = 1;
383         pthread_cond_wait(&cond_screenshot, &mutex_screenshot);
384     }
385     pthread_mutex_unlock(&mutex_screenshot);
386
387     info->pixel_data_length = length;
388
389     return info;
390 }
391
392 void free_screenshot_info(QemuSurfaceInfo* info)
393 {
394     if (info) {
395         if(info->pixel_data) {
396             g_free(info->pixel_data);
397         }
398
399         g_free(info);
400     }
401 }
402
403 DetailInfo* get_detail_info(int qemu_argc, char** qemu_argv)
404 {
405     DetailInfo* detail_info = g_malloc0( sizeof(DetailInfo) );
406     if ( !detail_info ) {
407         ERR( "Fail to malloc for DetailInfo.\n" );
408         return NULL;
409     }
410
411     int i = 0;
412     int total_len = 0;
413     int delimiter_len = strlen( DATA_DELIMITER );
414
415     /* collect QEMU information */
416     for ( i = 0; i < qemu_argc; i++ ) {
417         total_len += strlen( qemu_argv[i] );
418         total_len += delimiter_len;
419     }
420
421 #ifdef CONFIG_WIN32
422     /* collect HAXM information */
423     const int HAX_LEN = 32;
424     char hax_error[HAX_LEN];
425     memset( hax_error, 0, HAX_LEN );
426
427     int hax_err_len = 0;
428     hax_err_len = sprintf( hax_error + hax_err_len, "%s", "hax_error=" );
429
430     int error = 0;
431     if ( !ret_hax_init ) {
432         if ( -ENOSPC == ret_hax_init ) {
433             error = 1;
434         }
435     }
436     hax_err_len += sprintf( hax_error + hax_err_len, "%s#", error ? "true" : "false" );
437     total_len += (hax_err_len + 1);
438 #endif
439
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);
445
446     /* memory allocation */
447     char* info_data = g_malloc0( total_len + 1 );
448     if ( !info_data ) {
449         g_free( detail_info );
450         ERR( "Fail to malloc for info data.\n" );
451         return NULL;
452     }
453
454
455     /* write informations */
456     int len = 0;
457     total_len = 0; //recycle
458
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;
463     }
464
465 #ifdef CONFIG_WIN32
466     snprintf( info_data + total_len, hax_err_len + 1, "%s#", hax_error );
467     total_len += hax_err_len;
468 #endif
469
470     snprintf( info_data + total_len, log_path_len + 1, "%s%s#", LOGPATH_TEXT, log_path );
471     total_len += log_path_len;
472
473     INFO( "################## detail info data ####################\n" );
474     INFO( "%s\n", info_data );
475
476     detail_info->data = info_data;
477     detail_info->data_length = total_len;
478
479     return detail_info;
480 }
481
482 void free_detail_info(DetailInfo* detail_info)
483 {
484     if (detail_info) {
485         if (detail_info->data) {
486             g_free(detail_info->data);
487         }
488
489         g_free(detail_info);
490     }
491 }
492
493 void do_open_shell(void)
494 {
495     INFO("open shell\n");
496
497     /* do nothing */
498 }
499
500 void onoff_host_kbd(int on)
501 {
502     INFO("host kbd on/off: %d.\n", on);
503
504 #if defined(TARGET_ARM)
505     mloop_evcmd_usbkbd(on);
506 #elif defined(TARGET_I386)
507     mloop_evcmd_hostkbd(on);
508 #endif
509 }
510
511 void do_ram_dump(void)
512 {
513     INFO("dump ram!\n");
514
515     mloop_evcmd_ramdump();
516 }
517
518 void do_guestmemory_dump(void)
519 {
520     INFO("dump guest memory!\n");
521
522     /* TODO: */
523 }
524
525 void request_close(void)
526 {
527     INFO("request_close\n");
528
529     /* FIXME: convert to device emulatoion */
530     do_hardkey_event(KEY_PRESSED, HARD_KEY_POWER);
531
532 #ifdef CONFIG_WIN32
533         Sleep(CLOSE_POWER_KEY_INTERVAL);
534 #else
535         usleep(CLOSE_POWER_KEY_INTERVAL * 1000);
536 #endif
537
538     do_hardkey_event(KEY_RELEASED, HARD_KEY_POWER);
539
540 }
541
542 void shutdown_qemu_gracefully(void)
543 {
544     requested_shutdown_qemu_gracefully = 1;
545
546     pthread_t thread_id;
547     if (0 > pthread_create(
548         &thread_id, NULL, run_timed_shutdown_thread, NULL)) {
549
550         ERR("!!! Fail to create run_timed_shutdown_thread. shutdown qemu right now !!!\n");
551         qemu_system_shutdown_request();
552     }
553
554 }
555
556 int is_requested_shutdown_qemu_gracefully(void)
557 {
558     return requested_shutdown_qemu_gracefully;
559 }
560
561 static void* run_timed_shutdown_thread(void* args)
562 {
563     send_to_emuld("system\n\n\n\n", 10, "shutdown", 8);
564
565     int sleep_interval_time = 1000; /* milli-seconds */
566
567     int i;
568     for (i = 0; i < TIMEOUT_FOR_SHUTDOWN; i++) {
569 #ifdef CONFIG_WIN32
570         Sleep(sleep_interval_time);
571 #else
572         usleep(sleep_interval_time * 1000);
573 #endif
574         /* do not use logger to help user see log in console */
575         fprintf(stdout, "Wait for shutdown qemu...%d\n", (i + 1));
576     }
577
578     INFO("Shutdown qemu !!!\n");
579
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: ");
584     }
585 #endif
586
587     qemu_system_shutdown_request();
588
589     return NULL;
590
591 }
592
593 static void send_to_emuld(const char* request_type,
594     int request_size, const char* send_buf, int buf_size)
595 {
596     int s = tcp_socket_outgoing( "127.0.0.1", (uint16_t) ( tizen_base_port + SDB_TCP_EMULD_INDEX ) );
597
598     if ( s < 0 ) {
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) );
601         return;
602     }
603
604     if(send( s, (char*)request_type, request_size, 0 ) < 0) {
605         ERR("failed to send to emuld\n");
606     }
607     if(send( s, &buf_size, 4, 0 ) < 0) {
608         ERR("failed to send to emuld\n");
609     }
610     if(send( s, (char*)send_buf, buf_size, 0 ) < 0) {
611         ERR("failed to send to emuld\n");
612     }
613
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 );
616
617 #ifdef CONFIG_WIN32
618     closesocket( s );
619 #else
620     close( s );
621 #endif
622
623 }