aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVladimir Chtchetkine <vchtchetkine@google.com>2011-01-19 18:29:27 -0800
committerVladimir Chtchetkine <vchtchetkine@google.com>2011-01-19 18:29:27 -0800
commit9411a562e1ab772732a4d5147c9103a638837c82 (patch)
treebf11eddce29c02b4376bc0cb76e5f9233791cf39
parenta9edc435e6592fcc001e21e150391a84bde114a6 (diff)
downloadexternal_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.android1
-rw-r--r--android/console.c42
-rw-r--r--android/framebuffer-core.c4
-rw-r--r--android/main-ui.c7
-rw-r--r--android/sync-utils.c18
-rw-r--r--android/sync-utils.h11
-rw-r--r--android/user-events-common.h57
-rw-r--r--android/user-events-core.c172
-rw-r--r--android/user-events-core.h37
-rw-r--r--user-events-ui.c134
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));
}