diff options
author | Vladimir Chtchetkine <vchtchetkine@google.com> | 2011-01-19 18:29:27 -0800 |
---|---|---|
committer | Vladimir Chtchetkine <vchtchetkine@google.com> | 2011-01-19 18:29:27 -0800 |
commit | 9411a562e1ab772732a4d5147c9103a638837c82 (patch) | |
tree | bf11eddce29c02b4376bc0cb76e5f9233791cf39 | |
parent | a9edc435e6592fcc001e21e150391a84bde114a6 (diff) | |
download | external_qemu-9411a562e1ab772732a4d5147c9103a638837c82.zip external_qemu-9411a562e1ab772732a4d5147c9103a638837c82.tar.gz external_qemu-9411a562e1ab772732a4d5147c9103a638837c82.tar.bz2 |
Implement user event transmission between the UI and the core
Change-Id: I503aa691cada5250b76167a923d4a226d20ee41d
-rw-r--r-- | Makefile.android | 1 | ||||
-rw-r--r-- | android/console.c | 42 | ||||
-rw-r--r-- | android/framebuffer-core.c | 4 | ||||
-rw-r--r-- | android/main-ui.c | 7 | ||||
-rw-r--r-- | android/sync-utils.c | 18 | ||||
-rw-r--r-- | android/sync-utils.h | 11 | ||||
-rw-r--r-- | android/user-events-common.h | 57 | ||||
-rw-r--r-- | android/user-events-core.c | 172 | ||||
-rw-r--r-- | android/user-events-core.h | 37 | ||||
-rw-r--r-- | user-events-ui.c | 134 |
10 files changed, 458 insertions, 25 deletions
diff --git a/Makefile.android b/Makefile.android index b502344..b9a6fa5 100644 --- a/Makefile.android +++ b/Makefile.android @@ -1058,6 +1058,7 @@ VL_SOURCES := framebuffer.c \ android/looper-generic.c \ android/display-core.c \ android/framebuffer-core.c \ + android/user-events-core.c \ # Add common system libraries # diff --git a/android/console.c b/android/console.c index 96cc005..6f9e26b 100644 --- a/android/console.c +++ b/android/console.c @@ -53,6 +53,7 @@ #include "android/core-ui-protocol.h" #include "android/display-core.h" #include "android/framebuffer-core.h" +#include "android/user-events-core.h" #if defined(CONFIG_SLIRP) #include "libslirp.h" @@ -119,6 +120,12 @@ ControlClient attached_ui_client = NULL; /* Core framebuffer service client. */ ControlClient framebuffer_client = NULL; + +/* User events service client. */ +ControlClient user_events_client = NULL; + +/* User events service. */ +CoreUserEvents* core_ue = NULL; #endif // CONFIG_STANDALONE_CORE /* -android-avdname option value. Defined in vl-android.c */ @@ -236,6 +243,11 @@ control_client_destroy( ControlClient client ) } framebuffer_client = NULL; } + + if (client == user_events_client) { + coreue_destroy(core_ue); + user_events_client = NULL; + } #endif // CONFIG_STANDALONE_CORE sock = control_client_detach( client ); @@ -2537,6 +2549,32 @@ do_create_framebuffer_service( ControlClient client, char* args ) return 0; } + +static int +do_create_user_events_service( ControlClient client, char* args ) +{ + // Make sure that there are no framebuffer client already existing. + if (user_events_client != NULL) { + control_write( client, "KO: Another user events service is already existing!\r\n" ); + control_client_destroy(client); + return -1; + } + + core_ue = coreue_create(client->sock); + if (core_ue != NULL) { + char reply_buf[4096]; + user_events_client = client; + // Reply "OK" with the framebuffer's bits per pixel + snprintf(reply_buf, sizeof(reply_buf), "OK\r\n"); + control_write( client, reply_buf); + } else { + control_write( client, "KO\r\n" ); + control_client_destroy(client); + return -1; + } + + return 0; +} #endif // CONFIG_STANDALONE_CORE static const CommandDefRec qemu_commands[] = @@ -2553,6 +2591,10 @@ static const CommandDefRec qemu_commands[] = { "framebuffer", "create framebuffer service", "Create framebuffer service\r\n", NULL, do_create_framebuffer_service, NULL }, + + { "user events", "create user events service", + "Create user events service\r\n", + NULL, do_create_user_events_service, NULL }, #endif // CONFIG_STANDALONE_CORE { NULL, NULL, NULL, NULL, NULL, NULL } diff --git a/android/framebuffer-core.c b/android/framebuffer-core.c index f4f53a7..978bfc0 100644 --- a/android/framebuffer-core.c +++ b/android/framebuffer-core.c @@ -229,7 +229,6 @@ corefb_update(CoreFramebuffer* core_fb, struct DisplayState* ds, if (core_fb->fb_update_tail != NULL) { core_fb->fb_update_tail->next_fb_update = descr; core_fb->fb_update_tail = descr; - printf("PENDED\n"); return; } @@ -243,16 +242,13 @@ corefb_update(CoreFramebuffer* core_fb, struct DisplayState* ds, case ASYNC_COMPLETE: fbupdatenotify_delete(descr); core_fb->fb_update_head = core_fb->fb_update_tail = NULL; - printf("COMPLETED\n"); return; case ASYNC_ERROR: - printf("FAILED: %s\n", errno_str); fbupdatenotify_delete(descr); core_fb->fb_update_head = core_fb->fb_update_tail = NULL; return; case ASYNC_NEED_MORE: // Update transfer will eventually complete in corefb_io_func - printf("PARTIAL\n"); return; } } diff --git a/android/main-ui.c b/android/main-ui.c index 7a4d746..4d8560c 100644 --- a/android/main-ui.c +++ b/android/main-ui.c @@ -852,6 +852,9 @@ list_running_cores(const char* host) } } +/* Implemented in user-events-ui.c */ +extern int clientue_create(SockAddress* console_socket); + /* Attaches starting UI to a running core process. * This routine is called from main() when -attach-core parameter is set, * indicating that this UI instance should attach to a running core, rather than @@ -955,6 +958,10 @@ attach_to_core(AndroidOptions* opts) { return -1; } + if (clientue_create(&console_socket)) { + return -1; + } + return 0; } diff --git a/android/sync-utils.c b/android/sync-utils.c index c5674b2..32c803c 100644 --- a/android/sync-utils.c +++ b/android/sync-utils.c @@ -25,6 +25,7 @@ #include "sockets.h" #include "android/utils/debug.h" #include "android/sync-utils.h" +#include "android/utils/system.h" #define D(...) do { if (VERBOSE_CHECK(init)) dprint(__VA_ARGS__); } while (0) @@ -37,11 +38,24 @@ struct SyncSocket { }; SyncSocket* +syncsocket_init(int fd) +{ + SyncSocket* sync_socket; + ANEW0(sync_socket); + + socket_set_nonblock(fd); + sync_socket->iolooper = iolooper_new(); + sync_socket->fd = fd; + + return sync_socket; +} + +SyncSocket* syncsocket_connect(int fd, SockAddress* sockaddr, int timeout) { - IoLooper* looper = NULL; + IoLooper* looper; int connect_status; - SyncSocket* sync_socket; + SyncSocket* sync_socket = NULL; socket_set_nonblock(fd); diff --git a/android/sync-utils.h b/android/sync-utils.h index 726b310..110a143 100644 --- a/android/sync-utils.h +++ b/android/sync-utils.h @@ -39,6 +39,17 @@ typedef struct SyncSocket SyncSocket; SyncSocket* syncsocket_connect(int fd, SockAddress* sockaddr, int timeout); /* + * Initializes a non-blocking socket for further synchronous I/O. + * Note: this routine will explicitly call socket_set_nonblock on the fd passed + * to this routine. + * Param: + * fd - File descriptor for the already connected. + * Return: + * Initialized SyncSocket descriptor on success, or NULL on failure. + */ +SyncSocket* syncsocket_init(int fd); + +/* * Closes SyncSocket descriptor obtained from syncsocket_connect routine. * Param: * ssocket - SyncSocket descriptor obtained from syncsocket_connect routine. diff --git a/android/user-events-common.h b/android/user-events-common.h new file mode 100644 index 0000000..4d02c09 --- /dev/null +++ b/android/user-events-common.h @@ -0,0 +1,57 @@ +/* Copyright (C) 2010 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** 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. +*/ + +#ifndef _ANDROID_USER_EVENTS_COMMON_H +#define _ANDROID_USER_EVENTS_COMMON_H + +#include "globals.h" + +/* Mouse event. */ +#define AUSER_EVENT_MOUSE 0 +/* Keycode event. */ +#define AUSER_EVENT_KEYCODE 1 +/* Generic event. */ +#define AUSER_EVENT_GENERIC 2 + +/* Header for user event message sent from UI to the core. */ +typedef struct UserEventHeader { + /* Event type. See AUSER_EVENT_XXX for possible values. */ + uint8_t event_type; +} UserEventHeader; + +/* Formats mouse event message (AUSER_EVENT_MOUSE) sent from + * UI to the core. + */ +typedef struct UserEventMouse { + int dx; + int dy; + int dz; + unsigned buttons_state; +} UserEventMouse; + +/* Formats keycode event message (AUSER_EVENT_KEYCODE) sent from + * UI to the core. + */ +typedef struct UserEventKeycode { + int keycode; +} UserEventKeycode; + +/* Formats generic event message (AUSER_EVENT_GENERIC) sent from + * UI to the core. + */ +typedef struct UserEventGeneric { + int type; + int code; + int value; +} UserEventGeneric; + +#endif /* _ANDROID_USER_EVENTS_COMMON_H */ diff --git a/android/user-events-core.c b/android/user-events-core.c new file mode 100644 index 0000000..a732791 --- /dev/null +++ b/android/user-events-core.c @@ -0,0 +1,172 @@ +/* Copyright (C) 2010 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** 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. +*/ + +#include "user-events.h" +#include "android/globals.h" +#include "android/android.h" +#include "android/looper.h" +#include "android/async-utils.h" +#include "android/utils/system.h" +#include "android/utils/debug.h" +#include "android/user-events-common.h" +#include "android/user-events-core.h" +#include "android/sync-utils.h" + +/* States of the core user events service. + */ + +/* Event header is expected in the pipe. */ +#define UE_STATE_EVENT_HEADER 0 +/* Event parameters are expected in the pipe. */ +#define UE_STATE_EVENT_PARAM 1 + +/* Core user events service descriptor. */ +struct CoreUserEvents { + /* Reader to receive user events. */ + AsyncReader user_events_reader; + + /* I/O associated with this descriptor. */ + LoopIo io; + + /* Looper used to communicate user events. */ + Looper* looper; + + /* Socket for this service. */ + int sock; + + /* State of the service (see UE_STATE_XXX for possible values). */ + int state; + + /* Current event header. */ + UserEventHeader event_header; + + /* Current event parameters. */ + union { + UserEventGeneric generic_event; + UserEventMouse mouse_event; + UserEventKeycode keycode_event; + }; +}; + + +/* + * Asynchronous I/O callback launched when reading user events from the socket. + * Param: + * opaque - CoreUserEvents instance. + */ +static void +coreue_io_func(void* opaque, int fd, unsigned events) +{ + CoreUserEvents* ue = opaque; + // Read whatever is expected from the socket. + const AsyncStatus status = asyncReader_read(&ue->user_events_reader, &ue->io); + + switch (status) { + case ASYNC_COMPLETE: + switch (ue->state) { + case UE_STATE_EVENT_HEADER: + // We just read event header. Now we expect event parameters. + ue->state = UE_STATE_EVENT_PARAM; + // Setup the reader depending on the event type. + switch (ue->event_header.event_type) { + case AUSER_EVENT_MOUSE: + asyncReader_init(&ue->user_events_reader, + &ue->mouse_event, + sizeof(ue->mouse_event), + &ue->io); + break; + case AUSER_EVENT_KEYCODE: + asyncReader_init(&ue->user_events_reader, + &ue->keycode_event, + sizeof(ue->keycode_event), + &ue->io); + break; + case AUSER_EVENT_GENERIC: + asyncReader_init(&ue->user_events_reader, + &ue->generic_event, + sizeof(ue->generic_event), + &ue->io); + break; + default: + derror("Unexpected event type %d\n", + ue->event_header.event_type); + break; + } + break; + + case UE_STATE_EVENT_PARAM: + // We just read event parameters. Lets fire the event. + switch (ue->event_header.event_type) { + case AUSER_EVENT_MOUSE: + user_event_mouse(ue->mouse_event.dx, + ue->mouse_event.dy, + ue->mouse_event.dz, + ue->mouse_event.buttons_state); + break; + case AUSER_EVENT_KEYCODE: + user_event_keycode(ue->keycode_event.keycode); + break; + case AUSER_EVENT_GENERIC: + user_event_generic(ue->generic_event.type, + ue->generic_event.code, + ue->generic_event.value); + break; + default: + derror("Unexpected event type %d\n", + ue->event_header.event_type); + break; + } + // Now we expect event header. + ue->event_header.event_type = -1; + ue->state = UE_STATE_EVENT_HEADER; + asyncReader_init(&ue->user_events_reader, &ue->event_header, + sizeof(ue->event_header), &ue->io); + break; + } + break; + case ASYNC_ERROR: + loopIo_dontWantRead(&ue->io); + break; + + case ASYNC_NEED_MORE: + // Transfer will eventually come back into this routine. + return; + } +} + +CoreUserEvents* +coreue_create(int fd) +{ + CoreUserEvents* ue; + ANEW0(ue); + ue->sock = fd; + ue->state = UE_STATE_EVENT_HEADER; + ue->looper = looper_newCore(); + loopIo_init(&ue->io, ue->looper, ue->sock, coreue_io_func, ue); + asyncReader_init(&ue->user_events_reader, &ue->event_header, + sizeof(ue->event_header), &ue->io); + return ue; +} + +void +coreue_destroy(CoreUserEvents* ue) +{ + if (ue != NULL) { + if (ue->looper != NULL) { + // Stop all I/O that may still be going on. + loopIo_done(&ue->io); + looper_free(ue->looper); + ue->looper = NULL; + } + free(ue); + } +} diff --git a/android/user-events-core.h b/android/user-events-core.h new file mode 100644 index 0000000..04bab6c --- /dev/null +++ b/android/user-events-core.h @@ -0,0 +1,37 @@ +/* Copyright (C) 2010 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** 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. +*/ + +/* + * Contains recepient of user events sent from the UI. + */ + +#ifndef _ANDROID_USER_EVENTS_CORE_H +#define _ANDROID_USER_EVENTS_CORE_H + +/* Descriptor for a core user events instance */ +typedef struct CoreUserEvents CoreUserEvents; + +/* + * Creates and initializes core user events instance. + * Param: + * fd - Socket descriptor for the service. + */ +extern CoreUserEvents* coreue_create(int fd); + +/* + * Destroys core user events service. + * Param: + * ue - User event service descriptor to destroy. + */ +extern void coreue_destroy(CoreUserEvents* ue); + +#endif /* _ANDROID_USER_EVENTS_CORE_H */ diff --git a/user-events-ui.c b/user-events-ui.c index f295ade..cef3689 100644 --- a/user-events-ui.c +++ b/user-events-ui.c @@ -11,9 +11,110 @@ */ #include "user-events.h" #include "android/utils/debug.h" +#include "android/user-events-common.h" #include "console.h" #include <stdio.h> +#include "android/looper.h" +#include "android/async-utils.h" +#include "android/core-connection.h" + +/* Descriptor for the user events client. */ +typedef struct ClientUserEvents { + /* Core connection instance for the user events client. */ + CoreConnection* core_connection; + + /* Socket for the client. */ + int sock; + + /* Socket wrapper for sync I/O. */ + SyncSocket* sync_socket; +} ClientUserEvents; + +/* One and only one user events client instance. */ +static ClientUserEvents _client_ue = { 0 }; + +int +clientue_create(SockAddress* console_socket) +{ + char* connect_message = NULL; + char switch_cmd[256]; + + // Connect to the framebuffer service. + _client_ue.core_connection = core_connection_create(console_socket); + if (_client_ue.core_connection == NULL) { + derror("User events client is unable to connect to the console: %s\n", + errno_str); + return -1; + } + if (core_connection_open(_client_ue.core_connection)) { + core_connection_free(_client_ue.core_connection); + _client_ue.core_connection = NULL; + derror("User events client is unable to open the console: %s\n", + errno_str); + return -1; + } + snprintf(switch_cmd, sizeof(switch_cmd), "user events"); + if (core_connection_switch_stream(_client_ue.core_connection, switch_cmd, + &connect_message)) { + derror("Unable to connect to the user events service: %s\n", + connect_message ? connect_message : ""); + if (connect_message != NULL) { + free(connect_message); + } + core_connection_close(_client_ue.core_connection); + core_connection_free(_client_ue.core_connection); + _client_ue.core_connection = NULL; + return -1; + } + + // Now that we're connected lets initialize the descriptor. + _client_ue.sock = core_connection_get_socket(_client_ue.core_connection); + _client_ue.sync_socket = syncsocket_init(_client_ue.sock); + if (connect_message != NULL) { + free(connect_message); + } + + fprintf(stdout, "User events client is now attached to the core %s\n", + sock_address_to_string(console_socket)); + + return 0; +} + +/* Sends an event to the core. + * Parameters: + * ue - User events client instance. + * event - Event type. Must be one of the AUSER_EVENT_XXX. + * event_param - Event parameters. + * size - Byte size of the event parameters buffer. + * Return: + * 0 on success, or -1 on failure. + */ +static int +clientue_send(ClientUserEvents* ue, + uint8_t event, + const void* event_param, + size_t size) +{ + int res; + UserEventHeader header; + + header.event_type = event; + syncsocket_start_write(ue->sync_socket); + // Send event type first (event header) + res = syncsocket_write(ue->sync_socket, &header, sizeof(header), 500); + if (res < 0) { + return -1; + } + // Send event param next. + res = syncsocket_write(ue->sync_socket, event_param, size, 500); + if (res < 0) { + return -1; + } + syncsocket_stop_write(ue->sync_socket); + return 0; +} + void user_event_keycodes(int *kcodes, int count) { @@ -25,9 +126,9 @@ user_event_keycodes(int *kcodes, int count) void user_event_keycode(int kcode) { -#if 0 /* TODO */ - kbd_put_keycode(kcode); -#endif + UserEventKeycode message; + message.keycode = kcode; + clientue_send(&_client_ue, AUSER_EVENT_KEYCODE, &message, sizeof(message)); } void @@ -46,29 +147,24 @@ user_event_key(unsigned code, unsigned down) void user_event_mouse(int dx, int dy, int dz, unsigned buttons_state) { -#if 0 /* TODO */ - kbd_mouse_event(dx, dy, dz, buttons_state); -#endif + UserEventMouse message; + message.dx = dx; + message.dy = dy; + message.dz = dz; + message.buttons_state = buttons_state; + clientue_send(&_client_ue, AUSER_EVENT_MOUSE, &message, sizeof(message)); } -#if 0 -static QEMUPutGenericEvent *generic_event_callback; -static void* generic_event_opaque; -#endif - void user_event_register_generic(void* opaque, QEMUPutGenericEvent *callback) { -#if 0 /* TODO */ - generic_event_callback = callback; - generic_event_opaque = opaque; -#endif } void user_event_generic(int type, int code, int value) { -#if 0 /* TODO */ - if (generic_event_callback) - generic_event_callback(generic_event_opaque, type, code, value); -#endif + UserEventGeneric message; + message.type = type; + message.code = code; + message.value = value; + clientue_send(&_client_ue, AUSER_EVENT_GENERIC, &message, sizeof(message)); } |