Comments
Patch
new file mode 100644
@@ -0,0 +1,214 @@
+/*
+ * Faraday FTKBC010 emulator for A369.
+ *
+ * Copyright (c) 2012 Faraday Technology
+ *
+ * Written by Dante Su <dantesu@faraday-tech.com>
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "hw.h"
+#include "qemu/timer.h"
+#include "sysemu/sysemu.h"
+#include "sysbus.h"
+#include "ui/console.h"
+#include "devices.h"
+
+/* Key codes */
+#define KEYCODE_ESC 1
+#define KEYCODE_BACKSPACE 14
+#define KEYCODE_ENTER 28
+#define KEYCODE_SPACE 57
+#define KEYCODE_MENU 139 /* Menu (show menu) */
+
+typedef struct {
+ SysBusDevice busdev;
+ MemoryRegion iomem;
+ qemu_irq irq;
+
+ int x;
+ int y;
+
+ /* HW registers */
+ uint32_t cr;
+ uint32_t isr;
+} ftkbc010_state;
+
+static inline void ftkbc010_update(void *opaque)
+{
+ ftkbc010_state *s = (ftkbc010_state *) opaque;
+ uint32_t ier = 0;
+
+ /* keypad interrupt */
+ ier |= (s->cr & (1 << 8)) ? (1 << 2) : 0;
+ /* tx interrupt */
+ ier |= (s->cr & (1 << 3)) ? (1 << 1) : 0;
+ /* rx interrupt */
+ ier |= (s->cr & (1 << 4)) ? (1 << 0) : 0;
+
+ if (ier & s->isr)
+ qemu_irq_raise(s->irq);
+ else
+ qemu_irq_lower(s->irq);
+}
+
+static uint64_t ftkbc010_mem_read(void *opaque, hwaddr addr, unsigned size)
+{
+ ftkbc010_state *s = (ftkbc010_state *) opaque;
+
+ switch (addr) {
+ case 0x00:
+ return s->cr;
+ case 0x10:
+ return s->isr;
+ case 0x30:
+ return ~(1 << s->x);
+ case 0x34:
+ return ~(1 << s->y);
+ case 0x50: /* revision */
+ return 0x00010403;
+ case 0x54: /* feature */
+ return 0x00000808;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static void ftkbc010_mem_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
+{
+ ftkbc010_state *s = (ftkbc010_state *) opaque;
+
+ switch (addr) {
+ case 0x00:
+ s->cr = (uint32_t)val;
+ /* if ftkbc010 enabled */
+ if (!(s->cr & (1 << 2)))
+ break;
+ /* if keypad interrupt cleared */
+ if (s->cr & (1 << 10)) {
+ s->cr &= ~(1 << 10);
+ s->isr &= ~(1 << 2);
+ }
+ /* if rx interrupt cleared */
+ if (s->cr & (1 << 7)) {
+ s->cr &= ~(1 << 7);
+ s->isr &= ~(1 << 0);
+ }
+ /* if tx interrupt cleared */
+ if (s->cr & (1 << 6)) {
+ s->cr &= ~(1 << 6);
+ s->isr &= ~(1 << 1);
+ }
+ ftkbc010_update(s);
+ break;
+ default:
+ break;
+ }
+}
+
+static const MemoryRegionOps ftkbc010_mem_ops = {
+ .read = ftkbc010_mem_read,
+ .write = ftkbc010_mem_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void ftkbc010_key_event(void *opaque, int scancode)
+{
+ ftkbc010_state *s = (ftkbc010_state *) opaque;
+ int released = 0;
+
+ /* key release from qemu */
+ if (scancode & 0x80)
+ released = 1;
+
+ /* strip qemu key release bit */
+ scancode &= ~0x80;
+
+ /* keypad interrupt */
+ if (!released && (s->cr & (1 << 8))) {
+ switch(scancode) {
+ case KEYCODE_ESC:
+ case KEYCODE_BACKSPACE:
+ s->x = 1;
+ break;
+ case KEYCODE_ENTER:
+ case KEYCODE_MENU:
+ case KEYCODE_SPACE:
+ s->x = 3;
+ break;
+ default:
+ s->x = 2; /* KEY_HOME */
+ break;
+ }
+ s->y = 0;
+ s->isr |= (1 << 2);
+ ftkbc010_update(s);
+ }
+}
+
+static int ftkbc010_post_load(void *opaque, int version_id)
+{
+ ftkbc010_state *s = (ftkbc010_state *) opaque;
+
+ qemu_irq_lower(s->irq);
+
+ return 0;
+}
+
+static int ftkbc010_init(SysBusDevice *dev)
+{
+ ftkbc010_state *s = FROM_SYSBUS(ftkbc010_state, dev);
+
+ s->cr = 0;
+ s->isr = 0;
+ s->x = 0;
+ s->y = 0;
+
+ memory_region_init_io(&s->iomem, &ftkbc010_mem_ops, s, "ftkbc010", 0x1000);
+ sysbus_init_mmio(dev, &s->iomem);
+ sysbus_init_irq(dev, &s->irq);
+
+ qemu_add_kbd_event_handler(ftkbc010_key_event, s);
+
+ return 0;
+}
+
+static const VMStateDescription vmstate_ftkbc010_regs = {
+ .name = "ftkbc010",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .post_load = ftkbc010_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(cr, ftkbc010_state),
+ VMSTATE_UINT32(isr, ftkbc010_state),
+ VMSTATE_END_OF_LIST(),
+ }
+};
+
+static void ftkbc010_dev_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = ftkbc010_init;
+ dc->desc = "ftkbc010";
+ dc->vmsd = &vmstate_ftkbc010_regs;
+}
+
+static TypeInfo ftkbc010_dev_info = {
+ .name = "ftkbc010",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(ftkbc010_state),
+ .class_init = ftkbc010_dev_class_init,
+};
+
+static void ftkbc010_register_types(void)
+{
+ type_register_static(&ftkbc010_dev_info);
+}
+
+type_init(ftkbc010_register_types)
Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com> --- hw/ftkbc010.c | 214 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 214 insertions(+) create mode 100644 hw/ftkbc010.c