hotplug: new device hotplug system is introduced 26/23626/5
authorSeokYeon Hwang <syeon.hwang@samsung.com>
Tue, 1 Jul 2014 01:13:58 +0000 (10:13 +0900)
committerSeokYeon Hwang <syeon.hwang@samsung.com>
Tue, 1 Jul 2014 07:29:00 +0000 (16:29 +0900)
Do not use old hotplug logic anymore.
"Hotplug logic" becomes independent of legacy mloop.
"mloop" will be removed.

Change-Id: Ib1c40cb9bb65e6f2d8a2310ad5a0c761184b6321
Signed-off-by: SeokYeon Hwang <syeon.hwang@samsung.com>
hw/pci/pci-hotplug-old.c
tizen/src/ecs/ecs_msg.c
tizen/src/emulator.c
tizen/src/mloop_event.c
tizen/src/skin/maruskin_operation.c
tizen/src/util/Makefile.objs
tizen/src/util/maru_device_hotplug.c [new file with mode: 0644]
tizen/src/util/maru_device_hotplug.h [new file with mode: 0644]

index 555cf72b49052b344159d309221de78e1fc99783..cf2caebfb1b6cfe8d5380d1ac8026fb92dbc2ea4 100644 (file)
@@ -261,52 +261,7 @@ static PCIDevice *qemu_pci_hot_add_storage(Monitor *mon,
     return dev;
 }
 
-#ifdef CONFIG_MARU
-static PCIDevice *qemu_pci_hot_add_keyboard(Monitor *mon,
-                                            const char *devaddr,
-                                            const char *opts)
-{
-    PCIDevice *dev;
-    PCIBus *root = pci_find_primary_bus();
-    PCIBus *bus;
-    int devfn;
-
-    if (!root) {
-        monitor_printf(mon, "no primary PCI bus (if there are multiple"
-                       " PCI roots, you must use device_add instead)");
-        return NULL;
-    }
-
-    bus = pci_get_bus_devfn(&devfn, root, devaddr);
-    if (!bus) {
-        monitor_printf(mon, "Invalid PCI device address %s\n", devaddr);
-        return NULL;
-    }
-
-    if (!((BusState*)bus)->allow_hotplug) {
-        monitor_printf(mon, "PCI bus doesn't support hotplug\n");
-        return NULL;
-    }
-
-    dev = pci_create(bus, devfn, "virtio-keyboard-pci");
-    if (qdev_init(&dev->qdev) < 0) {
-        dev = NULL;
-    }
-
-    return dev;
-}
-#endif /* CONFIG_MARU */
-
-#ifdef CONFIG_MARU
-void pci_device_hot_add(Monitor *mon, const QDict *qdict)
-{
-    do_pci_device_hot_add(mon, qdict);
-}
-
-PCIDevice *do_pci_device_hot_add(Monitor *mon, const QDict *qdict)
-#else
 void pci_device_hot_add(Monitor *mon, const QDict *qdict)
-#endif
 {
     PCIDevice *dev = NULL;
     const char *pci_addr = qdict_get_str(qdict, "pci_addr");
@@ -329,10 +284,6 @@ void pci_device_hot_add(Monitor *mon, const QDict *qdict)
         dev = qemu_pci_hot_add_nic(mon, pci_addr, opts);
     } else if (strcmp(type, "storage") == 0) {
         dev = qemu_pci_hot_add_storage(mon, pci_addr, opts);
-#ifdef CONFIG_MARU
-    } else if (strcmp(type, "keyboard") == 0) {
-        dev = qemu_pci_hot_add_keyboard(mon, pci_addr, opts);
-#endif
     } else {
         monitor_printf(mon, "invalid type: %s\n", type);
     }
@@ -344,9 +295,6 @@ void pci_device_hot_add(Monitor *mon, const QDict *qdict)
                        PCI_FUNC(dev->devfn));
     } else
         monitor_printf(mon, "failed to add %s\n", opts);
-#ifdef CONFIG_MARU
-    return dev;
-#endif
 }
 
 static int pci_device_hot_remove(Monitor *mon, const char *pci_addr)
