diff --git a/Makefile.target b/Makefile.target
index 82caf20..a49b21f 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -188,6 +188,7 @@ obj-$(CONFIG_KVM) += kvm.o kvm-all.o
 # MSI-X depends on kvm for interrupt injection,
 # so moved it from Makefile.objs to Makefile.target for now
 obj-y += msix.o
+obj-y += event-tap.o
 
 obj-$(CONFIG_ISA_MMIO) += isa_mmio.o
 LIBS+=-lz
diff --git a/event-tap.c b/event-tap.c
new file mode 100644
index 0000000..5d3a338
--- /dev/null
+++ b/event-tap.c
@@ -0,0 +1,184 @@
+/*
+ * Event Tap functions for QEMU
+ *
+ * Copyright (c) 2010 Nippon Telegraph and Telephone Corporation. 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ */
+
+#include "block.h"
+#include "ioport.h"
+#include "osdep.h"
+#include "hw/hw.h"
+#include "net/queue.h"
+#include "event-tap.h"
+
+static enum EVENT_TAP_STATE event_tap_state = EVENT_TAP_OFF;
+
+typedef struct EventTapIOport {
+    uint32_t address;
+    uint32_t data;    
+    int index;
+} EventTapIOport;
+
+#define MMIO_BUF_SIZE 8
+
+typedef struct EventTapMMIO {
+    uint64_t address;
+    uint8_t buf[MMIO_BUF_SIZE];
+    int len;
+} EventTapMMIO;
+
+#define EVENT_TAP_IOPORT 1
+#define EVENT_TAP_MMIO   2
+
+typedef struct EventTapLog {
+    int mode;
+    union {
+        EventTapIOport ioport ;    
+        EventTapMMIO mmio;
+    };
+} EventTapLog;
+
+static EventTapLog last_event_tap;
+
+int event_tap_register(int (*cb)(void))
+{
+    if (cb == NULL || event_tap_state != EVENT_TAP_OFF)
+        return -1;
+
+    bdrv_event_tap_register(cb);
+    qemu_net_event_tap_register(cb);
+    event_tap_state = EVENT_TAP_ON;
+
+    return 0;
+}
+
+int event_tap_unregister(void)
+{
+    if (event_tap_state == EVENT_TAP_OFF)
+        return -1;
+
+    bdrv_event_tap_unregister();
+    qemu_net_event_tap_unregister();
+    event_tap_state = EVENT_TAP_OFF;
+
+    return 0;
+}
+
+void event_tap_suspend(void)
+{
+    if (event_tap_state == EVENT_TAP_ON)
+        event_tap_state = EVENT_TAP_SUSPEND;
+}
+
+void event_tap_resume(void)
+{
+    if (event_tap_state == EVENT_TAP_SUSPEND)
+        event_tap_state = EVENT_TAP_ON;
+}
+
+int event_tap_get_state(void)
+{
+    return event_tap_state;
+}
+
+void event_tap_ioport(int index, uint32_t address, uint32_t data)
+{
+    if (event_tap_state != EVENT_TAP_ON) {
+        return;
+    }
+
+    last_event_tap.mode = EVENT_TAP_IOPORT;
+    last_event_tap.ioport.index = index;
+    last_event_tap.ioport.address = address;
+    last_event_tap.ioport.data = data;
+}
+
+void event_tap_mmio(uint64_t address, uint8_t *buf, int len)
+{
+    if (event_tap_state != EVENT_TAP_ON || len > MMIO_BUF_SIZE) {
+        return;
+    }
+
+    last_event_tap.mode = EVENT_TAP_MMIO;
+    last_event_tap.mmio.address = address;
+    last_event_tap.mmio.len = len;
+    memcpy(last_event_tap.mmio.buf, buf, len);
+}
+
+static void event_tap_reset(void)
+{
+    memset(&last_event_tap, 0, sizeof(last_event_tap));
+}
+
+void event_tap_replay(void)
+{
+    if (event_tap_state != EVENT_TAP_REPLAY) {
+        return;
+    }
+
+    switch (last_event_tap.mode) {
+    case EVENT_TAP_IOPORT:
+        switch (last_event_tap.ioport.index) {
+        case 0:
+            cpu_outb(last_event_tap.ioport.address, last_event_tap.ioport.data);
+            break;
+        case 1:
+            cpu_outw(last_event_tap.ioport.address, last_event_tap.ioport.data);
+            break;
+        case 2:
+            cpu_outl(last_event_tap.ioport.address, last_event_tap.ioport.data);
+            break;
+        }
+        event_tap_reset();
+        break;
+    case EVENT_TAP_MMIO:
+        cpu_physical_memory_rw(last_event_tap.mmio.address,
+                               last_event_tap.mmio.buf,
+                               last_event_tap.mmio.len, 1);
+        event_tap_reset();
+        break;
+    }
+}
+
+static void event_tap_save(QEMUFile *f, void *opaque)
+{
+    qemu_put_byte(f, last_event_tap.mode);
+
+    if (last_event_tap.mode == EVENT_TAP_IOPORT) {
+        qemu_put_be32(f, last_event_tap.ioport.index);
+        qemu_put_be32(f, last_event_tap.ioport.address);
+        qemu_put_byte(f, last_event_tap.ioport.data);
+    } else {
+        qemu_put_be64(f, last_event_tap.mmio.address);
+        qemu_put_byte(f, last_event_tap.mmio.len);
+        qemu_put_buffer(f, last_event_tap.mmio.buf, last_event_tap.mmio.len);
+    }
+}
+
+static int event_tap_load(QEMUFile *f, void *opaque, int version_id)
+{
+    last_event_tap.mode = qemu_get_byte(f);
+
+    if (last_event_tap.mode == EVENT_TAP_IOPORT) {
+        last_event_tap.ioport.index = qemu_get_be32(f);
+        last_event_tap.ioport.address = qemu_get_be32(f);
+        last_event_tap.ioport.data = qemu_get_byte(f);
+    } else {
+        last_event_tap.mmio.address = qemu_get_be64(f);
+        last_event_tap.mmio.len = qemu_get_byte(f);
+        qemu_get_buffer(f, last_event_tap.mmio.buf, last_event_tap.mmio.len);
+    }
+
+    event_tap_state = EVENT_TAP_REPLAY;
+
+    return 0;
+}
+
+void event_tap_init(void)
+{
+    register_savevm("event-tap", 0, 1,
+                    event_tap_save, event_tap_load, &last_event_tap);
+}
diff --git a/event-tap.h b/event-tap.h
new file mode 100644
index 0000000..d5f3042
--- /dev/null
+++ b/event-tap.h
@@ -0,0 +1,32 @@
+/*
+ * Event Tap functions for QEMU
+ *
+ * Copyright (c) 2010 Nippon Telegraph and Telephone Corporation. 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ */
+
+#ifndef EVENT_TAP_H
+#define EVENT_TAP_H
+
+#include "qemu-common.h"
+
+enum EVENT_TAP_STATE {
+    EVENT_TAP_OFF,
+    EVENT_TAP_ON,
+    EVENT_TAP_SUSPEND,
+    EVENT_TAP_REPLAY,
+};
+
+int event_tap_register(int (*cb)(void));
+int event_tap_unregister(void);
+void event_tap_suspend(void);
+void event_tap_resume(void);
+int event_tap_get_state(void);
+void event_tap_ioport(int index, uint32_t address, uint32_t data);
+void event_tap_mmio(uint64_t address, uint8_t *buf, int len);
+void event_tap_replay(void);
+void event_tap_init(void);
+
+#endif
