@@ -46,3 +46,4 @@ CONFIG_APIC=y
CONFIG_IOAPIC=y
CONFIG_ICC_BUS=y
CONFIG_PVPANIC=y
+CONFIG_ACPI_EC=y
@@ -1,2 +1,3 @@
common-obj-$(CONFIG_ACPI) += core.o piix4.o ich9.o
+common-obj-$(CONFIG_ACPI_EC) += ec.o
new file mode 100644
@@ -0,0 +1,192 @@
+#include "hw/acpi/ec.h"
+#include "hw/hw.h"
+#include "hw/isa/isa.h"
+#include "sysemu/sysemu.h"
+
+#define TYPE_EC_DEV "ACPI Embedded Controller"
+#define EC_DEV(obj) \
+ OBJECT_CHECK(ECState, (obj), TYPE_EC_DEV)
+
+static uint8_t ec_acpi_space[EC_ACPI_SPACE_SIZE] = {0};
+static uint8_t sci_event;
+static bool ec_enabled = false;
+
+typedef struct ECState {
+ ISADevice parent_obj;
+
+ uint8_t cmd;
+ uint8_t status;
+ uint8_t data;
+ uint8_t buf;
+ qemu_irq irq;
+ MemoryRegion io;
+} ECState;
+
+static NotifierList ec_sci_notifiers =
+ NOTIFIER_LIST_INITIALIZER(ec_sci_notifiers);
+void qemu_register_ec_sci_notifier(Notifier *notifier)
+{
+ notifier_list_add(&ec_sci_notifiers, notifier);
+}
+
+bool qemu_ec_enabled(void)
+{
+ return ec_enabled;
+}
+
+void ec_dev_init(ISABus *isabus)
+{
+ isa_create_simple(isabus, TYPE_EC_DEV);
+}
+
+void ec_acpi_event(uint8_t evt)
+{
+ sci_event = evt;
+}
+
+static void ec_generate_sci(void)
+{
+ notifier_list_notify(&ec_sci_notifiers, NULL);
+}
+
+static void acpi_data_write(void *opaque, hwaddr addr, uint64_t val,
+ unsigned size)
+{
+ ECState *s = opaque;
+ uint8_t tmp = val & 0xff;
+
+ if (s->status & EC_ACPI_CMD) {
+ s->buf = tmp & 0xff;
+ s->status &= ~EC_ACPI_CMD;
+ } else {
+ switch (tmp) {
+ case EC_ACPI_CMD_READ:
+ if (tmp < EC_ACPI_SPACE_SIZE) {
+ s->data = ec_acpi_space[tmp];
+ }
+ s->status |= EC_ACPI_OBF;
+ break;
+ case EC_ACPI_CMD_WRITE:
+ if (tmp < EC_ACPI_SPACE_SIZE) {
+ ec_acpi_space[s->buf] = tmp;
+ }
+ break;
+ case EC_ACPI_CMD_QUERY:
+ s->data = sci_event;
+ default:
+ break;
+ }
+ }
+ ec_generate_sci();
+}
+
+static uint64_t acpi_data_read(void *opaque, hwaddr addr, unsigned size)
+{
+ ECState *s = opaque;
+
+ s->status &= ~(EC_ACPI_OBF | EC_ACPI_SCI);
+
+ return s->data;
+}
+
+static void acpi_cmd_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
+{
+ ECState *s = opaque;
+ bool is_cmd = false;
+
+ s->status |= EC_ACPI_CMD;
+
+ switch (val & 0xff) {
+ case EC_ACPI_CMD_READ:
+ case EC_ACPI_CMD_WRITE:
+ is_cmd = true;
+ break;
+ case EC_ACPI_BURST_EN:
+ s->status |= EC_ACPI_BST;
+ s->data = 0x90;
+ is_cmd = true;
+ break;
+ case EC_ACPI_BURST_DN:
+ s->status &= ~EC_ACPI_BST;
+ is_cmd = true;
+ break;
+ case EC_ACPI_CMD_QUERY:
+ is_cmd = true;
+ default:
+ break;
+ }
+ if (is_cmd) {
+ s->cmd = val & 0xff;
+ ec_generate_sci();
+ s->status |= EC_ACPI_SCI;
+ } else {
+ s->cmd = 0;
+ }
+}
+
+static uint64_t acpi_status_read(void *opaque, hwaddr addr, unsigned size)
+{
+ ECState *s = opaque;
+
+ return s->status;
+}
+
+static const MemoryRegionOps io62_io_ops = {
+ .write = acpi_data_write,
+ .read = acpi_data_read,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .impl = {
+ .min_access_size = 1,
+ .max_access_size = 1,
+ },
+};
+
+static const MemoryRegionOps io66_io_ops = {
+ .write = acpi_cmd_write,
+ .read = acpi_status_read,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .impl = {
+ .min_access_size = 1,
+ .max_access_size = 1,
+ },
+};
+
+static int ec_dev_initfn(ISADevice *dev)
+{
+ ISADevice *isadev = dev;
+ ECState *s = EC_DEV(dev);
+
+/* isa_init_irq(isadev, &s->irq, 0xb); */
+
+ memory_region_init_io(&s->io, &io62_io_ops, NULL, "ec-acpi-data", 1);
+ isa_register_ioport(isadev, &s->io, 0x62);
+
+ memory_region_init_io(&s->io + 1, &io66_io_ops, NULL, "ec-acpi-cmd", 1);
+ isa_register_ioport(isadev, &s->io + 1, 0x66);
+
+ return 0;
+}
+
+static void ec_class_initfn(ObjectClass *oc, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+ ISADeviceClass *ic = ISA_DEVICE_CLASS(oc);
+
+ dc->no_user = 1;
+ ic->init = ec_dev_initfn;
+ ec_enabled = true;
+}
+
+static TypeInfo acpi_ec_info = {
+ .name = TYPE_EC_DEV,
+ .parent = TYPE_ISA_DEVICE,
+ .class_init = ec_class_initfn,
+ .instance_size = sizeof(ECState),
+};
+
+static void ec_register_type(void)
+{
+ type_register_static(&acpi_ec_info);
+}
+
+type_init(ec_register_type);
new file mode 100644
@@ -0,0 +1,29 @@
+#ifndef __EC_H
+#define __EC_H
+
+#include "hw/i386/pc.h"
+#include "qemu/notify.h"
+
+#define EC_ACPI_SPACE_SIZE 0x80
+
+#define EC_ACPI_CMD_PORT 0x66
+#define EC_ACPI_DATA_PORT 0x62
+
+#define EC_ACPI_OBF 0x1
+#define EC_ACPI_IBF 0x2
+#define EC_ACPI_CMD 0x8
+#define EC_ACPI_BST 0x10
+#define EC_ACPI_SCI 0x20
+
+#define EC_ACPI_CMD_READ 0x80
+#define EC_ACPI_CMD_WRITE 0x81
+#define EC_ACPI_BURST_EN 0x82
+#define EC_ACPI_BURST_DN 0x83
+#define EC_ACPI_CMD_QUERY 0x84
+
+void qemu_register_ec_sci_notifier(Notifier *notifier);
+bool qemu_ec_enabled(void);
+void ec_dev_init(ISABus *isabus);
+void ec_acpi_event(uint8_t evt);
+
+#endif
this work implemented Embedded Controller chip emulation which was defined at ACPI SEPC v5 chapter 12: "ACPI Embedded Controller Interface Specification" commonly Embedded Controller will emulate keyboard, mouse, handle ACPI defined operations and some low-speed devices like SMbus. Signed-off-by: liguang <lig.fnst@cn.fujitsu.com> --- default-configs/x86_64-softmmu.mak | 1 + hw/acpi/Makefile.objs | 1 + hw/acpi/ec.c | 192 ++++++++++++++++++++++++++++++++++++ include/hw/acpi/ec.h | 29 ++++++ 4 files changed, 223 insertions(+), 0 deletions(-) create mode 100644 hw/acpi/ec.c create mode 100644 include/hw/acpi/ec.h