ce4cf993d18b87c45582917f94c1dd4739bc1536
[sdk/emulator/qemu.git] / tizen / src / skin / maruskin_operation.c
1 /*
2  * operation for emulator skin
3  *
4  * Copyright (C) 2011 - 2012 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 "debug_ch.h"
40 #include "sdb.h"
41 #include "nbd.h"
42 #include "mloop_event.h"
43 #include "emul_state.h"
44 #include "maruskin_keymap.h"
45 #include "maruskin_server.h"
46 #include "emul_state.h"
47 #include "hw/maru_pm.h"
48 #include "sysemu.h"
49 #include "sysbus.h"
50
51 #ifdef CONFIG_HAX
52 #include "guest_debug.h"
53
54 #include "target-i386/hax-i386.h"
55 #endif
56
57 MULTI_DEBUG_CHANNEL(qemu, skin_operation);
58
59 #define RESUME_KEY_SEND_INTERVAL 500 // milli-seconds
60 #define CLOSE_POWER_KEY_INTERVAL 1200 // milli-seconds
61 #define DATA_DELIMITER "#" // in detail info data
62 #define TIMEOUT_FOR_SHUTDOWN 10 // seconds
63
64 static int requested_shutdown_qemu_gracefully = 0;
65
66 /* touch values */
67 static int guest_x, guest_y;
68 static int pressing_x = -1, pressing_y = -1;
69 static int pressing_origin_x = -1, pressing_origin_y = -1;
70
71 extern pthread_mutex_t mutex_screenshot;
72 extern pthread_cond_t cond_screenshot;
73
74 static void* run_timed_shutdown_thread(void* args);
75 static void send_to_emuld(const char* request_type, int request_size, const char* send_buf, int buf_size);
76
77 void start_display(uint64 handle_id, int lcd_size_width, int lcd_size_height, double scale_factor, short rotation_type)
78 {
79     INFO("start_display handle_id:%ld, lcd size:%dx%d, scale_factor:%f, rotation_type:%d\n",
80         (long)handle_id, lcd_size_width, lcd_size_height, scale_factor, rotation_type);
81
82     set_emul_win_scale(scale_factor);
83     maruskin_init(handle_id, lcd_size_width, lcd_size_height, false);
84 }
85
86 void do_mouse_event(int button_type, int event_type,
87     int origin_x, int origin_y, int x, int y, int z)
88 {
89     if (brightness_off) {
90         TRACE("reject mouse touch in lcd off = button:%d, type:%d, x:%d, y:%d, z:%d\n",
91             button_type, event_type, x, y, z);
92         return;
93     }
94
95     TRACE("mouse_event button:%d, type:%d, host:(%d, %d), x:%d, y:%d, z:%d\n",
96         button_type, event_type, origin_x, origin_y, x, y, z);
97
98 #ifndef CONFIG_USE_SHM
99     /* multi-touch */
100     if (get_emul_multi_touch_state()->multitouch_enable == 1) {
101         maru_finger_processing_1(event_type, origin_x, origin_y, x, y);
102         return;
103     } else if (get_emul_multi_touch_state()->multitouch_enable == 2) {
104         maru_finger_processing_2(event_type, origin_x, origin_y, x, y);
105         return;
106     }
107 #endif
108
109     /* single touch */
110     switch(event_type) {
111         case MOUSE_DOWN:
112         case MOUSE_DRAG:
113             pressing_x = guest_x = x;
114             pressing_y = guest_y = y;
115             pressing_origin_x = origin_x;
116             pressing_origin_y = origin_y;
117
118             kbd_mouse_event(x, y, z, 1);
119             TRACE("mouse_event event_type:%d, origin:(%d, %d), x:%d, y:%d, z:%d\n\n",
120             event_type, origin_x, origin_y, x, y, z);
121             break;
122         case MOUSE_UP:
123             guest_x = x;
124             guest_y = y;
125             pressing_x = pressing_y = -1;
126             pressing_origin_x = pressing_origin_y = -1;
127
128             kbd_mouse_event(x, y, z, 0);
129             TRACE("mouse_event event_type:%d, origin:(%d, %d), x:%d, y:%d, z:%d\n\n",
130             event_type, origin_x, origin_y, x, y, z);
131             break;
132         case MOUSE_WHEELUP:
133         case MOUSE_WHEELDOWN:
134             x -= guest_x;
135             y -= guest_y;
136             guest_x += x;
137             guest_y += y;
138
139             kbd_mouse_event(x, y, -z, event_type);
140             TRACE("mouse_event event_type:%d, origin:(%d, %d), x:%d, y:%d, z:%d\n\n",
141             event_type, origin_x, origin_y, x, y, z);
142             break;
143         default:
144             ERR("undefined mouse event type passed:%d\n", event_type);
145             break;
146     }
147
148 #if 0
149 #ifdef CONFIG_WIN32
150     Sleep(1);
151 #else
152     usleep(1000);
153 #endif
154 #endif
155 }
156
157 void do_key_event(int event_type, int keycode, int state_mask, int key_location)
158 {
159     int scancode = -1;
160
161     TRACE("key_event event_type:%d, keycode:%d, state_mask:%d, key_location:%d\n",
162         event_type, keycode, state_mask, key_location);
163
164 #ifndef CONFIG_USE_SHM
165     //is multi-touch mode ?
166     if (get_emul_max_touch_point() > 1) {
167         int state_mask_temp = state_mask & ~JAVA_KEYCODE_NO_FOCUS;
168
169         if ((keycode == JAVA_KEYCODE_BIT_SHIFT &&
170             state_mask_temp == JAVA_KEYCODE_BIT_CTRL) ||
171             (keycode == JAVA_KEYCODE_BIT_CTRL &&
172             state_mask_temp == JAVA_KEYCODE_BIT_SHIFT))
173         {
174             if (KEY_PRESSED == event_type) {
175                 get_emul_multi_touch_state()->multitouch_enable = 2;
176
177                 /* add a finger before start the multi-touch processing
178                 if already exist the pressed touch in display */
179                 if (pressing_x != -1 && pressing_y != -1 &&
180                     pressing_origin_x != -1 && pressing_origin_y != -1) {
181                     add_finger_point(
182                         pressing_origin_x, pressing_origin_y,
183                         pressing_x, pressing_y);
184                     pressing_x = pressing_y = -1;
185                     pressing_origin_x = pressing_origin_y = -1;
186                 }
187
188                 INFO("enable multi-touch = mode2\n");
189             }
190         }
191         else if (keycode == JAVA_KEYCODE_BIT_CTRL ||
192             keycode == JAVA_KEYCODE_BIT_SHIFT)
193         {
194             if (KEY_PRESSED == event_type) {
195                 get_emul_multi_touch_state()->multitouch_enable = 1;
196
197                 /* add a finger before start the multi-touch processing
198                 if already exist the pressed touch in display */
199                 if (pressing_x != -1 && pressing_y != -1 &&
200                     pressing_origin_x != -1 && pressing_origin_y != -1) {
201                     add_finger_point(
202                         pressing_origin_x, pressing_origin_y,
203                         pressing_x, pressing_y);
204                     pressing_x = pressing_y = -1;
205                     pressing_origin_x = pressing_origin_y = -1;
206                 }
207
208                 INFO("enable multi-touch = mode1\n");
209             } else if (KEY_RELEASED == event_type) {
210                 if (state_mask_temp == (JAVA_KEYCODE_BIT_CTRL | JAVA_KEYCODE_BIT_SHIFT)) {
211                     get_emul_multi_touch_state()->multitouch_enable = 1;
212                     INFO("enabled multi-touch = mode1\'\n");
213                 } else {
214                     get_emul_multi_touch_state()->multitouch_enable = 0;
215                     clear_finger_slot();
216                     INFO("disable multi-touch\n");
217                 }
218             }
219         }
220
221     }
222 #endif
223
224 #if defined(TARGET_I386)
225     if (!mloop_evcmd_get_hostkbd_status()) {
226         TRACE("ignore keyboard input because usb keyboard is dettached.\n");
227         return;
228     }
229 #endif
230
231 #if defined(TARGET_ARM)
232     if (!mloop_evcmd_get_usbkbd_status()) {
233         TRACE("ignore keyboard input because usb keyboard is dettached.\n");
234         return;
235     }
236 #endif
237
238     scancode = javakeycode_to_scancode(event_type, keycode, state_mask, key_location);
239
240     if (scancode == -1) {
241         INFO("cannot find scancode\n");
242         return;
243     }
244
245     if (KEY_PRESSED == event_type) {
246         TRACE("key pressed: %d\n", scancode);
247         kbd_put_keycode(scancode);
248     } else if (KEY_RELEASED == event_type) {
249         TRACE("key released: %d\n", scancode);
250         kbd_put_keycode(scancode | 0x80);
251     }
252 }
253
254 void do_hardkey_event(int event_type, int keycode)
255 {
256     INFO("do_hardkey_event event_type:%d, keycode:%d\n",
257         event_type, keycode);
258
259     if ( is_suspended_state() ) {
260         if ( KEY_PRESSED == event_type ) {
261             if ( kbd_mouse_is_absolute() ) {
262                 // home key or power key is used for resume.
263                 if ( ( HARD_KEY_HOME == keycode ) || ( HARD_KEY_POWER == keycode ) ) {
264                     INFO( "user requests system resume.\n" );
265                     resume();
266 #ifdef CONFIG_WIN32
267                     Sleep( RESUME_KEY_SEND_INTERVAL );
268 #else
269                     usleep( RESUME_KEY_SEND_INTERVAL * 1000 );
270 #endif
271                 }
272             }
273         }
274     }
275
276     mloop_evcmd_hwkey(event_type, keycode);
277 }
278
279 void do_scale_event(double scale_factor)
280 {
281     INFO("do_scale_event scale_factor:%lf\n", scale_factor);
282
283     set_emul_win_scale(scale_factor);
284
285 #if 0
286     //TODO: thread safe
287     //qemu refresh
288     vga_hw_invalidate();
289     vga_hw_update();
290 #endif
291 }
292
293 void do_rotation_event(int rotation_type)
294 {
295
296     INFO( "do_rotation_event rotation_type:%d\n", rotation_type);
297
298     char send_buf[32] = { 0 };
299
300     switch ( rotation_type ) {
301         case ROTATION_PORTRAIT:
302             sprintf( send_buf, "1\n3\n0\n9.80665\n0\n" );
303             break;
304         case ROTATION_LANDSCAPE:
305             sprintf( send_buf, "1\n3\n9.80665\n0\n0\n" );
306             break;
307         case ROTATION_REVERSE_PORTRAIT:
308             sprintf( send_buf, "1\n3\n0\n-9.80665\n0\n" );
309             break;
310         case ROTATION_REVERSE_LANDSCAPE:
311             sprintf(send_buf, "1\n3\n-9.80665\n0\n0\n");
312             break;
313
314         default:
315             break;
316     }
317
318     send_to_emuld( "sensor\n\n\n\n", 10, send_buf, 32 );
319
320     set_emul_rotation( rotation_type );
321
322 }
323
324 QemuSurfaceInfo* get_screenshot_info(void)
325 {
326     DisplaySurface* qemu_display_surface = get_qemu_display_surface();
327
328     if ( !qemu_display_surface ) {
329         ERR( "qemu surface is NULL.\n" );
330         return NULL;
331     }
332
333     QemuSurfaceInfo* info = (QemuSurfaceInfo*) g_malloc0( sizeof(QemuSurfaceInfo) );
334     if ( !info ) {
335         ERR( "Fail to malloc for QemuSurfaceInfo.\n");
336         return NULL;
337     }
338
339     int length = qemu_display_surface->linesize * qemu_display_surface->height;
340     INFO( "screenshot data length:%d\n", length );
341
342     if ( 0 >= length ) {
343         g_free( info );
344         ERR( "screenshot data ( 0 >=length ). length:%d\n", length );
345         return NULL;
346     }
347
348     info->pixel_data = (unsigned char*) g_malloc0( length );
349     if ( !info->pixel_data ) {
350         g_free( info );
351         ERR( "Fail to malloc for pixel data.\n");
352         return NULL;
353     }
354
355     pthread_mutex_lock(&mutex_screenshot);
356     MaruScreenshot* maru_screenshot = get_maru_screenshot();
357     if ( !maru_screenshot || maru_screenshot->isReady != 1) {
358         ERR( "maru screenshot is NULL or not ready.\n" );
359         memset(info->pixel_data, 0x00, length);
360     } else {
361         maru_screenshot->pixel_data = info->pixel_data;
362         maru_screenshot->request_screenshot = 1;
363         pthread_cond_wait(&cond_screenshot, &mutex_screenshot);
364     }
365     pthread_mutex_unlock(&mutex_screenshot);
366
367     info->pixel_data_length = length;
368
369     return info;
370 }
371
372 void free_screenshot_info(QemuSurfaceInfo* info)
373 {
374     if (info) {
375         if(info->pixel_data) {
376             g_free(info->pixel_data);
377         }
378
379         g_free(info);
380     }
381 }
382
383 DetailInfo* get_detail_info(int qemu_argc, char** qemu_argv)
384 {
385     DetailInfo* detail_info = g_malloc0( sizeof(DetailInfo) );
386     if ( !detail_info ) {
387         ERR( "Fail to malloc for DetailInfo.\n" );
388         return NULL;
389     }
390
391     int i = 0;
392     int total_len = 0;
393     int delimiter_len = strlen( DATA_DELIMITER );
394
395     /* collect QEMU information */
396     for ( i = 0; i < qemu_argc; i++ ) {
397         total_len += strlen( qemu_argv[i] );
398         total_len += delimiter_len;
399     }
400
401 #ifdef CONFIG_WIN32
402     /* collect HAXM information */
403     const int HAX_LEN = 32;
404     char hax_error[HAX_LEN];
405     memset( hax_error, 0, HAX_LEN );
406
407     int hax_err_len = 0;
408     hax_err_len = sprintf( hax_error + hax_err_len, "%s", "hax_error=" );
409
410     int error = 0;
411     if ( !ret_hax_init ) {
412         if ( -ENOSPC == ret_hax_init ) {
413             error = 1;
414         }
415     }
416     hax_err_len += sprintf( hax_error + hax_err_len, "%s#", error ? "true" : "false" );
417     total_len += (hax_err_len + 1);
418 #endif
419
420     /* collect log path information */
421 #define LOGPATH_TEXT "log_path="
422     char* log_path = get_log_path();
423     int log_path_len = strlen(LOGPATH_TEXT) + strlen(log_path) + delimiter_len;
424     total_len += (log_path_len + 1);
425
426     /* memory allocation */
427     char* info_data = g_malloc0( total_len + 1 );
428     if ( !info_data ) {
429         g_free( detail_info );
430         ERR( "Fail to malloc for info data.\n" );
431         return NULL;
432     }
433
434
435     /* write informations */
436     int len = 0;
437     total_len = 0; //recycle
438
439     for ( i = 0; i < qemu_argc; i++ ) {
440         len = strlen( qemu_argv[i] );
441         sprintf( info_data + total_len, "%s%s", qemu_argv[i], DATA_DELIMITER );
442         total_len += len + delimiter_len;
443     }
444
445 #ifdef CONFIG_WIN32
446     snprintf( info_data + total_len, hax_err_len + 1, "%s#", hax_error );
447     total_len += hax_err_len;
448 #endif
449
450     snprintf( info_data + total_len, log_path_len + 1, "%s%s#", LOGPATH_TEXT, log_path );
451     total_len += log_path_len;
452
453     INFO( "################## detail info data ####################\n" );
454     INFO( "%s\n", info_data );
455
456     detail_info->data = info_data;
457     detail_info->data_length = total_len;
458
459     return detail_info;
460 }
461
462 void free_detail_info(DetailInfo* detail_info)
463 {
464     if (detail_info) {
465         if (detail_info->data) {
466             g_free(detail_info->data);
467         }
468
469         g_free(detail_info);
470     }
471 }
472
473 void do_open_shell(void)
474 {
475     INFO("open shell\n");
476     /* do nothing */
477 }
478
479 void onoff_host_kbd(int on)
480 {
481     INFO("host kbd on/off: %d.\n", on);
482
483 #if defined(TARGET_ARM)
484     mloop_evcmd_usbkbd(on);
485 #elif defined(TARGET_I386)
486     mloop_evcmd_hostkbd(on);
487 #endif
488 }
489
490 void do_ram_dump(void)
491 {
492     INFO("dump ram!\n");
493
494     mloop_evcmd_ramdump();
495 }
496
497 void do_guestmemory_dump(void)
498 {
499     INFO("dump guest memory!\n");
500
501     /* TODO: */
502 }
503
504 void request_close(void)
505 {
506     INFO("request_close\n");
507
508     /* FIXME: convert to device emulatoion */
509     do_hardkey_event(KEY_PRESSED, HARD_KEY_POWER);
510
511 #ifdef CONFIG_WIN32
512         Sleep(CLOSE_POWER_KEY_INTERVAL);
513 #else
514         usleep(CLOSE_POWER_KEY_INTERVAL * 1000);
515 #endif
516
517     do_hardkey_event(KEY_RELEASED, HARD_KEY_POWER);
518
519 }
520
521 void shutdown_qemu_gracefully( void ) {
522
523     requested_shutdown_qemu_gracefully = 1;
524
525     pthread_t thread_id;
526     if( 0 > pthread_create( &thread_id, NULL, run_timed_shutdown_thread, NULL ) ) {
527         ERR( "!!! Fail to create run_timed_shutdown_thread. shutdown qemu right now !!!\n"  );
528         qemu_system_shutdown_request();
529     }
530
531 }
532
533 int is_requested_shutdown_qemu_gracefully( void ) {
534     return requested_shutdown_qemu_gracefully;
535 }
536
537 static void* run_timed_shutdown_thread( void* args ) {
538
539     send_to_emuld( "system\n\n\n\n", 10, "shutdown", 8 );
540
541     int sleep_interval_time = 1000; // milli-seconds
542
543     int i;
544     for ( i = 0; i < TIMEOUT_FOR_SHUTDOWN; i++ ) {
545 #ifdef CONFIG_WIN32
546         Sleep( sleep_interval_time );
547 #else
548         usleep( sleep_interval_time * 1000 );
549 #endif
550         // do not use logger to help user see log in console
551         fprintf( stdout, "Wait for shutdown qemu...%d\n", ( i + 1 ) );
552     }
553
554     INFO( "Shutdown qemu !!!\n" );
555     qemu_system_shutdown_request();
556
557     return NULL;
558
559 }
560
561 static void send_to_emuld( const char* request_type, int request_size, const char* send_buf, int buf_size ) {
562
563     int s = tcp_socket_outgoing( "127.0.0.1", (uint16_t) ( tizen_base_port + SDB_TCP_EMULD_INDEX ) );
564
565     if ( s < 0 ) {
566         ERR( "can't create socket to talk to the sdb forwarding session \n" );
567         ERR( "[127.0.0.1:%d/tcp] connect fail (%d:%s)\n" , tizen_base_port + SDB_TCP_EMULD_INDEX , errno, strerror(errno) );
568         return;
569     }
570
571     socket_send( s, (char*)request_type, request_size );
572     socket_send( s, &buf_size, 4 );
573     socket_send( s, (char*)send_buf, buf_size );
574
575     INFO( "send to emuld [req_type:%s, send_data:%s, send_size:%d] 127.0.0.1:%d/tcp \n",
576         request_type, send_buf, buf_size, tizen_base_port + SDB_TCP_EMULD_INDEX );
577
578 #ifdef CONFIG_WIN32
579     closesocket( s );
580 #else
581     close( s );
582 #endif
583
584 }