aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile.android1
-rw-r--r--android/display.c102
-rw-r--r--android/display.h20
-rw-r--r--android/main.c316
-rw-r--r--android/qemulator.c280
-rw-r--r--android/skin/window.c22
-rw-r--r--android/ui-core-protocol.c24
-rw-r--r--android/ui-core-protocol.h7
-rw-r--r--console.h5
-rw-r--r--docs/DISPLAY-STATE.TXT263
-rw-r--r--framebuffer.c12
-rw-r--r--framebuffer.h11
-rw-r--r--hw/android_arm.c3
-rw-r--r--hw/goldfish_device.h2
-rw-r--r--hw/goldfish_events_device.c2
-rw-r--r--hw/goldfish_fb.c84
16 files changed, 787 insertions, 367 deletions
diff --git a/Makefile.android b/Makefile.android
index 2eb39c4..ae3e53d 100644
--- a/Makefile.android
+++ b/Makefile.android
@@ -632,6 +632,7 @@ CORE_MISC_SOURCES = vl-android.c \
bt-vhci.c \
module.c \
android/boot-properties.c \
+ android/display.c \
android/hw-kmsg.c \
android/hw-lcd.c \
android/gps.c \
diff --git a/android/display.c b/android/display.c
new file mode 100644
index 0000000..0cfd98d
--- /dev/null
+++ b/android/display.c
@@ -0,0 +1,102 @@
+/* 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.
+*/
+
+/* Initialization of the Android-specific DisplayState.
+ * Read docs/DISPLAY-STATE.TXT to understand what this
+ * is supposed to do.
+ */
+#include "android/display.h"
+
+/*
+
+TECHNICAL NOTE:
+
+DisplayState <--> QFrameBuffer <--> QEmulator/SDL
+
+*/
+
+/* QFrameBuffer producer callbacks */
+
+/* this is called periodically by the GUI timer to check for updates
+ * and poll user events. Use vga_hw_update().
+ */
+static void
+android_display_producer_check(void *opaque)
+{
+ /* core: call vga_hw_update(). this will eventually
+ * lead to calls to android_display_update()
+ */
+ (void)opaque;
+ vga_hw_update();
+}
+
+static void
+android_display_producer_invalidate(void *opaque)
+{
+ (void)opaque;
+ vga_hw_invalidate();
+}
+
+/* QFrameBuffer client callbacks */
+
+/* this is called from dpy_update() each time a hardware framebuffer
+ * rectangular update was detected. Send this to the QFrameBuffer.
+ */
+static void
+android_display_update(DisplayState *ds, int x, int y, int w, int h)
+{
+ QFrameBuffer* qfbuff = ds->opaque;
+ qframebuffer_update(qfbuff, x, y, w, h);
+}
+
+static void
+android_display_resize(DisplayState *ds)
+{
+ QFrameBuffer* qfbuff = ds->opaque;
+ qframebuffer_rotate(qfbuff, 0);
+}
+
+static void
+android_display_refresh(DisplayState *ds)
+{
+ QFrameBuffer* qfbuff = ds->opaque;
+ qframebuffer_poll(qfbuff);
+}
+
+
+void android_display_init(DisplayState* ds, QFrameBuffer* qf)
+{
+ DisplayChangeListener* dcl;
+
+ qframebuffer_set_producer(qf, ds,
+ android_display_producer_check,
+ android_display_producer_invalidate,
+ NULL); // detach
+
+ /* Replace the display surface with one with the right dimensions */
+ qemu_free_displaysurface(ds);
+ ds->opaque = qf;
+ ds->surface = qemu_create_displaysurface_from(qf->width,
+ qf->height,
+ 16,
+ qf->pitch,
+ qf->pixels);
+
+ /* Register a change listener for it */
+ dcl = (DisplayChangeListener *) qemu_mallocz(sizeof(DisplayChangeListener));
+ dcl->dpy_update = android_display_update;
+ dcl->dpy_resize = android_display_resize;
+ dcl->dpy_refresh = android_display_refresh;
+ dcl->dpy_text_cursor = NULL;
+
+ register_displaychangelistener(ds, dcl);
+}
diff --git a/android/display.h b/android/display.h
new file mode 100644
index 0000000..111979c
--- /dev/null
+++ b/android/display.h
@@ -0,0 +1,20 @@
+/* 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_DISPLAY_H
+#define _ANDROID_DISPLAY_H
+
+#include "console.h"
+#include "framebuffer.h"
+
+extern void android_display_init(DisplayState* ds, QFrameBuffer* qfbuff);
+
+#endif /* _ANDROID_DISPLAY_H */
diff --git a/android/main.c b/android/main.c
index 88ce36b..99720f5 100644
--- a/android/main.c
+++ b/android/main.c
@@ -70,11 +70,13 @@
#include "tcpdump.h"
#include "android/qemulator.h"
+#include "android/display.h"
/* in vl.c */
extern void qemu_help(int code);
#include "framebuffer.h"
+
AndroidRotation android_framebuffer_rotation;
#define STRINGIFY(x) _STRINGIFY(x)
@@ -103,8 +105,6 @@ extern int qemu_milli_needed;
static int opts->flashkeys; /* forward */
#endif
-static void handle_key_command( void* opaque, SkinKeyCommand command, int param );
-
#ifdef CONFIG_TRACE
extern void start_tracing(void);
extern void stop_tracing(void);
@@ -247,298 +247,6 @@ uint64_t convertMBToBytes( unsigned megaBytes )
/***** *****/
/***********************************************************************/
/***********************************************************************/
-
-/* called by the emulated framebuffer device each time the content of the
- * framebuffer has changed. the rectangle is the bounding box of all changes
- */
-static void
-sdl_update(DisplayState *ds, int x, int y, int w, int h)
-{
- /* this function is being called from the console code that is currently inactive
- ** simple totally ignore it...
- */
- (void)ds;
- (void)x;
- (void)y;
- (void)w;
- (void)h;
-}
-
-
-
-
-/* called by the emulated framebuffer device each time the framebuffer
- * is resized or rotated */
-static void
-sdl_resize(DisplayState *ds)
-{
- //fprintf(stderr, "weird, sdl_resize being called with framebuffer interface\n");
- //exit(1);
-}
-
-
-/* called periodically to poll for user input events */
-static void sdl_refresh(DisplayState *ds)
-{
- QEmulator* emulator = ds->opaque;
- SDL_Event ev;
- SkinWindow* window = emulator->window;
- SkinKeyboard* keyboard = emulator->keyboard;
-
- /* this will eventually call sdl_update if the content of the VGA framebuffer
- * has changed */
- qframebuffer_check_updates();
-
- if (window == NULL)
- return;
-
- while(SDL_PollEvent(&ev)){
- switch(ev.type){
- case SDL_VIDEOEXPOSE:
- skin_window_redraw( window, NULL );
- break;
-
- case SDL_KEYDOWN:
-#ifdef _WIN32
- /* special code to deal with Alt-F4 properly */
- if (ev.key.keysym.sym == SDLK_F4 &&
- ev.key.keysym.mod & KMOD_ALT) {
- goto CleanExit;
- }
-#endif
-#ifdef __APPLE__
- /* special code to deal with Command-Q properly */
- if (ev.key.keysym.sym == SDLK_q &&
- ev.key.keysym.mod & KMOD_META) {
- goto CleanExit;
- }
-#endif
- skin_keyboard_process_event( keyboard, &ev, 1 );
- break;
-
- case SDL_KEYUP:
- skin_keyboard_process_event( keyboard, &ev, 0 );
- break;
-
- case SDL_MOUSEMOTION:
- skin_window_process_event( window, &ev );
- break;
-
- case SDL_MOUSEBUTTONDOWN:
- case SDL_MOUSEBUTTONUP:
- {
- int down = (ev.type == SDL_MOUSEBUTTONDOWN);
- if (ev.button.button == 4)
- {
- /* scroll-wheel simulates DPad up */
- AndroidKeyCode kcode;
-
- kcode = // qemulator_rotate_keycode(kKeyCodeDpadUp);
- android_keycode_rotate(kKeyCodeDpadUp,
- skin_layout_get_dpad_rotation(qemulator_get_layout(qemulator_get())));
- user_event_key( kcode, down );
- }
- else if (ev.button.button == 5)
- {
- /* scroll-wheel simulates DPad down */
- AndroidKeyCode kcode;
-
- kcode = // qemulator_rotate_keycode(kKeyCodeDpadDown);
- android_keycode_rotate(kKeyCodeDpadDown,
- skin_layout_get_dpad_rotation(qemulator_get_layout(qemulator_get())));
- user_event_key( kcode, down );
- }
- else if (ev.button.button == SDL_BUTTON_LEFT) {
- skin_window_process_event( window, &ev );
- }
-#if 0
- else {
- fprintf(stderr, "... mouse button %s: button=%d state=%04x x=%d y=%d\n",
- down ? "down" : "up ",
- ev.button.button, ev.button.state, ev.button.x, ev.button.y);
- }
-#endif
- }
- break;
-
- case SDL_QUIT:
-#if defined _WIN32 || defined __APPLE__
- CleanExit:
-#endif
- /* only save emulator config through clean exit */
- qemulator_done(qemulator_get());
- qemu_system_shutdown_request();
- return;
- }
- }
-
- skin_keyboard_flush( keyboard );
-}
-
-
-/* used to respond to a given keyboard command shortcut
- */
-static void
-handle_key_command( void* opaque, SkinKeyCommand command, int down )
-{
- static const struct { SkinKeyCommand cmd; AndroidKeyCode kcode; } keycodes[] =
- {
- { SKIN_KEY_COMMAND_BUTTON_CALL, kKeyCodeCall },
- { SKIN_KEY_COMMAND_BUTTON_HOME, kKeyCodeHome },
- { SKIN_KEY_COMMAND_BUTTON_BACK, kKeyCodeBack },
- { SKIN_KEY_COMMAND_BUTTON_HANGUP, kKeyCodeEndCall },
- { SKIN_KEY_COMMAND_BUTTON_POWER, kKeyCodePower },
- { SKIN_KEY_COMMAND_BUTTON_SEARCH, kKeyCodeSearch },
- { SKIN_KEY_COMMAND_BUTTON_MENU, kKeyCodeMenu },
- { SKIN_KEY_COMMAND_BUTTON_DPAD_UP, kKeyCodeDpadUp },
- { SKIN_KEY_COMMAND_BUTTON_DPAD_LEFT, kKeyCodeDpadLeft },
- { SKIN_KEY_COMMAND_BUTTON_DPAD_RIGHT, kKeyCodeDpadRight },
- { SKIN_KEY_COMMAND_BUTTON_DPAD_DOWN, kKeyCodeDpadDown },
- { SKIN_KEY_COMMAND_BUTTON_DPAD_CENTER, kKeyCodeDpadCenter },
- { SKIN_KEY_COMMAND_BUTTON_VOLUME_UP, kKeyCodeVolumeUp },
- { SKIN_KEY_COMMAND_BUTTON_VOLUME_DOWN, kKeyCodeVolumeDown },
- { SKIN_KEY_COMMAND_BUTTON_CAMERA, kKeyCodeCamera },
- { SKIN_KEY_COMMAND_NONE, 0 }
- };
- int nn;
-#ifdef CONFIG_TRACE
- static int tracing = 0;
-#endif
- QEmulator* emulator = opaque;
-
-
- for (nn = 0; keycodes[nn].kcode != 0; nn++) {
- if (command == keycodes[nn].cmd) {
- unsigned code = keycodes[nn].kcode;
- if (down)
- code |= 0x200;
- kbd_put_keycode( code );
- return;
- }
- }
-
- // for the show-trackball command, handle down events to enable, and
- // up events to disable
- if (command == SKIN_KEY_COMMAND_SHOW_TRACKBALL) {
- emulator->show_trackball = (down != 0);
- skin_window_show_trackball( emulator->window, emulator->show_trackball );
- //qemulator_set_title( emulator );
- return;
- }
-
- // only handle down events for the rest
- if (down == 0)
- return;
-
- switch (command)
- {
- case SKIN_KEY_COMMAND_TOGGLE_NETWORK:
- {
- qemu_net_disable = !qemu_net_disable;
- if (android_modem) {
- amodem_set_data_registration(
- android_modem,
- qemu_net_disable ? A_REGISTRATION_UNREGISTERED
- : A_REGISTRATION_HOME);
- }
- D( "network is now %s", qemu_net_disable ? "disconnected" : "connected" );
- }
- break;
-
- case SKIN_KEY_COMMAND_TOGGLE_FULLSCREEN:
- if (emulator->window) {
- skin_window_toggle_fullscreen(emulator->window);
- }
- break;
-
- case SKIN_KEY_COMMAND_TOGGLE_TRACING:
- {
-#ifdef CONFIG_TRACE
- tracing = !tracing;
- if (tracing)
- start_tracing();
- else
- stop_tracing();
-#endif
- }
- break;
-
- case SKIN_KEY_COMMAND_TOGGLE_TRACKBALL:
- emulator->show_trackball = !emulator->show_trackball;
- skin_window_show_trackball( emulator->window, emulator->show_trackball );
- qemulator_set_title(emulator);
- break;
-
- case SKIN_KEY_COMMAND_ONION_ALPHA_UP:
- case SKIN_KEY_COMMAND_ONION_ALPHA_DOWN:
- if (emulator->onion)
- {
- int alpha = emulator->onion_alpha;
-
- if (command == SKIN_KEY_COMMAND_ONION_ALPHA_UP)
- alpha += 16;
- else
- alpha -= 16;
-
- if (alpha > 256)
- alpha = 256;
- else if (alpha < 0)
- alpha = 0;
-
- emulator->onion_alpha = alpha;
- skin_window_set_onion( emulator->window, emulator->onion, emulator->onion_rotation, alpha );
- skin_window_redraw( emulator->window, NULL );
- //dprint( "onion alpha set to %d (%.f %%)", alpha, alpha/2.56 );
- }
- break;
-
- case SKIN_KEY_COMMAND_CHANGE_LAYOUT_PREV:
- case SKIN_KEY_COMMAND_CHANGE_LAYOUT_NEXT:
- {
- SkinLayout* layout = NULL;
-
- if (command == SKIN_KEY_COMMAND_CHANGE_LAYOUT_NEXT) {
- layout = emulator->layout->next;
- if (layout == NULL)
- layout = emulator->layout_file->layouts;
- }
- else if (command == SKIN_KEY_COMMAND_CHANGE_LAYOUT_PREV) {
- layout = emulator->layout_file->layouts;
- while (layout->next && layout->next != emulator->layout)
- layout = layout->next;
- }
- if (layout != NULL) {
- SkinRotation rotation;
-
- emulator->layout = layout;
- skin_window_reset( emulator->window, layout );
-
- rotation = skin_layout_get_dpad_rotation( layout );
-
- if (emulator->keyboard)
- skin_keyboard_set_rotation( emulator->keyboard, rotation );
-
- if (emulator->trackball) {
- skin_trackball_set_rotation( emulator->trackball, rotation );
- skin_window_set_trackball( emulator->window, emulator->trackball );
- skin_window_show_trackball( emulator->window, emulator->show_trackball );
- }
-
- skin_window_set_lcd_brightness( emulator->window, emulator->lcd_brightness );
-
- qframebuffer_invalidate_all();
- qframebuffer_check_updates();
- }
- }
- break;
-
- default:
- /* XXX: TODO ? */
- ;
- }
-}
-
-
static void sdl_at_exit(void)
{
emulator_config_done();
@@ -551,8 +259,8 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
{
QEmulator* emulator = qemulator_get();
SkinDisplay* disp = skin_layout_get_display(emulator->layout);
- DisplayChangeListener* dcl;
int width, height;
+ char buf[128];
if (disp->rotation & 1) {
width = disp->rect.size.h;
@@ -562,22 +270,8 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
height = disp->rect.size.h;
}
- /* Register a display state object for the emulated framebuffer */
- ds->allocator = &default_allocator;
- ds->opaque = emulator;
- ds->surface = qemu_create_displaysurface(ds, width, height);
- register_displaystate(ds);
-
- /* Register a change listener for it */
- dcl = (DisplayChangeListener *) qemu_mallocz(sizeof(DisplayChangeListener));
- dcl->dpy_update = sdl_update;
- dcl->dpy_resize = sdl_resize;
- dcl->dpy_refresh = sdl_refresh;
- dcl->dpy_text_cursor = NULL;
- register_displaychangelistener(ds, dcl);
-
- skin_keyboard_enable( emulator->keyboard, 1 );
- skin_keyboard_on_command( emulator->keyboard, handle_key_command, emulator );
+ snprintf(buf, sizeof buf, "width=%d,height=%d", width, height);
+ android_display_init(ds, qframebuffer_fifo_get());
}
diff --git a/android/qemulator.c b/android/qemulator.c
index 7d2d2e8..f6dc550 100644
--- a/android/qemulator.c
+++ b/android/qemulator.c
@@ -15,6 +15,7 @@
#include "android/globals.h"
#include "android/qemulator.h"
#include "android/ui-core-protocol.h"
+#include "user-events.h"
#define D(...) do { if (VERBOSE_CHECK(init)) dprint(__VA_ARGS__); } while (0)
static double get_default_scale( AndroidOptions* opts );
@@ -22,6 +23,9 @@ static double get_default_scale( AndroidOptions* opts );
/* QEmulator structure instance. */
static QEmulator qemulator[1];
+static void handle_key_command( void* opaque, SkinKeyCommand command, int param );
+static void qemulator_refresh(QEmulator* emulator);
+
static void
qemulator_light_brightness( void* opaque, const char* light, int value )
{
@@ -98,11 +102,18 @@ qemulator_fb_update( void* _emulator, int x, int y, int w, int h )
static void
qemulator_fb_rotate( void* _emulator, int rotation )
{
- QEmulator* emulator = _emulator;
+ QEmulator* emulator = _emulator;
qemulator_setup( emulator );
}
+static void
+qemulator_fb_poll( void* _emulator )
+{
+ QEmulator* emulator = _emulator;
+ qemulator_refresh(emulator);
+}
+
QEmulator*
qemulator_get(void)
{
@@ -141,12 +152,17 @@ qemulator_init( QEmulator* emulator,
SkinDisplay* disp = part->display;
if (disp->valid) {
qframebuffer_add_client( disp->qfbuff,
- emulator,
- qemulator_fb_update,
- qemulator_fb_rotate,
- NULL );
+ emulator,
+ qemulator_fb_update,
+ qemulator_fb_rotate,
+ qemulator_fb_poll,
+ NULL );
}
SKIN_FILE_LOOP_END_PARTS
+
+ skin_keyboard_enable( emulator->keyboard, 1 );
+ skin_keyboard_on_command( emulator->keyboard, handle_key_command, emulator );
+
return 0;
}
@@ -301,6 +317,260 @@ get_default_scale( AndroidOptions* opts )
return scale;
}
+/* used to respond to a given keyboard command shortcut
+ */
+static void
+handle_key_command( void* opaque, SkinKeyCommand command, int down )
+{
+ static const struct { SkinKeyCommand cmd; AndroidKeyCode kcode; } keycodes[] =
+ {
+ { SKIN_KEY_COMMAND_BUTTON_CALL, kKeyCodeCall },
+ { SKIN_KEY_COMMAND_BUTTON_HOME, kKeyCodeHome },
+ { SKIN_KEY_COMMAND_BUTTON_BACK, kKeyCodeBack },
+ { SKIN_KEY_COMMAND_BUTTON_HANGUP, kKeyCodeEndCall },
+ { SKIN_KEY_COMMAND_BUTTON_POWER, kKeyCodePower },
+ { SKIN_KEY_COMMAND_BUTTON_SEARCH, kKeyCodeSearch },
+ { SKIN_KEY_COMMAND_BUTTON_MENU, kKeyCodeMenu },
+ { SKIN_KEY_COMMAND_BUTTON_DPAD_UP, kKeyCodeDpadUp },
+ { SKIN_KEY_COMMAND_BUTTON_DPAD_LEFT, kKeyCodeDpadLeft },
+ { SKIN_KEY_COMMAND_BUTTON_DPAD_RIGHT, kKeyCodeDpadRight },
+ { SKIN_KEY_COMMAND_BUTTON_DPAD_DOWN, kKeyCodeDpadDown },
+ { SKIN_KEY_COMMAND_BUTTON_DPAD_CENTER, kKeyCodeDpadCenter },
+ { SKIN_KEY_COMMAND_BUTTON_VOLUME_UP, kKeyCodeVolumeUp },
+ { SKIN_KEY_COMMAND_BUTTON_VOLUME_DOWN, kKeyCodeVolumeDown },
+ { SKIN_KEY_COMMAND_BUTTON_CAMERA, kKeyCodeCamera },
+ { SKIN_KEY_COMMAND_NONE, 0 }
+ };
+ int nn;
+#ifdef CONFIG_TRACE
+ static int tracing = 0;
+#endif
+ QEmulator* emulator = opaque;
+
+
+ for (nn = 0; keycodes[nn].kcode != 0; nn++) {
+ if (command == keycodes[nn].cmd) {
+ unsigned code = keycodes[nn].kcode;
+ if (down)
+ code |= 0x200;
+ user_event_keycode( code );
+ return;
+ }
+ }
+
+ // for the show-trackball command, handle down events to enable, and
+ // up events to disable
+ if (command == SKIN_KEY_COMMAND_SHOW_TRACKBALL) {
+ emulator->show_trackball = (down != 0);
+ skin_window_show_trackball( emulator->window, emulator->show_trackball );
+ //qemulator_set_title( emulator );
+ return;
+ }
+
+ // only handle down events for the rest
+ if (down == 0)
+ return;
+
+ switch (command)
+ {
+ case SKIN_KEY_COMMAND_TOGGLE_NETWORK:
+ {
+ qemu_net_disable = !qemu_net_disable;
+ android_core_set_network_enabled(!qemu_net_disable);
+ D( "network is now %s", qemu_net_disable ? "disconnected" : "connected" );
+ }
+ break;
+
+ case SKIN_KEY_COMMAND_TOGGLE_FULLSCREEN:
+ if (emulator->window) {
+ skin_window_toggle_fullscreen(emulator->window);
+ }
+ break;
+
+ case SKIN_KEY_COMMAND_TOGGLE_TRACING:
+ {
+#ifdef CONFIG_TRACE
+ tracing = !tracing;
+ if (tracing)
+ android_core_tracing_start();
+ else
+ android_core_tracing_stop();
+#endif
+ }
+ break;
+
+ case SKIN_KEY_COMMAND_TOGGLE_TRACKBALL:
+ emulator->show_trackball = !emulator->show_trackball;
+ skin_window_show_trackball( emulator->window, emulator->show_trackball );
+ qemulator_set_title(emulator);
+ break;
+
+ case SKIN_KEY_COMMAND_ONION_ALPHA_UP:
+ case SKIN_KEY_COMMAND_ONION_ALPHA_DOWN:
+ if (emulator->onion)
+ {
+ int alpha = emulator->onion_alpha;
+
+ if (command == SKIN_KEY_COMMAND_ONION_ALPHA_UP)
+ alpha += 16;
+ else
+ alpha -= 16;
+
+ if (alpha > 256)
+ alpha = 256;
+ else if (alpha < 0)
+ alpha = 0;
+
+ emulator->onion_alpha = alpha;
+ skin_window_set_onion( emulator->window, emulator->onion, emulator->onion_rotation, alpha );
+ skin_window_redraw( emulator->window, NULL );
+ //dprint( "onion alpha set to %d (%.f %%)", alpha, alpha/2.56 );
+ }
+ break;
+
+ case SKIN_KEY_COMMAND_CHANGE_LAYOUT_PREV:
+ case SKIN_KEY_COMMAND_CHANGE_LAYOUT_NEXT:
+ {
+ SkinLayout* layout = NULL;
+
+ if (command == SKIN_KEY_COMMAND_CHANGE_LAYOUT_NEXT) {
+ layout = emulator->layout->next;
+ if (layout == NULL)
+ layout = emulator->layout_file->layouts;
+ }
+ else if (command == SKIN_KEY_COMMAND_CHANGE_LAYOUT_PREV) {
+ layout = emulator->layout_file->layouts;
+ while (layout->next && layout->next != emulator->layout)
+ layout = layout->next;
+ }
+ if (layout != NULL) {
+ SkinRotation rotation;
+
+ emulator->layout = layout;
+ skin_window_reset( emulator->window, layout );
+
+ rotation = skin_layout_get_dpad_rotation( layout );
+
+ if (emulator->keyboard)
+ skin_keyboard_set_rotation( emulator->keyboard, rotation );
+
+ if (emulator->trackball) {
+ skin_trackball_set_rotation( emulator->trackball, rotation );
+ skin_window_set_trackball( emulator->window, emulator->trackball );
+ skin_window_show_trackball( emulator->window, emulator->show_trackball );
+ }
+
+ skin_window_set_lcd_brightness( emulator->window, emulator->lcd_brightness );
+
+ qframebuffer_invalidate_all();
+ qframebuffer_check_updates();
+ }
+ }
+ break;
+
+ default:
+ /* XXX: TODO ? */
+ ;
+ }
+}
+
+/* called periodically to poll for user input events */
+static void qemulator_refresh(QEmulator* emulator)
+{
+ SDL_Event ev;
+ SkinWindow* window = emulator->window;
+ SkinKeyboard* keyboard = emulator->keyboard;
+
+ /* this will eventually call sdl_update if the content of the VGA framebuffer
+ * has changed */
+ qframebuffer_check_updates();
+
+ if (window == NULL)
+ return;
+
+ while(SDL_PollEvent(&ev)){
+ switch(ev.type){
+ case SDL_VIDEOEXPOSE:
+ skin_window_redraw( window, NULL );
+ break;
+
+ case SDL_KEYDOWN:
+#ifdef _WIN32
+ /* special code to deal with Alt-F4 properly */
+ if (ev.key.keysym.sym == SDLK_F4 &&
+ ev.key.keysym.mod & KMOD_ALT) {
+ goto CleanExit;
+ }
+#endif
+#ifdef __APPLE__
+ /* special code to deal with Command-Q properly */
+ if (ev.key.keysym.sym == SDLK_q &&
+ ev.key.keysym.mod & KMOD_META) {
+ goto CleanExit;
+ }
+#endif
+ skin_keyboard_process_event( keyboard, &ev, 1 );
+ break;
+
+ case SDL_KEYUP:
+ skin_keyboard_process_event( keyboard, &ev, 0 );
+ break;
+
+ case SDL_MOUSEMOTION:
+ skin_window_process_event( window, &ev );
+ break;
+
+ case SDL_MOUSEBUTTONDOWN:
+ case SDL_MOUSEBUTTONUP:
+ {
+ int down = (ev.type == SDL_MOUSEBUTTONDOWN);
+ if (ev.button.button == 4)
+ {
+ /* scroll-wheel simulates DPad up */
+ AndroidKeyCode kcode;
+
+ kcode = // qemulator_rotate_keycode(kKeyCodeDpadUp);
+ android_keycode_rotate(kKeyCodeDpadUp,
+ skin_layout_get_dpad_rotation(qemulator_get_layout(qemulator_get())));
+ user_event_key( kcode, down );
+ }
+ else if (ev.button.button == 5)
+ {
+ /* scroll-wheel simulates DPad down */
+ AndroidKeyCode kcode;
+
+ kcode = // qemulator_rotate_keycode(kKeyCodeDpadDown);
+ android_keycode_rotate(kKeyCodeDpadDown,
+ skin_layout_get_dpad_rotation(qemulator_get_layout(qemulator_get())));
+ user_event_key( kcode, down );
+ }
+ else if (ev.button.button == SDL_BUTTON_LEFT) {
+ skin_window_process_event( window, &ev );
+ }
+#if 0
+ else {
+ fprintf(stderr, "... mouse button %s: button=%d state=%04x x=%d y=%d\n",
+ down ? "down" : "up ",
+ ev.button.button, ev.button.state, ev.button.x, ev.button.y);
+ }
+#endif
+ }
+ break;
+
+ case SDL_QUIT:
+#if defined _WIN32 || defined __APPLE__
+ CleanExit:
+#endif
+ /* only save emulator config through clean exit */
+ qemulator_done(qemulator_get());
+ qemu_system_shutdown_request();
+ return;
+ }
+ }
+
+ skin_keyboard_flush( keyboard );
+}
+
/*
* android/console.c helper routines.
*/
diff --git a/android/skin/window.c b/android/skin/window.c
index 4765bba..48e5916 100644
--- a/android/skin/window.c
+++ b/android/skin/window.c
@@ -1220,15 +1220,6 @@ skin_window_reset_internal ( SkinWindow* window, SkinLayout* slayout )
skin_window_redraw( window, NULL );
- if (slayout->event_type != 0) {
- user_event_generic( slayout->event_type, slayout->event_code, slayout->event_value );
- /* XXX: hack, replace by better code here */
- if (slayout->event_value != 0)
- android_sensors_set_coarse_orientation( ANDROID_COARSE_PORTRAIT );
- else
- android_sensors_set_coarse_orientation( ANDROID_COARSE_LANDSCAPE );
- }
-
return 0;
}
@@ -1238,7 +1229,18 @@ skin_window_reset ( SkinWindow* window, SkinLayout* slayout )
if (!window->fullscreen) {
SDL_WM_GetPos(&window->x_pos, &window->y_pos);
}
- return skin_window_reset_internal( window, slayout );
+ if (skin_window_reset_internal( window, slayout ) < 0)
+ return -1;
+
+ if (slayout->event_type != 0) {
+ user_event_generic( slayout->event_type, slayout->event_code, slayout->event_value );
+ /* XXX: hack, replace by better code here */
+ if (slayout->event_value != 0)
+ android_sensors_set_coarse_orientation( ANDROID_COARSE_PORTRAIT );
+ else
+ android_sensors_set_coarse_orientation( ANDROID_COARSE_LANDSCAPE );
+ }
+ return 0;
}
void
diff --git a/android/ui-core-protocol.c b/android/ui-core-protocol.c
index c62f09e..3e4fdcc 100644
--- a/android/ui-core-protocol.c
+++ b/android/ui-core-protocol.c
@@ -23,6 +23,8 @@
#include "android/globals.h"
#include "android/hw-control.h"
#include "android/ui-core-protocol.h"
+#include "telephony/modem_driver.h"
+#include "trace.h"
int
android_core_get_hw_lcd_density(void)
@@ -45,3 +47,25 @@ android_core_get_base_port(void)
{
return android_base_port;
}
+
+void
+android_core_set_network_enabled(int enabled)
+{
+ if (android_modem) {
+ amodem_set_data_registration(
+ android_modem,
+ qemu_net_disable ? A_REGISTRATION_UNREGISTERED
+ : A_REGISTRATION_HOME);
+ }
+}
+
+void android_core_tracing_start(void)
+{
+ start_tracing();
+}
+
+void android_core_tracing_stop(void)
+{
+ stop_tracing();
+}
+
diff --git a/android/ui-core-protocol.h b/android/ui-core-protocol.h
index 7b12f24..4ec025f 100644
--- a/android/ui-core-protocol.h
+++ b/android/ui-core-protocol.h
@@ -40,4 +40,11 @@ void android_core_set_brightness_change_callback(AndroidHwLightBrightnessCallbac
/* Returns base port assigned for the emulated system. */
int android_core_get_base_port(void);
+/* Sets/toggles the network state */
+void android_core_set_network_enabled(int enabled);
+
+/* Start/stop tracing in the guest system */
+void android_core_tracing_start(void);
+void android_core_tracing_stop(void);
+
#endif // QEMU_ANDROID_UI_CORE_PROTOCOL_H
diff --git a/console.h b/console.h
index 3d0c4f4..fd283ba 100644
--- a/console.h
+++ b/console.h
@@ -330,4 +330,9 @@ char *vnc_display_local_addr(DisplayState *ds);
/* curses.c */
void curses_display_init(DisplayState *ds, int full_screen);
+#if defined(CONFIG_ANDROID)
+/* android-display.c */
+void android_display_init(DisplayState *ds);
+#endif
+
#endif
diff --git a/docs/DISPLAY-STATE.TXT b/docs/DISPLAY-STATE.TXT
new file mode 100644
index 0000000..b76376f
--- /dev/null
+++ b/docs/DISPLAY-STATE.TXT
@@ -0,0 +1,263 @@
+This tries to document the mess that is DisplayState in QEMU.
+See "console.h" for the main definitions, and below for some
+explanations:
+
+
+DISPLAY STATE OBJECTS:
+======================
+
+A DisplayState holds state for stuff to be displayed on QEMU. More
+precisely:
+
+ - A DisplayState owns a 'DisplaySurface' which is nothing more than a
+ pixel buffer with specific dimensions, pitch and format plus bytes
+ to carry its content.
+
+ - A DisplayState also holds a 'DisplayAllocator' which allows it to
+ allocate its surface through a proper API. For example, this is
+ used in the upstream sdl UI backend to allocate the surface pixels
+ through SDL_SetVideoMode(). The default allocator simply uses
+ 'malloc' to do the allocation (with 32-bits/pixel).
+
+ - A DisplayState also holds a list of DisplayChangeListener object.
+ Each listener contains a small set of callbacks that will be called
+ whenever an "event" happens on the display state. Events examples
+ are:
+
+ dpy_update: a rectangular portion of the surface has been updated.
+ dpy_resize: the hardware decided to resize the framebuffer.
+ dpy_refresh: called periodically by the GUI timer.
+ dpy_copy: the hardware performed a rectangular copy operation.
+ dpy_fill: the hardware performed a rectangular fill operation.
+ dpy_setdata: the hardware decided to change the framebuffer address.
+ dpy_text_cursor: the hardware placed the text cursor at a given (x,y).
+
+ NOTE: dpy_setdata is essentially the same than dpy_resize except that
+ there is a guarantee that the size didn't change.
+
+ More on DisplayChangeListeners below.
+
+ - The file "console.h" provides many helper functions to call all listeners
+ registered for a given DisplayState. For example, dpy_update(ds,x,y,w,h)
+ will call the 'dpy_update' callback of all listeners for the display
+ state 'ds'.
+
+
+CONSOLES:
+=========
+
+A "console" is something that can write pixels into a DisplayState.
+There are two kinds of consoles, and they're fairly different in usage.
+
+ GRAPHICAL CONSOLE:
+ ------------------
+
+ A "Graphical console" creates and owns a DisplayState. It is used when one
+ needs to write directly to the DisplaySurface pixel buffer. A typical
+ hardware framebuffer emulator (e.g. hw/vga-pic.c) will call the
+ function graphic_console_init() to create the DisplayState. Note that
+ this functions accepts several callbacks and is defined as:
+
+ typedef void (*vga_hw_update_ptr)(void *);
+ typedef void (*vga_hw_invalidate_ptr)(void *);
+ typedef void (*vga_hw_screen_dump_ptr)(void *, const char *);
+ typedef void (*vga_hw_text_update_ptr)(void *, console_ch_t *);
+
+ DisplayState *graphic_console_init(vga_hw_update_ptr update,
+ vga_hw_invalidate_ptr invalidate,
+ vga_hw_screen_dump_ptr screen_dump,
+ vga_hw_text_update_ptr text_update,
+ void *opaque);
+
+ The update/invalidate/screen_dump/text_update functions must be provided
+ by the hardware framebuffer emulation, and will be called under various
+ circumstances:
+
+ 'update' is called periodically to check for any hw framebuffer
+ updates (and then copy them to the DisplayState, to finally send
+ them through dpy_update() to the listeners).
+
+ 'invalidate' is called to indicate that the next call to 'update'
+ should send the content of _all_ the framebuffer, instead of only
+ the smallest possible update.
+
+ 'screen_dump' is called to force a screen dump (i.e. print the
+ content of the framebuffer to a ppm file, which name is passed as
+ a parameter).
+
+ 'text_update' is called to display one single character. XXX: Code is
+ not very clear, but probably related to text console.
+
+
+ TEXT CONSOLES:
+ --------------
+
+ A "Text console" attaches to an existing DisplayState, and is able to
+ take over its rendering in order to display a text *terminal*. It's not
+ sure whether this emulates VT101 or something else (see the code inside
+ the console_putchar() for all the gory details), but the main idea is
+ that you create a console with a call to:
+
+ CharDriverState* text_console_init(const char* p);
+
+ The function returns a CharDriverState* (see docs/CHAR-DEVICES.TXT) that
+ will be connected to a host device identified by the string in 'p'. This
+ allows you, for example, to connect the console to stdio.
+
+ The text console code is capable of producing a bitmap each time you update
+ its content (i.e. it includes code to manage fixed-size font rendering,
+ scrolling, escape sequences, color, blinking cursor, etc...).
+
+ - By default, the graphics console writes to its DisplayState, but you can
+ use console_select() to change that at runtime. This function can be used
+ to force switching between virtual terminals and the graphics display.
+ There can be several text consoles associated to a single DisplayState
+ object.
+
+
+DISPLAY CHANGE LISTENERES:
+==========================
+
+There QEMU sources provide the implementation for various
+DisplayChangeListeners, most notables are the following:
+
+ - In sdl.c: This one uses the SDL library to display the content of a
+ DisplaySurface through a SDL_Window. The implementation also supports
+ zooming the output to an arbitrary size (using SDL functions).
+
+ - In vnc.c: This listener implements a VNC Server that can be used to
+ display the DisplaySurface remotely through the RDP protocol.
+
+ - In curses.c: This listener is used to display text consoles through the
+ "curses" library on Unix systems. It cannot be used to display any
+ graphics though.
+
+NOTE: The initialization sequence in vl.c only allows for a single listener
+on the main display state, but the rest of the code deals with several
+listeners per DisplayState just fine.
+
+Each DisplayChangeListener can specify a refresh period (e.g. every 1/60th
+of second). QEMU will then create a timer that will be programmed to called
+the listener's 'dpy_refresh' callback periodically. The point of this
+callback is to perform the following:
+
+- poll for new user input events from the underlying UI (e.g. from the SDL
+ event loop, or from the network for VNC). These should be translated into
+ guest event codes with functions like 'kbd_put_keycode' or 'kbd_mouse_event'.
+
+- call the global vga_hw_update() function. It will, if the graphics console
+ is being displayed, call the 'update' callback that was passed to
+ graphic_console_init(). If a text console is being displayed, the does
+ nothing.
+
+- eventually call the global vga_hw_invalidate() to indicate that the whole
+ framebuffer content should be resent as an update. This can happen when a
+ UI window was minimized and is made visible again, for example.
+
+
+INITIALIZATION AND RUNTIME EXECUTION:
+=====================================
+
+Initialization happens in the qemu main() function in the vl.c source file.
+
+First, the hardware machine is initialized. The hardware fraembuffer emulation
+shall call graphic_console_init() to create a new DisplayState. Note that the
+object returned by this function has a default DisplaySurface of 640x480 pixels
+allocated through malloc(). In other words, the hardware emulation does not
+set the size of the display state by default!
+
+After that, the listener's initialization function (e.g. sdl_display_init)
+is called. It is passed the DisplayState object and can replace the
+corresponding DisplaySurface with another one with proper dimensions, and
+eventually created with a different DisplayAllocator. It also registers a
+DisplayChangeListener to receive later state changes.
+
+Note that the VNC listener doesn't change the dimension of the DisplayState
+surface it is initialized with. However, it will react to dpy_resize events
+accordingly.
+
+NOTE: dpy_resize()s are currently only generated when switching between
+consoles, or when the framebuffer's size is modified by the guest kernel.
+
+
+The GUI timer, corresponding to the first listener than has one refresh
+period, drives the whole update process (if no listener provides a refresh
+period, a default 'no_graphic' timer is setup with a default refresh period
+of 30 frame/s).
+
+Things happen in this order:
+
+ - the GUI timer kicks in, and calls the 'dpy_refresh()' callback of
+ the listener (each listener has its own timer, btw).
+
+ - the listener callback polls for user events, and calls vga_hw_update()
+ to see if there are hardware framebuffer updates.
+
+ - vga_hw_update() checks that the graphics console is displayed (otherwise
+ it exits)
+
+ - it then calls the graphics console's 'update' callback
+
+ - the callback, implemented by the framebuffer hw emulation, checks for
+ dirty pages in order to detect what changed since it was invoked.
+
+ For every rectangle of the hw framebuffer that was modified, it copies
+ the pixels from VRAM into the DisplayState's surface buffer (eventually
+ performing format conversion at the same time).
+
+ After that, it calls dpy_update() to send the update to all registered
+ listeners for the DisplayState.
+
+ - The listener's 'dpy_update' callback is called and receives a pointer
+ to the DisplayState, and the rectangle corresponding to the update. Its
+ implementation can then update the content of the screen (or the internal
+ VNC framebuffer).
+
+Eventually, hardware emulation can also trigger other dpy_xxxx events (e.g.
+dpy_resize, dpy_copy, dpy_fill....)
+
+Here's a simplified diagram of what happens in the typical case:
+
+ _____________
+ | |
+ | hardware |
+ | framebuffer |-------+
+ | | |
+ |_____________| |
+ ^ |
+ | |
+ | 3/ ds.update() | 4/ dpy_update(ds,x,y,w,h)
+ | |
+ | |
+ _____________ |
+ | | |
+ | Display | <-----+
+ | State |
+ | | ----------+
+ |_____________| |
+ ^ |
+ | |
+ | 2/ vga_hw_update() |
+ | |
+ | |
+ | |
+ | +---------------+
+ | | |
+ | | 5/listener.dpy_update(ds,x,y,w,h)
+ | | |
+ | | | 6/listener.dpy_update(...)
+ | | |
+ | v v
+ _____________ _____________
+ | | | |
+ | SDL | | VNC |
+ | Listener | | Listener |
+ | | | |
+ |_____________| |_____________|
+ ^
+ |
+ | 1/ listener.dpy_refresh()
+ |
+
+ GUI timer
+
diff --git a/framebuffer.c b/framebuffer.c
index d0f9b40..adbebb3 100644
--- a/framebuffer.c
+++ b/framebuffer.c
@@ -19,6 +19,7 @@ typedef struct {
void* fb_opaque;
QFrameBufferUpdateFunc fb_update;
QFrameBufferRotateFunc fb_rotate;
+ QFrameBufferPollFunc fb_poll;
QFrameBufferDoneFunc fb_done;
void* pr_opaque;
@@ -122,6 +123,7 @@ qframebuffer_add_client( QFrameBuffer* qfbuff,
void* fb_opaque,
QFrameBufferUpdateFunc fb_update,
QFrameBufferRotateFunc fb_rotate,
+ QFrameBufferPollFunc fb_poll,
QFrameBufferDoneFunc fb_done )
{
QFrameBufferExtra* extra = qfbuff->extra;
@@ -129,6 +131,7 @@ qframebuffer_add_client( QFrameBuffer* qfbuff,
extra->fb_opaque = fb_opaque;
extra->fb_update = fb_update;
extra->fb_rotate = fb_rotate;
+ extra->fb_poll = fb_poll;
extra->fb_done = fb_done;
}
@@ -170,6 +173,15 @@ qframebuffer_rotate( QFrameBuffer* qfbuff, int rotation )
extra->fb_rotate( extra->fb_opaque, rotation );
}
+void
+qframebuffer_poll( QFrameBuffer* qfbuff )
+{
+ QFrameBufferExtra* extra = qfbuff->extra;
+
+ if (extra->fb_poll)
+ extra->fb_poll( extra->fb_opaque );
+}
+
extern void
qframebuffer_done( QFrameBuffer* qfbuff )
diff --git a/framebuffer.h b/framebuffer.h
index 1dce0d9..9e99d26 100644
--- a/framebuffer.h
+++ b/framebuffer.h
@@ -106,6 +106,13 @@ typedef void (*QFrameBufferUpdateFunc)( void* opaque, int x, int y,
*/
typedef void (*QFrameBufferRotateFunc)( void* opaque, int rotation );
+/* the Client::Poll method is called periodically to poll for input
+ * events and act on them. Putting this here is not 100% pure but
+ * make things simpler due to QEMU's weird architecture where the
+ * GUI timer drivers event polling.
+ */
+typedef void (*QFrameBufferPollFunc)( void* opaque );
+
/* the Client::Done func tells a client that a framebuffer object was freed.
* no more reference to its pixels should be done.
*/
@@ -121,6 +128,7 @@ qframebuffer_add_client( QFrameBuffer* qfbuff,
void* fb_opaque,
QFrameBufferUpdateFunc fb_update,
QFrameBufferRotateFunc fb_rotate,
+ QFrameBufferPollFunc fb_poll,
QFrameBufferDoneFunc fb_done );
/* Producer::CheckUpdate is called to let the producer check the
@@ -161,6 +169,9 @@ qframebuffer_update( QFrameBuffer* qfbuff, int x, int y, int w, int h );
extern void
qframebuffer_rotate( QFrameBuffer* qfbuff, int rotation );
+extern void
+qframebuffer_poll( QFrameBuffer* qfbuff );
+
/* finalize a framebuffer, release its pixel buffer. Should be called
* from the framebuffer object's owner
*/
diff --git a/hw/android_arm.c b/hw/android_arm.c
index f5df7f2..d805b0e 100644
--- a/hw/android_arm.c
+++ b/hw/android_arm.c
@@ -70,7 +70,6 @@ static void android_arm_init_(ram_addr_t ram_size,
int i;
struct arm_boot_info info;
ram_addr_t ram_offset;
- DisplayState* ds = get_displaystate();
if (!cpu_model)
cpu_model = "arm926";
@@ -116,7 +115,7 @@ static void android_arm_init_(ram_addr_t ram_size,
}
}
- goldfish_fb_init(ds, 0);
+ goldfish_fb_init(0);
#ifdef HAS_AUDIO
goldfish_audio_init(0xff004000, 0, audio_input_source);
#endif
diff --git a/hw/goldfish_device.h b/hw/goldfish_device.h
index d04a166..19f4b32 100644
--- a/hw/goldfish_device.h
+++ b/hw/goldfish_device.h
@@ -41,7 +41,7 @@ int goldfish_device_bus_init(uint32_t base, uint32_t irq);
qemu_irq *goldfish_interrupt_init(uint32_t base, qemu_irq parent_irq, qemu_irq parent_fiq);
void goldfish_timer_and_rtc_init(uint32_t timerbase, int timerirq);
int goldfish_tty_add(CharDriverState *cs, int id, uint32_t base, int irq);
-void goldfish_fb_init(DisplayState *ds, int id);
+void goldfish_fb_init(int id);
void goldfish_audio_init(uint32_t base, int id, const char* input_source);
void goldfish_battery_init();
void goldfish_battery_set_prop(int ac, int property, int value);
diff --git a/hw/goldfish_events_device.c b/hw/goldfish_events_device.c
index 9e98dac..3f5bf0b 100644
--- a/hw/goldfish_events_device.c
+++ b/hw/goldfish_events_device.c
@@ -102,7 +102,7 @@ static void enqueue_event(events_state *s, unsigned int type, unsigned int code,
return;
}
- if(s->first == s->last){
+ if(s->first == s->last) {
qemu_irq_raise(s->irq);
}
diff --git a/hw/goldfish_fb.c b/hw/goldfish_fb.c
index d092fe4..8300e7c 100644
--- a/hw/goldfish_fb.c
+++ b/hw/goldfish_fb.c
@@ -12,7 +12,7 @@
#include "qemu_file.h"
#include "android/android.h"
#include "goldfish_device.h"
-#include "framebuffer.h"
+#include "console.h"
enum {
FB_GET_WIDTH = 0x00,
@@ -31,7 +31,7 @@ enum {
struct goldfish_fb_state {
struct goldfish_device dev;
- QFrameBuffer* qfbuff;
+ DisplayState* ds;
uint32_t fb_base;
uint32_t base_valid : 1;
uint32_t need_update : 1;
@@ -41,20 +41,21 @@ struct goldfish_fb_state {
uint32_t int_status;
uint32_t int_enable;
int rotation; /* 0, 1, 2 or 3 */
+ int dpi;
};
-#define GOLDFISH_FB_SAVE_VERSION 1
+#define GOLDFISH_FB_SAVE_VERSION 2
static void goldfish_fb_save(QEMUFile* f, void* opaque)
{
struct goldfish_fb_state* s = opaque;
- QFrameBuffer* q = s->qfbuff;
+ DisplayState* ds = s->ds;
- qemu_put_be32(f, q->width);
- qemu_put_be32(f, q->height);
- qemu_put_be32(f, q->pitch);
- qemu_put_byte(f, q->rotation);
+ qemu_put_be32(f, ds->surface->width);
+ qemu_put_be32(f, ds->surface->height);
+ qemu_put_be32(f, ds->surface->linesize);
+ qemu_put_byte(f, 0);
qemu_put_be32(f, s->fb_base);
qemu_put_byte(f, s->base_valid);
@@ -65,13 +66,12 @@ static void goldfish_fb_save(QEMUFile* f, void* opaque)
qemu_put_be32(f, s->int_status);
qemu_put_be32(f, s->int_enable);
qemu_put_be32(f, s->rotation);
+ qemu_put_be32(f, s->dpi);
}
static int goldfish_fb_load(QEMUFile* f, void* opaque, int version_id)
{
struct goldfish_fb_state* s = opaque;
-
- QFrameBuffer* q = s->qfbuff;
int ret = -1;
int ds_w, ds_h, ds_pitch, ds_rot;
@@ -83,10 +83,12 @@ static int goldfish_fb_load(QEMUFile* f, void* opaque, int version_id)
ds_pitch = qemu_get_be32(f);
ds_rot = qemu_get_byte(f);
- if (q->width != ds_w ||
- q->height != ds_h ||
- q->pitch != ds_pitch ||
- q->rotation != ds_rot )
+ DisplayState* ds = s->ds;
+
+ if (ds->surface->width != ds_w ||
+ ds->surface->height != ds_h ||
+ ds->surface->linesize != ds_pitch ||
+ ds_rot != 0)
{
/* XXX: We should be able to force a resize/rotation from here ? */
fprintf(stderr, "%s: framebuffer dimensions mismatch\n", __FUNCTION__);
@@ -102,6 +104,7 @@ static int goldfish_fb_load(QEMUFile* f, void* opaque, int version_id)
s->int_status = qemu_get_be32(f);
s->int_enable = qemu_get_be32(f);
s->rotation = qemu_get_be32(f);
+ s->dpi = qemu_get_be32(f);
/* force a refresh */
s->need_update = 1;
@@ -111,6 +114,17 @@ Exit:
return ret;
}
+static int
+pixels_to_mm(int pixels, int dpi)
+{
+ /* dpi = dots / inch
+ ** inch = dots / dpi
+ ** mm / 25.4 = dots / dpi
+ ** mm = (dots * 25.4)/dpi
+ */
+ return (int)(0.5 + 25.4 * pixels / dpi);
+}
+
#define STATS 0
@@ -156,10 +170,11 @@ static void goldfish_fb_update_display(void *opaque)
}
src_line = qemu_get_ram_ptr( base );
- dst_line = s->qfbuff->pixels;
- pitch = s->qfbuff->pitch;
- width = s->qfbuff->width;
- height = s->qfbuff->height;
+
+ dst_line = s->ds->surface->data;
+ pitch = s->ds->surface->linesize;
+ width = s->ds->surface->width;
+ height = s->ds->surface->height;
#if STATS
if (full_update)
@@ -272,7 +287,7 @@ static void goldfish_fb_update_display(void *opaque)
base + y_last * width * 2,
VGA_DIRTY_FLAG);
- qframebuffer_update( s->qfbuff, 0, y_first, width, y_last-y_first );
+ dpy_update(s->ds, 0, y_first, width, y_last-y_first);
}
static void goldfish_fb_invalidate_display(void * opaque)
@@ -282,12 +297,6 @@ static void goldfish_fb_invalidate_display(void * opaque)
s->need_update = 1;
}
-static void goldfish_fb_detach_display(void* opaque)
-{
- struct goldfish_fb_state *s = (struct goldfish_fb_state *)opaque;
- s->qfbuff = NULL;
-}
-
static uint32_t goldfish_fb_read(void *opaque, target_phys_addr_t offset)
{
uint32_t ret;
@@ -295,12 +304,12 @@ static uint32_t goldfish_fb_read(void *opaque, target_phys_addr_t offset)
switch(offset) {
case FB_GET_WIDTH:
- ret = s->qfbuff->width;
+ ret = ds_get_width(s->ds);
//printf("FB_GET_WIDTH => %d\n", ret);
return ret;
case FB_GET_HEIGHT:
- ret = s->qfbuff->height;
+ ret = ds_get_height(s->ds);
//printf( "FB_GET_HEIGHT = %d\n", ret);
return ret;
@@ -313,12 +322,12 @@ static uint32_t goldfish_fb_read(void *opaque, target_phys_addr_t offset)
return ret;
case FB_GET_PHYS_WIDTH:
- ret = s->qfbuff->phys_width_mm;
+ ret = pixels_to_mm( ds_get_width(s->ds), s->dpi );
//printf( "FB_GET_PHYS_WIDTH => %d\n", ret );
return ret;
case FB_GET_PHYS_HEIGHT:
- ret = s->qfbuff->phys_height_mm;
+ ret = pixels_to_mm( ds_get_height(s->ds), s->dpi );
//printf( "FB_GET_PHYS_HEIGHT => %d\n", ret );
return ret;
@@ -353,7 +362,7 @@ static void goldfish_fb_write(void *opaque, target_phys_addr_t offset,
goldfish_device_set_irq(&s->dev, 0, (s->int_status & s->int_enable));
if (need_resize) {
//printf("FB_SET_BASE: need resize (rotation=%d)\n", s->rotation );
- qframebuffer_rotate( s->qfbuff, s->rotation );
+ dpy_resize(s->ds);
}
} break;
case FB_SET_ROTATION:
@@ -381,7 +390,7 @@ static CPUWriteMemoryFunc *goldfish_fb_writefn[] = {
goldfish_fb_write
};
-void goldfish_fb_init(DisplayState *ds, int id)
+void goldfish_fb_init(int id)
{
struct goldfish_fb_state *s;
@@ -391,15 +400,16 @@ void goldfish_fb_init(DisplayState *ds, int id)
s->dev.size = 0x1000;
s->dev.irq_count = 1;
- s->qfbuff = qframebuffer_fifo_get();
- qframebuffer_set_producer( s->qfbuff, s,
- goldfish_fb_update_display,
- goldfish_fb_invalidate_display,
- goldfish_fb_detach_display );
+ s->ds = graphic_console_init(goldfish_fb_update_display,
+ goldfish_fb_invalidate_display,
+ NULL,
+ NULL,
+ s);
+
+ s->dpi = 165; /* XXX: Find better way to get actual value ! */
goldfish_device_add(&s->dev, goldfish_fb_readfn, goldfish_fb_writefn, s);
register_savevm( "goldfish_fb", 0, GOLDFISH_FB_SAVE_VERSION,
goldfish_fb_save, goldfish_fb_load, s);
}
-