index 227cab975dd0f2c93b346d0eda6cfd1dcec9f2e3..04f93274be2dea94a3c225ca95eb2e72c989a3fb 100644 (file)
@@ -67,6 +67,7 @@
 #include "hw/maru_virtio_vmodem.h"
 #include "skin/maruskin_operation.h"
 #include "skin/maruskin_server.h"
+#include "util/maru_device_hotplug.h"
 #include "emulator.h"
 #include "emul_state.h"
 
@@ -509,7 +510,7 @@ bool msgproc_device_req(ECS_Client* ccli, ECS__DeviceReq* msg)
         }
     } else if (!strncmp(cmd, "HKeyboard", 8)) {
         if (group == MSG_GROUP_STATUS) {
-            send_host_keyboard_ntf(mloop_evcmd_get_hostkbd_status());
+            send_host_keyboard_ntf(is_host_keyboard_attached());
         } else {
             if (data == NULL) {
                 ERR("HKeyboard data is NULL\n");
@@ -897,6 +898,7 @@ bool send_nfc_ntf(struct nfc_msg_info* msg)
     return true;
 }
 
+
 static void handle_sdcard(char* dataBuf, size_t dataLen)
 {
 
@@ -907,8 +909,7 @@ static void handle_sdcard(char* dataBuf, size_t dataLen)
 
         if (ret == '0' ) {
             /* umount sdcard */
-            //mloop_evcmd_usbdisk(NULL);
-            mloop_evcmd_sdcard(NULL);
+            do_hotplug(DETACH_SDCARD, NULL, 0);
         } else if (ret == '1') {
             /* mount sdcard */
             char sdcard_img_path[256];
@@ -930,8 +931,7 @@ static void handle_sdcard(char* dataBuf, size_t dataLen)
                     g_strlcat(sdcard_img_path, sdcard_img_name, sizeof(sdcard_img_path));
                     TRACE("sdcard path: [%s]\n", sdcard_img_path);
 
-                    //mloop_evcmd_usbdisk(sdcard_img_path);
-                    mloop_evcmd_sdcard(sdcard_img_path);
+                    do_hotplug(ATTACH_SDCARD, sdcard_img_path, strlen(sdcard_img_path) + 1);
 
                     /*if using strndup than free string*/
                     if(pLinechange != NULL && sdcard_img_name!= NULL){
index b921ec8a09e111d5d5a9fc5273fb188adf6286f7..b0b467a2393bbfebcf811ee7a719eefc10a562f3 100644 (file)
@@ -47,6 +47,7 @@
 #include "skin/maruskin_server.h"
 #include "debug_ch.h"
 #include "ecs/ecs.h"
+#include "util/maru_device_hotplug.h"
 
 #ifdef CONFIG_SDL
 #include <SDL.h>
@@ -248,6 +249,8 @@ static void prepare_basic_features(gchar * const kernel_cmdline)
     check_vm_lock();
     make_vm_lock();
 
+    maru_device_hotplug_init();
+
     qemu_add_opts(&qemu_ecs_opts);
     start_ecs();
 
index a341d2062c5dfaf52a54ffb8575c1f91cd0a8b62..464e2950538c056426975000cfc3eec18e586399 100644 (file)
@@ -81,12 +81,7 @@ struct mloop_evpack {
 #define MLOOP_EVTYPE_INTR_UP    3
 #define MLOOP_EVTYPE_INTR_DOWN  4
 #define MLOOP_EVTYPE_TOUCH      6
-#define MLOOP_EVTYPE_KBD_ADD    8
-#define MLOOP_EVTYPE_KBD_DEL    9
 #define MLOOP_EVTYPE_RAMDUMP    10
-#define MLOOP_EVTYPE_SDCARD_ATTACH  11
-#define MLOOP_EVTYPE_SDCARD_DETACH  12
-
 
 static struct mloop_evsock mloop = {-1, 0, 0};
 
@@ -236,10 +231,6 @@ static int mloop_evsock_send(struct mloop_evsock *ev, struct mloop_evpack *p)
 }
 
 static USBDevice *usbdisk = NULL;
-#ifdef TARGET_I386
-static PCIDevice *hostkbd = NULL;
-static PCIDevice *virtio_sdcard = NULL;
-#endif
 
 static void mloop_evhandle_usb_add(char *name)
 {
@@ -296,137 +287,6 @@ static void mloop_evhandle_touch(struct mloop_evpack* pack)
     maru_virtio_touchscreen_notify();
 }
 
-#ifdef TARGET_I386
-static void mloop_evhandle_kbd_add(char *name)
-{
-    QDict *qdict;
-
-    TRACE("try to add a keyboard device.\n");
-
-    if (name == NULL) {
-        ERR("packet data is NULL.\n");
-        return;
-    }
-
-    if (hostkbd) {
-        INFO("virtio-keyboard has already been added.\n");
-        return;
-    }
-
-    qdict = qdict_new();
-    qdict_put(qdict, "pci_addr", qstring_from_str("auto"));
-    qdict_put(qdict, "type", qstring_from_str(name));
-
-    hostkbd = do_pci_device_hot_add(cur_mon, qdict);
-    if (hostkbd) {
-        TRACE("virtio-keyboard device: root_bus_path %s, bus %d, slot %d, function %d\n",
-                pci_root_bus_path(hostkbd), pci_bus_num(hostkbd->bus),
-                PCI_SLOT(hostkbd->devfn), PCI_FUNC(hostkbd->devfn));
-    } else {
-        ERR("failed to hot_add keyboard device.\n");
-    }
-
-    QDECREF(qdict);
-}
-
-static void mloop_evhandle_kbd_del(void)
-{
-    QDict *qdict;
-    int slot = 0;
-    char slotbuf[4] = {0,};
-
-    TRACE("try to remove a keyboard device.\n");
-
-    if (!hostkbd) {
-        ERR("Failed to remove a keyboard device "
-            "because the device has not been created yet.\n");
-        return;
-    }
-
-    slot = PCI_SLOT(hostkbd->devfn);
-    snprintf(slotbuf, sizeof(slotbuf), "%x", slot);
-    TRACE("virtio-keyboard slot %s.\n", slotbuf);
-
-    qdict = qdict_new();
-    qdict_put(qdict, "pci_addr", qstring_from_str(slotbuf));
-
-    do_pci_device_hot_remove(cur_mon, qdict);
-    INFO("hot_remove keyboard.\n");
-
-    hostkbd = NULL;
-
-    QDECREF(qdict);
-}
-
-static void mloop_evhandle_sdcard_attach(char *name)
-{
-    char opts[PATH_MAX];
-
-    INFO("try to attach sdcard.\n");
-
-    if (name == NULL) {
-        ERR("Packet data is NULL.\n");
-        return;
-    }
-
-    if (virtio_sdcard) {
-        ERR("sdcard is already attached.\n");
-        return;
-    }
-
-    QDict *qdict = qdict_new();
-
-    qdict_put(qdict, "pci_addr", qstring_from_str("auto"));
-    qdict_put(qdict, "type", qstring_from_str("storage"));
-    snprintf(opts, sizeof(opts), "file=%s,if=virtio", name);
-    qdict_put(qdict, "opts", qstring_from_str(opts));
-
-    virtio_sdcard = do_pci_device_hot_add(cur_mon, qdict);
-    if (virtio_sdcard) {
-        INFO("hot add virtio storage device with [%s]\n", opts);
-        INFO("virtio-sdcard device: root_bus_path %s, bus %d, slot %d, function %d\n",
-            pci_root_bus_path(virtio_sdcard), pci_bus_num(virtio_sdcard->bus),
-            PCI_SLOT(virtio_sdcard->devfn), PCI_FUNC(virtio_sdcard->devfn));
-    } else {
-        ERR("failed to create a sdcard device.\n");
-    }
-
-    QDECREF(qdict);
-}
-
-static void mloop_evhandle_sdcard_detach(void)
-{
-    INFO("try to detach sdcard.\n");
-
-    if (!virtio_sdcard) {
-        ERR("sdcard is not attached yet.\n");
-        return;
-    }
-
-    QDict *qdict = qdict_new();
-    int slot = 0;
-    char slotbuf[4] = {0,};
-
-    slot = PCI_SLOT(virtio_sdcard->devfn);
-    snprintf(slotbuf, sizeof(slotbuf), "%x", slot);
-    INFO("virtio-sdcard slot [%d].\n", slot);
-    qdict_put(qdict, "pci_addr", qstring_from_str(slotbuf));
-
-    do_pci_device_hot_remove(cur_mon, qdict);
-
-    virtio_sdcard = NULL;
-
-    INFO("hot remove virtio storage device.\n");
-
-    QDECREF(qdict);
-}
-
-int mloop_evcmd_get_hostkbd_status(void)
-{
-    return hostkbd ? 1 : 0;
-}
-#endif
-
 static void mloop_evhandle_ramdump(struct mloop_evpack* pack)
 {
 #define MAX_PATH 256
@@ -505,25 +365,9 @@ static void mloop_evcb_recv(struct mloop_evsock *ev)
     case MLOOP_EVTYPE_TOUCH:
         mloop_evhandle_touch(&pack);
         break;
-#ifdef TARGET_I386
-    case MLOOP_EVTYPE_KBD_ADD:
-        mloop_evhandle_kbd_add(pack.data);
-        break;
-    case MLOOP_EVTYPE_KBD_DEL:
-        mloop_evhandle_kbd_del();
-        break;
-#endif
     case MLOOP_EVTYPE_RAMDUMP:
         mloop_evhandle_ramdump(&pack);
         break;
-#ifdef TARGET_I386
-    case MLOOP_EVTYPE_SDCARD_ATTACH:
-        mloop_evhandle_sdcard_attach(pack.data);
-        break;
-    case MLOOP_EVTYPE_SDCARD_DETACH:
-        mloop_evhandle_sdcard_detach();
-        break;
-#endif
     default:
         break;
     }
@@ -570,16 +414,6 @@ void mloop_evcmd_lower_intr(void *irq)
     mloop_evsock_send(&mloop, &pack);
 }
 
-void mloop_evcmd_hostkbd(int on)
-{
-    struct mloop_evpack pack
-        = {MLOOP_EVTYPE_KBD_ADD, 13, "keyboard"};
-    if (on == 0) {
-        pack.type = MLOOP_EVTYPE_KBD_DEL;
-    }
-    mloop_evsock_send(&mloop, &pack);
-}
-
 void mloop_evcmd_usbdisk(char *img)
 {
     struct mloop_evpack pack;
@@ -601,27 +435,6 @@ void mloop_evcmd_usbdisk(char *img)
     mloop_evsock_send(&mloop, &pack);
 }
 
-void mloop_evcmd_sdcard(char *img)
-{
-    struct mloop_evpack pack;
-
-    if (img) {
-        if (strlen(img) > PACKET_LEN-5) {
-            ERR("The length of disk image path is greater than "
-                "lenth of maximum packet.\n");
-            return;
-        }
-
-        pack.type = MLOOP_EVTYPE_SDCARD_ATTACH;
-        pack.size = 5 + sprintf(pack.data, "%s", img);
-    } else {
-        pack.type = MLOOP_EVTYPE_SDCARD_DETACH;
-        pack.size = 5;
-    }
-
-    mloop_evsock_send(&mloop, &pack);
-}
-
 void mloop_evcmd_set_usbdisk(void *dev)
 {
     usbdisk = (USBDevice *)dev;
index d4fb8f97add94fa0b6e5cc4a5a9bdba0dfe6f7ab..31d2879ba2da9aec074d92126da6063205cb708d 100644 (file)
@@ -50,6 +50,7 @@
 #include "maruskin_server.h"
 #include "display/maru_display.h"
 #include "hw/maru_pm.h"
+#include "util/maru_device_hotplug.h"
 #include "ecs/ecs.h"
 
 #ifdef CONFIG_HAX
@@ -258,7 +259,7 @@ void do_keyboard_key_event(int event_type,
 #endif
 
 #if defined(TARGET_I386)
-    if (!mloop_evcmd_get_hostkbd_status()) {
+    if (!is_host_keyboard_attached()) {
         TRACE("ignore keyboard input because usb keyboard is dettached.\n");
         return;
     }
@@ -546,7 +547,11 @@ void do_host_kbd_enable(bool on)
 #if defined(TARGET_ARM)
     mloop_evcmd_usbkbd(on);
 #elif defined(TARGET_I386)
-    mloop_evcmd_hostkbd(on);
+    if (on) {
+        do_hotplug(ATTACH_HOST_KEYBOARD, NULL, 0);
+    } else {
+        do_hotplug(DETACH_HOST_KEYBOARD, NULL, 0);
+    }
 #endif
 }
 
index d77c8131cd57cec01dd08cd819b23e1385cca8c9..1102f2ea239eac51a9c3a86b9d3606a01c3f6bfe 100644 (file)
@@ -14,4 +14,7 @@ obj-$(CONFIG_LINUX) += check_gl_glx.o
 obj-$(CONFIG_WIN32) += check_gl_wgl.o
 obj-$(CONFIG_DARWIN) += check_gl_cgl.o
 
+# hotplug
+obj-y += maru_device_hotplug.o
+
 $(obj)/osutil.o: QEMU_CFLAGS += $(CURL_CFLAGS)
diff --git a/tizen/src/util/maru_device_hotplug.c b/tizen/src/util/maru_device_hotplug.c
new file mode 100644 (file)
index 0000000..578161b
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ * Maru device hotplug
+ *
+ * Copyright (C) 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * SeokYeon Hwang <syeon.hwang@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#include "qemu/main-loop.h"
+#include "qemu/config-file.h"
+#include "hw/qdev.h"
+#include "monitor/qdev.h"
+#include "qmp-commands.h"
+#include "sysemu/blockdev.h"
+#include "qemu/event_notifier.h"
+
+#include "maru_common.h"
+#include "emulator.h"
+#include "maru_device_hotplug.h"
+
+#define HOST_KEYBOARD_DRIVER        "virtio-keyboard-pci"
+#define HOST_KEYBOARD_DEFAULT_ID    "HOSTKBD0"
+
+#define SDCARD_DRIVE_DEFAULT_ID     "SDCARD_DRIVE0"
+#define SDCARD_DRIVER               "virtio-blk-pci"
+#define SDCARD_DEFAULT_ID           "SDCARD0"
+
+struct maru_device_hotplug {
+    EventNotifier notifier;
+
+    char *opaque;
+    int command;
+
+    // FIXME: Should we query device every time ??
+    bool host_keyboard_attached;
+    bool sdcard_attached;
+};
+
+static struct maru_device_hotplug *state;
+
+static bool do_host_keyboard_attach(void)
+{
+    QDict *qdict = qdict_new();
+    qdict_put(qdict, "driver", qstring_from_str(HOST_KEYBOARD_DRIVER));
+    qdict_put(qdict, "id", qstring_from_str(HOST_KEYBOARD_DEFAULT_ID));
+
+    if (do_device_add(default_mon, qdict, NULL)) {
+        QDECREF(qdict);
+        // TODO error reporting
+        return false;
+    }
+
+    QDECREF(qdict);
+
+    state->host_keyboard_attached = true;
+
+    return true;
+}
+
+static bool do_host_keyboard_detach(void)
+{
+    QDict *qdict = qdict_new();
+    qdict_put(qdict, "id", qstring_from_str(HOST_KEYBOARD_DEFAULT_ID));
+
+    if (qmp_marshal_input_device_del(default_mon, qdict, NULL)) {
+        QDECREF(qdict);
+        // TODO error reporting
+        return false;
+    }
+
+    QDECREF(qdict);
+
+    state->host_keyboard_attached = false;
+
+    return true;
+}
+
+static bool do_sdcard_attach(const char * const file)
+{
+    QDict *qdict = qdict_new();
+    QDict *qdict_file = qdict_new();
+    QDict *qdict_options = qdict_new();
+
+    qdict_put(qdict_file, "driver", qstring_from_str("file"));
+    qdict_put(qdict_file, "filename", qstring_from_str(file));
+    qdict_put(qdict_options, "file", qdict_file);
+    qdict_put(qdict_options, "driver", qstring_from_str("qcow2"));
+    qdict_put(qdict_options, "id", qstring_from_str(SDCARD_DRIVE_DEFAULT_ID));
+    qdict_put(qdict, "options", qdict_options);
+
+    if (qmp_marshal_input_blockdev_add(default_mon, qdict, NULL)) {
+        QDECREF(qdict);
+    }
+
+    QDECREF(qdict);
+
+    qdict = qdict_new();
+    qdict_put(qdict, "driver", qstring_from_str(SDCARD_DRIVER));
+    qdict_put(qdict, "drive", qstring_from_str(SDCARD_DRIVE_DEFAULT_ID));
+    qdict_put(qdict, "id", qstring_from_str(SDCARD_DEFAULT_ID));
+
+    if (do_device_add(default_mon, qdict, NULL)) {
+        QDECREF(qdict);
+        // TODO error reporting
+        return false;
+    }
+
+    QDECREF(qdict);
+
+    state->sdcard_attached = true;
+
+    return true;
+}
+
+static bool do_sdcard_detach(void) {
+    QDict *qdict = qdict_new();
+    qdict_put(qdict, "id", qstring_from_str(SDCARD_DEFAULT_ID));
+
+    if (qmp_marshal_input_device_del(cur_mon, qdict, NULL)) {
+        QDECREF(qdict);
+        // TODO error reporting
+        return false;
+    }
+
+    QDECREF(qdict);
+
+    state->sdcard_attached = false;
+
+    return true;
+}
+
+void do_hotplug(int command, void *opaque, size_t size)
+{
+    if (command == ATTACH_SDCARD) {
+        state->opaque = g_malloc(size);
+        memcpy(state->opaque, opaque, size);
+    }
+    state->command = command;
+
+    event_notifier_set(&state->notifier);
+}
+
+static void device_hotplug_handler(EventNotifier *e)
+{
+    event_notifier_test_and_clear(e);
+
+    switch(state->command) {
+    case ATTACH_HOST_KEYBOARD:
+        do_host_keyboard_attach();
+        break;
+    case DETACH_HOST_KEYBOARD:
+        do_host_keyboard_detach();
+        break;
+    case ATTACH_SDCARD:
+        do_sdcard_attach(state->opaque);
+        g_free(state->opaque);
+        break;
+    case DETACH_SDCARD:
+        do_sdcard_detach();
+        break;
+    default:
+        break;
+    }
+}
+
+static void maru_device_hotplug_deinit(Notifier *notifier, void *data)
+{
+    event_notifier_cleanup(&state->notifier);
+
+    g_free(state);
+}
+
+static Notifier maru_device_hotplug_exit = { .notify = maru_device_hotplug_deinit };
+
+void maru_device_hotplug_init(void)
+{
+    state = g_malloc0(sizeof(struct maru_device_hotplug));
+
+    event_notifier_init(&state->notifier, 0);
+    event_notifier_set_handler(&state->notifier, device_hotplug_handler);
+
+    emulator_add_exit_notifier(&maru_device_hotplug_exit);
+}
+
+bool is_host_keyboard_attached(void)
+{
+    return state->host_keyboard_attached;
+}
+
+bool is_sdcard_attached(void)
+{
+    return state->sdcard_attached;
+}
+
diff --git a/tizen/src/util/maru_device_hotplug.h b/tizen/src/util/maru_device_hotplug.h
new file mode 100644 (file)
index 0000000..462baf3
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Maru device hotplug
+ *
+ * Copyright (C) 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * SeokYeon Hwang <syeon.hwang@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#ifndef _MARU_DEVICE_HOTPLUG_H_
+#define _MARU_DEVICE_HOTPLUG_H_
+
+enum command {
+    ATTACH_HOST_KEYBOARD,
+    DETACH_HOST_KEYBOARD,
+    ATTACH_SDCARD,
+    DETACH_SDCARD,
+};
+
+void maru_device_hotplug_init(void);
+
+void do_hotplug(int command, void *opaque, size_t size);
+
+bool is_host_keyboard_attached(void);
+bool is_sdcard_attached(void);
+
+#endif // _MARU_DEVICE_HOTPLUG_H_