aboutsummaryrefslogtreecommitdiffstats
path: root/hw/goldfish_events_device.c
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-03 19:30:32 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-03 19:30:32 -0800
commit8b23a6c7e1aee255004dd19098d4c2462b61b849 (patch)
tree7a4d682ba51f0ff0364c5ca2509f515bdaf96de9 /hw/goldfish_events_device.c
parentf721e3ac031f892af46f255a47d7f54a91317b30 (diff)
downloadexternal_qemu-8b23a6c7e1aee255004dd19098d4c2462b61b849.zip
external_qemu-8b23a6c7e1aee255004dd19098d4c2462b61b849.tar.gz
external_qemu-8b23a6c7e1aee255004dd19098d4c2462b61b849.tar.bz2
auto import from //depot/cupcake/@135843
Diffstat (limited to 'hw/goldfish_events_device.c')
-rw-r--r--hw/goldfish_events_device.c423
1 files changed, 423 insertions, 0 deletions
diff --git a/hw/goldfish_events_device.c b/hw/goldfish_events_device.c
new file mode 100644
index 0000000..4cb2904
--- /dev/null
+++ b/hw/goldfish_events_device.c
@@ -0,0 +1,423 @@
+/* Copyright (C) 2007-2008 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 "qemu_file.h"
+#include "android/hw-events.h"
+#include "irq.h"
+
+#if 0
+// From kernel...
+#define EV_SYN 0x00
+#define EV_KEY 0x01
+#define EV_REL 0x02
+#define EV_ABS 0x03
+#define EV_MSC 0x04
+#define EV_SW 0x05
+#define EV_LED 0x11
+#define EV_SND 0x12
+#define EV_REP 0x14
+#define EV_FF 0x15
+#define EV_PWR 0x16
+#define EV_FF_STATUS 0x17
+#define EV_MAX 0x1f
+
+#define BTN_MISC 0x100
+#define BTN_0 0x100
+#define BTN_1 0x101
+#define BTN_2 0x102
+#define BTN_3 0x103
+#define BTN_4 0x104
+#define BTN_5 0x105
+#define BTN_6 0x106
+#define BTN_7 0x107
+#define BTN_8 0x108
+#define BTN_9 0x109
+
+#define BTN_MOUSE 0x110
+#define BTN_LEFT 0x110
+#define BTN_RIGHT 0x111
+#define BTN_MIDDLE 0x112
+#define BTN_SIDE 0x113
+#define BTN_EXTRA 0x114
+#define BTN_FORWARD 0x115
+#define BTN_BACK 0x116
+#define BTN_TASK 0x117
+
+#define BTN_JOYSTICK 0x120
+#define BTN_TRIGGER 0x120
+#define BTN_THUMB 0x121
+#define BTN_THUMB2 0x122
+#define BTN_TOP 0x123
+#define BTN_TOP2 0x124
+#define BTN_PINKIE 0x125
+#define BTN_BASE 0x126
+#define BTN_BASE2 0x127
+#define BTN_BASE3 0x128
+#define BTN_BASE4 0x129
+#define BTN_BASE5 0x12a
+#define BTN_BASE6 0x12b
+#define BTN_DEAD 0x12f
+
+#define BTN_GAMEPAD 0x130
+#define BTN_A 0x130
+#define BTN_B 0x131
+#define BTN_C 0x132
+#define BTN_X 0x133
+#define BTN_Y 0x134
+#define BTN_Z 0x135
+#define BTN_TL 0x136
+#define BTN_TR 0x137
+#define BTN_TL2 0x138
+#define BTN_TR2 0x139
+#define BTN_SELECT 0x13a
+#define BTN_START 0x13b
+#define BTN_MODE 0x13c
+#define BTN_THUMBL 0x13d
+#define BTN_THUMBR 0x13e
+
+#define BTN_DIGI 0x140
+#define BTN_TOOL_PEN 0x140
+#define BTN_TOOL_RUBBER 0x141
+#define BTN_TOOL_BRUSH 0x142
+#define BTN_TOOL_PENCIL 0x143
+#define BTN_TOOL_AIRBRUSH 0x144
+#define BTN_TOOL_FINGER 0x145
+#define BTN_TOOL_MOUSE 0x146
+#define BTN_TOOL_LENS 0x147
+#define BTN_TOUCH 0x14a
+#define BTN_STYLUS 0x14b
+#define BTN_STYLUS2 0x14c
+#define BTN_TOOL_DOUBLETAP 0x14d
+#define BTN_TOOL_TRIPLETAP 0x14e
+
+#define BTN_WHEEL 0x150
+#define BTN_GEAR_DOWN 0x150
+#define BTN_GEAR_UP 0x151
+
+#define REL_X 0x00
+#define REL_Y 0x01
+
+#define ABS_X 0x00
+#define ABS_Y 0x01
+#define ABS_Z 0x02
+#define ABS_RX 0x03
+#define ABS_RY 0x04
+#define ABS_RZ 0x05
+#define ABS_THROTTLE 0x06
+#define ABS_RUDDER 0x07
+#define ABS_WHEEL 0x08
+#define ABS_GAS 0x09
+#define ABS_BRAKE 0x0a
+#define ABS_HAT0X 0x10
+#define ABS_HAT0Y 0x11
+#define ABS_HAT1X 0x12
+#define ABS_HAT1Y 0x13
+#define ABS_HAT2X 0x14
+#define ABS_HAT2Y 0x15
+#define ABS_HAT3X 0x16
+#define ABS_HAT3Y 0x17
+#define ABS_PRESSURE 0x18
+#define ABS_DISTANCE 0x19
+#define ABS_TILT_X 0x1a
+#define ABS_TILT_Y 0x1b
+#define ABS_TOOL_WIDTH 0x1c
+#define ABS_VOLUME 0x20
+#define ABS_MISC 0x28
+#define ABS_MAX 0x3f
+#endif
+
+#define MAX_EVENTS 256*4
+
+enum {
+ REG_READ = 0x00,
+ REG_SET_PAGE = 0x00,
+ REG_LEN = 0x04,
+ REG_DATA = 0x08,
+
+ PAGE_NAME = 0x00000,
+ PAGE_EVBITS = 0x10000,
+ PAGE_ABSDATA = 0x20000 | EV_ABS,
+};
+
+typedef struct
+{
+ uint32_t base;
+ qemu_irq irq;
+ int pending;
+ int page;
+
+ unsigned events[MAX_EVENTS];
+ unsigned first;
+ unsigned last;
+
+ const char *name;
+ struct {
+ size_t len;
+ uint8_t *bits;
+ } ev_bits[EV_MAX + 1];
+ int32_t *abs_info;
+ size_t abs_info_count;
+} events_state;
+
+/* 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
+
+#undef QFIELD_STRUCT
+#define QFIELD_STRUCT events_state
+
+QFIELD_BEGIN(events_state_fields)
+ QFIELD_INT32(pending),
+ QFIELD_INT32(page),
+ QFIELD_BUFFER(events),
+ QFIELD_INT32(first),
+ QFIELD_INT32(last),
+QFIELD_END
+
+static void events_state_save(QEMUFile* f, void* opaque)
+{
+ events_state* s = opaque;
+
+ qemu_put_struct(f, events_state_fields, s);
+}
+
+static int events_state_load(QEMUFile* f, void* opaque, int version_id)
+{
+ events_state* s = opaque;
+
+ if (version_id != EVENTS_STATE_SAVE_VERSION)
+ return -1;
+
+ return qemu_get_struct(f, events_state_fields, s);
+}
+
+extern const char* android_skin_keycharmap;
+
+static void enqueue_event(events_state *s, unsigned int type, unsigned int code, int value)
+{
+ int enqueued = s->last - s->first;
+
+ if (enqueued < 0)
+ enqueued += MAX_EVENTS;
+
+ if (enqueued + 3 >= MAX_EVENTS-1) {
+ fprintf(stderr, "##KBD: Full queue, lose event\n");
+ return;
+ }
+
+ if(s->first == s->last){
+ qemu_irq_raise(s->irq);
+ }
+
+ //fprintf(stderr, "##KBD: type=%d code=%d value=%d\n", type, code, value);
+
+ s->events[s->last] = type;
+ s->last = (s->last + 1) & (MAX_EVENTS-1);
+ s->events[s->last] = code;
+ s->last = (s->last + 1) & (MAX_EVENTS-1);
+ s->events[s->last] = value;
+ s->last = (s->last + 1) & (MAX_EVENTS-1);
+}
+
+static unsigned dequeue_event(events_state *s)
+{
+ unsigned n;
+
+ if(s->first == s->last) {
+ return 0;
+ }
+
+ n = s->events[s->first];
+
+ s->first = (s->first + 1) & (MAX_EVENTS - 1);
+
+ if(s->first == s->last) {
+ qemu_irq_lower(s->irq);
+ }
+
+ return n;
+}
+
+static int get_page_len(events_state *s)
+{
+ int page = s->page;
+ if (page == PAGE_NAME)
+ return strlen(s->name);
+ if (page >= PAGE_EVBITS && page <= PAGE_EVBITS + EV_MAX)
+ return s->ev_bits[page - PAGE_EVBITS].len;
+ if (page == PAGE_ABSDATA)
+ return s->abs_info_count * sizeof(s->abs_info[0]);
+ return 0;
+}
+
+static int get_page_data(events_state *s, int offset)
+{
+ int page_len = get_page_len(s);
+ int page = s->page;
+ if (offset > page_len)
+ return 0;
+ if (page == PAGE_NAME)
+ 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)
+ return s->abs_info[offset / sizeof(s->abs_info[0])];
+ return 0;
+}
+
+static uint32_t events_read(void *x, target_phys_addr_t off)
+{
+ events_state *s = (events_state *) x;
+ int offset = off - s->base;
+ if (offset == REG_READ)
+ return dequeue_event(s);
+ else if (offset == REG_LEN)
+ return get_page_len(s);
+ else if (offset >= REG_DATA)
+ return get_page_data(s, offset - REG_DATA);
+ return 0; // this shouldn't happen, if the driver does the right thing
+}
+
+static void events_write(void *x, target_phys_addr_t off, uint32_t val)
+{
+ events_state *s = (events_state *) x;
+ int offset = off - s->base;
+ if (offset == REG_SET_PAGE)
+ s->page = val;
+}
+
+static CPUReadMemoryFunc *events_readfn[] = {
+ events_read,
+ events_read,
+ events_read
+};
+
+static CPUWriteMemoryFunc *events_writefn[] = {
+ events_write,
+ events_write,
+ events_write
+};
+
+static void events_put_keycode(void *x, int keycode)
+{
+ events_state *s = (events_state *) x;
+
+ enqueue_event(s, EV_KEY, keycode&0x1ff, (keycode&0x200) ? 1 : 0);
+}
+
+static void events_put_mouse(void *opaque, int dx, int dy, int dz, int buttons_state)
+{
+ events_state *s = (events_state *) opaque;
+ if (dz == 0) {
+ enqueue_event(s, EV_ABS, ABS_X, dx);
+ enqueue_event(s, EV_ABS, ABS_Y, dy);
+ enqueue_event(s, EV_ABS, ABS_Z, dz);
+ enqueue_event(s, EV_KEY, BTN_TOUCH, buttons_state&1);
+ } else {
+ enqueue_event(s, EV_REL, REL_X, dx);
+ enqueue_event(s, EV_REL, REL_Y, dy);
+ }
+ enqueue_event(s, EV_SYN, 0, 0);
+}
+
+static void events_put_generic(void* opaque, int type, int code, int value)
+{
+ events_state *s = (events_state *) opaque;
+
+ enqueue_event(s, type, code, value);
+}
+
+static int events_set_bits(events_state *s, int type, int bitl, int bith)
+{
+ uint8_t *bits;
+ uint8_t maskl, maskh;
+ int il, ih;
+ il = bitl / 8;
+ ih = bith / 8;
+ if (ih >= s->ev_bits[type].len) {
+ bits = qemu_mallocz(ih + 1);
+ if (bits == NULL)
+ return -ENOMEM;
+ memcpy(bits, s->ev_bits[type].bits, s->ev_bits[type].len);
+ qemu_free(s->ev_bits[type].bits);
+ s->ev_bits[type].bits = bits;
+ s->ev_bits[type].len = ih + 1;
+ }
+ else
+ bits = s->ev_bits[type].bits;
+ maskl = 0xffU << (bitl & 7);
+ maskh = 0xffU >> (7 - (bith & 7));
+ if (il >= ih)
+ maskh &= maskl;
+ else {
+ bits[il] |= maskl;
+ while (++il < ih)
+ bits[il] = 0xff;
+ }
+ bits[ih] |= maskh;
+ return 0;
+}
+
+#if 0
+static int events_set_abs_info(events_state *s, int axis, int32_t min, int32_t max, int32_t fuzz, int32_t flat)
+{
+ int32_t *info;
+ if (axis * 4 >= s->abs_info_count) {
+ info = qemu_mallocz((axis + 1) * 4 * sizeof(int32_t));
+ if (info == NULL)
+ return -ENOMEM;
+ memcpy(info, s->abs_info, s->abs_info_count);
+ qemu_free(s->abs_info);
+ s->abs_info = info;
+ s->abs_info_count = (axis + 1) * 4;
+ }
+ else
+ info = s->abs_info;
+ info += axis * 4;
+ *info++ = min;
+ *info++ = max;
+ *info++ = fuzz;
+ *info++ = flat;
+}
+#endif
+
+void events_dev_init(uint32_t base, qemu_irq irq)
+{
+ events_state *s;
+ int iomemtype;
+
+ s = (events_state *) qemu_mallocz(sizeof(events_state));
+ s->name = android_skin_keycharmap;
+ events_set_bits(s, EV_SYN, EV_SYN, EV_ABS);
+ events_set_bits(s, EV_SYN, EV_SW, EV_SW);
+ events_set_bits(s, EV_KEY, 1, 0x1ff);
+ events_set_bits(s, EV_REL, REL_X, REL_Y);
+ events_set_bits(s, EV_ABS, ABS_X, ABS_Z);
+ events_set_bits(s, EV_SW, 0, 0);
+ iomemtype = cpu_register_io_memory(0, events_readfn, events_writefn, s);
+
+ cpu_register_physical_memory(base, 0xfff, iomemtype);
+
+ qemu_add_kbd_event_handler(events_put_keycode, s);
+ qemu_add_mouse_event_handler(events_put_mouse, s, 1);
+ qemu_add_generic_event_handler(events_put_generic, s);
+
+ s->base = base;
+ s->irq = irq;
+
+ s->first = 0;
+ s->last = 0;
+
+ register_savevm( "events_state", 0, EVENTS_STATE_SAVE_VERSION,
+ events_state_save, events_state_load, s );
+}
+