Patchwork [v2,19/20] arm: add Faraday FTKBC010 support for A369

login
register
mail settings
Submitter Kuo-Jung Su
Date Jan. 25, 2013, 8:19 a.m.
Message ID <1359101996-11667-20-git-send-email-dantesu@gmail.com>
Download mbox | patch
Permalink /patch/215594/
State New
Headers show

Comments

Kuo-Jung Su - Jan. 25, 2013, 8:19 a.m.
From: Kuo-Jung Su <dantesu@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 <dantesu@faraday-tech.com>
---
 hw/ftkbc010.c |  226 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 226 insertions(+)
 create mode 100644 hw/ftkbc010.c
Paul Brook - Jan. 25, 2013, 9:04 p.m.
> From: Kuo-Jung Su <dantesu@faraday-tech.com>
> 
> Faraday keyboard/mouse controller (FTKBC010) is compliant with the
> IBM PS/2 interface.

Your description doesn't appear to match the code at all.  Surely if this were 
true then you should be using the existing PS2 keyboard emulation.

Paul
Kuo-Jung Su - Jan. 28, 2013, 6:05 a.m.
Sorry,
the description was directly copied from the introduction of its datasheet,
it appears to be ambigous in this case.

In A369, the FTKBC010 is configured as a keypad controller, not a PS2
keyboard.
it acts like some dedicated gpio buttons on the board.

In other word:
1. There is no PS2 port on A369.
2. The keypad buttons monitored by FTKBC010 are some hard wired buttons on
the board.

So it's not appropriate to use existing PS2 keyboard emulation here.

Best Wishes
Dante Su



2013/1/26 Paul Brook <paul@codesourcery.com>

> > From: Kuo-Jung Su <dantesu@faraday-tech.com>
> >
> > Faraday keyboard/mouse controller (FTKBC010) is compliant with the
> > IBM PS/2 interface.
>
> Your description doesn't appear to match the code at all.  Surely if this
> were
> true then you should be using the existing PS2 keyboard emulation.
>
> Paul
>
Andreas Färber - Jan. 28, 2013, 6:50 a.m.
Am 28.01.2013 07:05, schrieb Kuo-Jung Su:
> Sorry,
> the description was directly copied from the introduction of its datasheet,
> it appears to be ambigous in this case.

I thought so for the "high quality" ethernet adapter. ;) The commit
message is supposed to describe the code in technical terms, not
advertise represented hardware products with marketing speech please.

Andreas
Kuo-Jung Su - Jan. 28, 2013, 6:59 a.m.
2013/1/28 Andreas Färber <afaerber@suse.de>

> Am 28.01.2013 07:05, schrieb Kuo-Jung Su:
> > Sorry,
> > the description was directly copied from the introduction of its
> datasheet,
> > it appears to be ambigous in this case.
>
> I thought so for the "high quality" ethernet adapter. ;) The commit
> message is supposed to describe the code in technical terms, not
> advertise represented hardware products with marketing speech please.
>
> Andreas
>
> --
> SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
> GF: Jeff Hawn, Jennifer Guild, Felix Imendörffer; HRB 16746 AG Nürnberg
>

Sorry, that's my bad. It would never happen again.

Patch

diff --git a/hw/ftkbc010.c b/hw/ftkbc010.c
new file mode 100644
index 0000000..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 <dantesu@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_MENU            139    /* 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 0x00000808;
+    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,
+                          s,
+                          TYPE_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 = {
+    .name = TYPE_FTKBC010,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(cr, ftkbc010_state),
+        VMSTATE_UINT32(isr, ftkbc010_state),
+        VMSTATE_END_OF_LIST(),
+    }
+};
+
+static void ftkbc010_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    k->init   = ftkbc010_init;
+    dc->desc  = TYPE_FTKBC010;
+    dc->vmsd  = &vmstate_ftkbc010;
+    dc->reset = ftkbc010_reset;
+}
+
+static const TypeInfo ftkbc010_info = {
+    .name          = TYPE_FTKBC010,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(ftkbc010_state),
+    .class_init    = ftkbc010_class_init,
+};
+
+static void ftkbc010_register_types(void)
+{
+    type_register_static(&ftkbc010_info);
+}
+
+type_init(ftkbc010_register_types)