From: Kuo-Jung Su dant...@faraday-tech.com
Faraday keyboard/mouse controller (FTKBC010) is compliant with the
IBM PS/2 interface. The interface uses the bidirectional clock and
data lines to perform the half-duplex synchronous serial interface.
It also provides the configurable scan matrix for the embedded or
external keypad. FTKBC010 performs a serial-to-parallel conversion
to receive the data from the keyboard/mouse interface, and a
parallel-to-serial conversion for transmitting the data to the
keyboard/mouse interface.
Signed-off-by: Kuo-Jung Su dant...@faraday-tech.com
---
hw/ftkbc010.c | 226 +
1 file changed, 226 insertions(+)
create mode 100644 hw/ftkbc010.c
diff --git a/hw/ftkbc010.c b/hw/ftkbc010.c
new file mode 100644
index 000..c142bd0
--- /dev/null
+++ b/hw/ftkbc010.c
@@ -0,0 +1,226 @@
+/*
+ * Faraday FTKBC010 emulator for A369.
+ *
+ * Copyright (c) 2012 Faraday Technology
+ * Written by Dante Su dant...@faraday-tech.com
+ *
+ * This code is licensed under the GPL v2.
+ */
+
+#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_MENU139/* Menu (show menu) */
+
+#define TYPE_FTKBC010 ftkbc010
+
+typedef struct Ftkbc010State {
+SysBusDevice busdev;
+MemoryRegion iomem;
+qemu_irq irq;
+
+int x;
+int y;
+
+/* HW registers */
+uint32_t cr;
+uint32_t isr;
+} ftkbc010_state;
+
+#define FTKBC010(obj) \
+OBJECT_CHECK(ftkbc010_state, obj, TYPE_FTKBC010)
+
+static void ftkbc010_update(ftkbc010_state *s)
+{
+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(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 0x0808;
+default:
+break;
+}
+
+return 0;
+}
+
+static void ftkbc010_mem_write(void*opaque,
+ hwaddr addr,
+ uint64_t val,
+ unsigned size)
+{
+ftkbc010_state *s = FTKBC010(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(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 void ftkbc010_reset(DeviceState *ds)
+{
+SysBusDevice *busdev = SYS_BUS_DEVICE(ds);
+ftkbc010_state *s = FTKBC010(FROM_SYSBUS(ftkbc010_state, busdev));
+
+qemu_irq_lower(s-irq);
+}
+
+static int ftkbc010_init(SysBusDevice *dev)
+{
+ftkbc010_state *s = FTKBC010(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,
+