aboutsummaryrefslogtreecommitdiffstats
path: root/hw
diff options
context:
space:
mode:
authorDavid 'Digit' Turner <digit@android.com>2010-10-20 19:04:51 +0200
committerDavid 'Digit' Turner <digit@android.com>2010-10-20 19:04:51 +0200
commit80bc5c8c7b9c50e8f302c22c2fba42dd6e8aa2df (patch)
tree50bc7e6512e1465a690b7b1569483034dcadefcf /hw
parent18fe86e8245878f3b7a2813bd59b8cfcf636e15c (diff)
downloadexternal_qemu-80bc5c8c7b9c50e8f302c22c2fba42dd6e8aa2df.zip
external_qemu-80bc5c8c7b9c50e8f302c22c2fba42dd6e8aa2df.tar.gz
external_qemu-80bc5c8c7b9c50e8f302c22c2fba42dd6e8aa2df.tar.bz2
Fix incorrect orientation at boot.
The goldfish kernel's event driver is very picky about the state of the virtual device it talks to. Essentially, it can only listen to h/w events if the corresponding IRQ is raised _after_ it has completed some initial setup. If the IRQ is raised before, the driver will refuse to listen to events, and any interaction becomes impossible. We changed the way our UI windows are built and managed previously, and this had the unfortunate effect of sending one h/w event too soon, which, in the old code, would raise the IRQ prematurely. This resulted in an input freeze. To work around this the UI code was modified to not send the initial h/w event, but this resulted in bad orientation of the home screen at the end of the boot sequence. This change allows the virtual device to wait for the kernel driver before raising the IRQ, in the case any h/w event has been buffered. It also removes the hack in the UI code, allowing the send of the initial h/w event at startup. BONUS MINOR CHANGES: EsounD probe: fix error message. console: fix compiler warnings libpng: proper handling of MMX support. android-configure.sh: fix --ignore-audio handling The option didn't do anything if the audio development packages are properly installed on the system. Change-Id: Ib134158873d5cb72290c9676d92d20233226c889
Diffstat (limited to 'hw')
-rw-r--r--hw/goldfish_events_device.c47
1 files changed, 41 insertions, 6 deletions
diff --git a/hw/goldfish_events_device.c b/hw/goldfish_events_device.c
index 1f932f3..b0f95ec 100644
--- a/hw/goldfish_events_device.c
+++ b/hw/goldfish_events_device.c
@@ -30,6 +30,17 @@ enum {
PAGE_ABSDATA = 0x20000 | EV_ABS,
};
+/* These corresponds to the state of the driver.
+ * Unfortunately, we have to buffer events coming
+ * from the UI, since the kernel driver is not
+ * capable of receiving them until XXXXXX
+ */
+enum {
+ STATE_INIT = 0, /* The device is initialized */
+ STATE_BUFFERED, /* Events have been buffered, but no IRQ raised yet */
+ STATE_LIVE /* Events can be sent directly to the kernel */
+};
+
/* NOTE: The ev_bits arrays are used to indicate to the kernel
* which events can be sent by the emulated hardware.
*/
@@ -44,6 +55,7 @@ typedef struct
unsigned events[MAX_EVENTS];
unsigned first;
unsigned last;
+ unsigned state;
const char *name;
@@ -59,7 +71,7 @@ typedef struct
/* modify this each time you change the events_device structure. you
* will also need to upadte events_state_load and events_state_save
*/
-#define EVENTS_STATE_SAVE_VERSION 1
+#define EVENTS_STATE_SAVE_VERSION 2
#undef QFIELD_STRUCT
#define QFIELD_STRUCT events_state
@@ -70,6 +82,7 @@ QFIELD_BEGIN(events_state_fields)
QFIELD_BUFFER(events),
QFIELD_INT32(first),
QFIELD_INT32(last),
+ QFIELD_INT32(state),
QFIELD_END
static void events_state_save(QEMUFile* f, void* opaque)
@@ -98,13 +111,17 @@ static void enqueue_event(events_state *s, unsigned int type, unsigned int code,
if (enqueued < 0)
enqueued += MAX_EVENTS;
- if (enqueued + 3 >= MAX_EVENTS-1) {
+ if (enqueued + 3 > MAX_EVENTS) {
fprintf(stderr, "##KBD: Full queue, lose event\n");
return;
}
if(s->first == s->last) {
- qemu_irq_raise(s->irq);
+ if (s->state == STATE_LIVE)
+ qemu_irq_raise(s->irq);
+ else {
+ s->state = STATE_BUFFERED;
+ }
}
//fprintf(stderr, "##KBD: type=%d code=%d value=%d\n", type, code, value);
@@ -158,8 +175,9 @@ static int get_page_data(events_state *s, int offset)
return s->name[offset];
if (page >= PAGE_EVBITS && page <= PAGE_EVBITS + EV_MAX)
return s->ev_bits[page - PAGE_EVBITS].bits[offset];
- if (page == PAGE_ABSDATA)
+ if (page == PAGE_ABSDATA) {
return s->abs_info[offset / sizeof(s->abs_info[0])];
+ }
return 0;
}
@@ -167,6 +185,19 @@ static uint32_t events_read(void *x, target_phys_addr_t off)
{
events_state *s = (events_state *) x;
int offset = off; // - s->base;
+
+ /* This gross hack below is used to ensure that we
+ * only raise the IRQ when the kernel driver is
+ * properly ready! If done before this, the driver
+ * becomes confused and ignores all input events
+ * as soon as one was buffered!
+ */
+ if (offset == REG_LEN && s->page == PAGE_ABSDATA) {
+ if (s->state == STATE_BUFFERED)
+ qemu_irq_raise(s->irq);
+ s->state = STATE_LIVE;
+ }
+
if (offset == REG_READ)
return dequeue_event(s);
else if (offset == REG_LEN)
@@ -388,15 +419,19 @@ void events_dev_init(uint32_t base, qemu_irq irq)
qemu_add_kbd_event_handler(events_put_keycode, s);
qemu_add_mouse_event_handler(events_put_mouse, s, 1, "goldfish-events");
- user_event_register_generic(s, events_put_generic);
s->base = base;
s->irq = irq;
s->first = 0;
s->last = 0;
+ s->state = STATE_INIT;
+
+ /* This function migh fire buffered events to the device, so
+ * ensure that it is called after initialization is complete
+ */
+ user_event_register_generic(s, events_put_generic);
register_savevm( "events_state", 0, EVENTS_STATE_SAVE_VERSION,
events_state_save, events_state_load, s );
}
-