All of lore.kernel.org
 help / color / mirror / Atom feed
From: Bo Cao <caobosimon@gmail.com>
To: xen-devel@lists.xensource.com
Cc: Lars Kurth <lars.kurth@citrix.com>,
	Ian Campbell <ian.campbell@citrix.com>,
	George Dunlap <george.dunlap@eu.citrix.com>,
	Ian Jackson <ian.jackson@citrix.com>,
	Bo Cao <caobosimon@gmail.com>
Subject: [PATCH v0 RFC 1/2] libxl: Introduce functions in libxl to add and remove USB devices for an PV guest
Date: Mon, 11 Aug 2014 04:23:53 +0800	[thread overview]
Message-ID: <1407702234-22309-2-git-send-email-caobosimon@gmail.com> (raw)
In-Reply-To: <1407702234-22309-1-git-send-email-caobosimon@gmail.com>

This patch exposes a generic interface which can be expanded in the
future to implement USB for DEVICEMODEL. 

In this patch, I have implemented fucntions in libxl to add and remove USB
devices for an PV guest. Most of the fucntion are implemented in "tools/libxl/libxl_usb.c".

Signed-off-by: Simon Cao <caobosimon@gmail.com>
---
CC: George Dunlap <george.dunlap@eu.citrix.com>
CC: Ian Jackson <ian.jackson@citrix.com>
CC: Ian Campbell <ian.campbell@citrix.com>
CC: Pasi Kärkkäinen <pasik@iki.fi>
CC: Lars Kurth <lars.kurth@citrix.com>
---
 tools/libxl/Makefile                 |    2 +-
 tools/libxl/libxl.c                  |    8 +-
 tools/libxl/libxl.h                  |   69 ++
 tools/libxl/libxl_create.c           |   41 +-
 tools/libxl/libxl_internal.h         |   26 +
 tools/libxl/libxl_types.idl          |   59 +-
 tools/libxl/libxl_types_internal.idl |    1 +
 tools/libxl/libxl_usb.c              | 1277 ++++++++++++++++++++++++++++++++++
 8 files changed, 1474 insertions(+), 9 deletions(-)
 create mode 100644 tools/libxl/libxl_usb.c

diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile
index 4cfa275..a50e6cf 100644
--- a/tools/libxl/Makefile
+++ b/tools/libxl/Makefile
@@ -76,7 +76,7 @@ LIBXL_OBJS = flexarray.o libxl.o libxl_create.o libxl_dm.o libxl_pci.o \
 			libxl_internal.o libxl_utils.o libxl_uuid.o \
 			libxl_json.o libxl_aoutils.o libxl_numa.o \
 			libxl_save_callout.o _libxl_save_msgs_callout.o \
-			libxl_qmp.o libxl_event.o libxl_fork.o $(LIBXL_OBJS-y)
+			libxl_qmp.o libxl_event.o libxl_fork.o libxl_usb.o $(LIBXL_OBJS-y)
 LIBXL_OBJS += _libxl_types.o libxl_flask.o _libxl_types_internal.o
 
 LIBXL_TESTS += timedereg
diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
index 9054c3b..ec63831 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -1434,6 +1434,8 @@ void libxl__destroy_domid(libxl__egc *egc, libxl__destroy_domid_state *dis)
 
     if (libxl__device_pci_destroy_all(gc, domid) < 0)
         LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "pci shutdown failed for domid %d", domid);
+    if (libxl__device_usb_destroy_all(gc, domid) < 0)
+         LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "usb shutdown failed for domid %d", domid);
     rc = xc_domain_pause(ctx->xch, domid);
     if (rc < 0) {
         LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc, "xc_domain_pause failed for %d", domid);
@@ -1734,7 +1736,7 @@ out:
 /******************************************************************************/
 
 /* generic callback for devices that only need to set ao_complete */
-static void device_addrm_aocomplete(libxl__egc *egc, libxl__ao_device *aodev)
+void device_addrm_aocomplete(libxl__egc *egc, libxl__ao_device *aodev)
 {
     STATE_AO_GC(aodev->ao);
 
@@ -1757,7 +1759,7 @@ out:
 }
 
 /* common function to get next device id */
-static int libxl__device_nextid(libxl__gc *gc, uint32_t domid, char *device)
+int libxl__device_nextid(libxl__gc *gc, uint32_t domid, char *device)
 {
     char *dompath, **l;
     unsigned int nb;
@@ -1776,7 +1778,7 @@ static int libxl__device_nextid(libxl__gc *gc, uint32_t domid, char *device)
     return nextid;
 }
 
-static int libxl__resolve_domid(libxl__gc *gc, const char *name,
+int libxl__resolve_domid(libxl__gc *gc, const char *name,
                                 uint32_t *domid)
 {
     if (!name)
diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
index 17b8a7b..68f070c 100644
--- a/tools/libxl/libxl.h
+++ b/tools/libxl/libxl.h
@@ -91,6 +91,12 @@
 #define LIBXL_HAVE_DOMAIN_NODEAFFINITY 1
 
 /*
+ * LIBXL_HAVE_DEVICE_USB indicates the functions for doing hot-plug of
+ * USB devices.
+ */
+#define LIBXL_HAVE_DEVICE_USB 1
+
+/*
  * LIBXL_HAVE_BUILDINFO_HVM_VENDOR_DEVICE indicates that the
  * libxl_vendor_device field is present in the hvm sections of
  * libxl_domain_build_info. This field tells libxl which
@@ -950,6 +956,64 @@ int libxl_cdrom_insert(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *disk,
                        const libxl_asyncop_how *ao_how)
                        LIBXL_EXTERNAL_CALLERS_ONLY;
 
+/* USB Controllers*/
+int libxl_device_usbctrl_add(libxl_ctx *ctx, uint32_t domid,
+                         libxl_device_usbctrl *usbctrl,
+                         const libxl_asyncop_how *ao_how)
+                         LIBXL_EXTERNAL_CALLERS_ONLY;
+
+int libxl_device_usbctrl_remove(libxl_ctx *ctx, uint32_t domid,
+                         libxl_device_usbctrl *usbctrl,
+                         const libxl_asyncop_how *ao_how)
+                         LIBXL_EXTERNAL_CALLERS_ONLY;
+
+int libxl_device_usbctrl_destroy(libxl_ctx *ctx, uint32_t domid,
+                         libxl_device_usbctrl *usbctrl,
+                         const libxl_asyncop_how *ao_how)
+                         LIBXL_EXTERNAL_CALLERS_ONLY;
+
+libxl_device_usbctrl *libxl_device_usbctrl_list(libxl_ctx *ctx,
+                            uint32_t domid, int *num);
+
+int libxl_devid_to_device_usbctrl(libxl_ctx *ctx, uint32_t domid, 
+                            int devid, libxl_device_usbctrl *usbctrl)
+                            LIBXL_EXTERNAL_CALLERS_ONLY;
+
+int libxl_device_usbctrl_getinfo(libxl_ctx *ctx, uint32_t domid,
+                                libxl_device_usbctrl *usbctrl,
+                                libxl_usbctrlinfo *usbctrlinfo)
+                                LIBXL_EXTERNAL_CALLERS_ONLY;
+
+/* USB Devices */
+int libxl_device_usb_add(libxl_ctx *ctx, uint32_t domid, libxl_device_usb *usb,
+                         const libxl_asyncop_how *ao_how)
+                         LIBXL_EXTERNAL_CALLERS_ONLY;
+
+int libxl_device_usb_remove(libxl_ctx *ctx, uint32_t domid, libxl_device_usb *usb,
+                            const libxl_asyncop_how *ao_how)
+                            LIBXL_EXTERNAL_CALLERS_ONLY;
+
+int libxl_device_usb_destroy(libxl_ctx *ctx, uint32_t domid, libxl_device_usb *usb,
+                            const libxl_asyncop_how *ao_how)
+                            LIBXL_EXTERNAL_CALLERS_ONLY;
+
+libxl_device_usb *libxl_device_usb_list(libxl_ctx *ctx, uint32_t domid,
+                                        int usbctrl, int *num);
+
+int libxl_devid_to_device_usb(libxl_ctx *ctx, uint32_t domid,
+                               int devid, libxl_device_usb *usb)
+                            LIBXL_EXTERNAL_CALLERS_ONLY;
+
+int libxl_hostdev_to_device_usb(libxl_ctx *ctx, uint32_t domid,
+                            int devid, libxl_device_usb *usb)
+                            LIBXL_EXTERNAL_CALLERS_ONLY;
+
+int libxl_intf_to_device_usb(libxl_ctx *ctx, uint32_t domid,
+                            char *intf, libxl_device_usb *usb)
+                            LIBXL_EXTERNAL_CALLERS_ONLY;
+
+int libxl_device_usb_getinfo(libxl_ctx *ctx, char *intf, libxl_usbinfo *usbinfo)
+                             LIBXL_EXTERNAL_CALLERS_ONLY;
 /* Network Interfaces */
 int libxl_device_nic_add(libxl_ctx *ctx, uint32_t domid, libxl_device_nic *nic,
                          const libxl_asyncop_how *ao_how)
@@ -1065,6 +1129,11 @@ int libxl_device_pci_assignable_add(libxl_ctx *ctx, libxl_device_pci *pcidev, in
 int libxl_device_pci_assignable_remove(libxl_ctx *ctx, libxl_device_pci *pcidev, int rebind);
 libxl_device_pci *libxl_device_pci_assignable_list(libxl_ctx *ctx, int *num);
 
+int libxl_device_usb_assignable_add(libxl_ctx *ctx, libxl_device_usb *usb, int rebind);
+int libxl_device_usb_assignable_remove(libxl_ctx *ctx, libxl_device_usb *usb, int rebind);
+libxl_device_usb *libxl_device_usb_assignable_list(libxl_ctx *ctx, int *num);
+libxl_device_usb *libxl_device_usb_assigned_list(libxl_ctx *ctx, int *num);
+
 /* CPUID handling */
 int libxl_cpuid_parse_config(libxl_cpuid_policy_list *cpuid, const char* str);
 int libxl_cpuid_parse_config_xend(libxl_cpuid_policy_list *cpuid,
diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c
index d015cf4..fc51c52 100644
--- a/tools/libxl/libxl_create.c
+++ b/tools/libxl/libxl_create.c
@@ -685,6 +685,8 @@ static void domcreate_launch_dm(libxl__egc *egc, libxl__multidev *aodevs,
 
 static void domcreate_attach_vtpms(libxl__egc *egc, libxl__multidev *multidev,
                                    int ret);
+static void domcreate_attach_usbs(libxl__egc *egc, libxl__multidev *multidev,
+                                   int ret);
 static void domcreate_attach_pci(libxl__egc *egc, libxl__multidev *aodevs,
                                  int ret);
 
@@ -1239,13 +1241,13 @@ static void domcreate_attach_vtpms(libxl__egc *egc,
    if (d_config->num_vtpms > 0) {
        /* Attach vtpms */
        libxl__multidev_begin(ao, &dcs->multidev);
-       dcs->multidev.callback = domcreate_attach_pci;
+       dcs->multidev.callback = domcreate_attach_usbs;
        libxl__add_vtpms(egc, ao, domid, d_config, &dcs->multidev);
        libxl__multidev_prepared(egc, &dcs->multidev, 0);
        return;
    }
 
-   domcreate_attach_pci(egc, multidev, 0);
+   domcreate_attach_usbs(egc, multidev, 0);
    return;
 
 error_out:
@@ -1253,6 +1255,39 @@ error_out:
    domcreate_complete(egc, dcs, ret);
 }
 
+static void domcreate_attach_usbs(libxl__egc *egc, libxl__multidev *multidev,
+                                int ret)
+{
+    libxl__domain_create_state *dcs = CONTAINER_OF(multidev, *dcs, multidev);
+    STATE_AO_GC(dcs->ao);
+    int i;
+    libxl_ctx *ctx = CTX;
+    int domid = dcs->guest_domid;
+    
+    libxl_domain_config *const d_config = dcs->guest_config;
+    
+    if (ret) {
+        LOG(ERROR, "unable to add vtpm devices");
+        goto error_out;
+    }
+    
+    for (i = 0; i < d_config->num_usbs; i++) {
+        ret = libxl__device_usb_add(gc, domid, &d_config->usbs[i]);
+        if (ret < 0) {
+            LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
+                       "libxl__device_usb_add failed: %d", ret);
+            goto error_out;
+        }
+    }
+    
+    domcreate_attach_pci(egc, multidev, 0);
+    return;
+
+error_out:
+   assert(ret);
+   domcreate_complete(egc, dcs, ret);
+}
+
 static void domcreate_attach_pci(libxl__egc *egc, libxl__multidev *multidev,
                                  int ret)
 {
@@ -1266,7 +1301,7 @@ static void domcreate_attach_pci(libxl__egc *egc, libxl__multidev *multidev,
     libxl_domain_config *const d_config = dcs->guest_config;
 
     if (ret) {
-        LOG(ERROR, "unable to add vtpm devices");
+        LOG(ERROR, "unable to add usb devices");
         goto error_out;
     }
 
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index a0d4f24..629a0c2 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -1031,6 +1031,12 @@ _hidden int libxl__wait_for_backend(libxl__gc *gc, const char *be_path,
                                     const char *state);
 _hidden int libxl__nic_type(libxl__gc *gc, libxl__device *dev,
                             libxl_nic_type *nictype);
+_hidden int libxl__device_nextid(libxl__gc *gc, uint32_t domid, char *device);
+_hidden int libxl__resolve_domid(libxl__gc *gc, const char *name, 
+                                 uint32_t *domid); 
+_hidden int libxl__domain_usb_init(libxl__gc *gc, xs_transaction_t t,
+                                   char *libxl_path, struct xs_permissions *perm,
+                                   int perm_size);
 
 /*
  * For each aggregate type which can be used as an input we provide:
@@ -1056,6 +1062,8 @@ _hidden int libxl__device_vtpm_setdefault(libxl__gc *gc, libxl_device_vtpm *vtpm
 _hidden int libxl__device_vfb_setdefault(libxl__gc *gc, libxl_device_vfb *vfb);
 _hidden int libxl__device_vkb_setdefault(libxl__gc *gc, libxl_device_vkb *vkb);
 _hidden int libxl__device_pci_setdefault(libxl__gc *gc, libxl_device_pci *pci);
+_hidden int libxl__device_usbctrl_setdefault(libxl__gc *gc, 
+                                    libxl_device_usbctrl *usbctrl, uint32_t domid);
 
 _hidden const char *libxl__device_nic_devname(libxl__gc *gc,
                                               uint32_t domid,
@@ -2147,6 +2155,8 @@ struct libxl__ao_device {
 
 /* Starts preparing to add/remove a bunch of devices. */
 _hidden void libxl__multidev_begin(libxl__ao *ao, libxl__multidev*);
+/* generic callback for devices that only need to set ao_complete */
+_hidden void device_addrm_aocomplete(libxl__egc *egc, libxl__ao_device *aodev);
 
 /* Prepares to add/remove one of many devices.  Returns a libxl__ao_device
  * which has had libxl__prepare_ao_device called, and which has also
@@ -2266,6 +2276,18 @@ _hidden void libxl__device_vtpm_add(libxl__egc *egc, uint32_t domid,
                                    libxl_device_vtpm *vtpm,
                                    libxl__ao_device *aodev);
 
+/* from libxl_usb */
+_hidden int libxl__device_usbctrl_add(libxl__gc *gc, uint32_t domid,
+                            libxl_device_usbctrl *usbctrl);
+_hidden int libxl__device_usb_add(libxl__gc *gc, uint32_t domid, 
+                            libxl_device_usb *usb);
+_hidden int libxl__device_usb_destroy_all(libxl__gc *gc, uint32_t domid);
+_hidden int libxl__device_usb_assigned_list(libxl__gc *gc, libxl_device_usb **list, int *num);
+_hidden int libxl__device_usb_list(libxl__gc *gc, uint32_t domid, 
+                                libxl_device_usb **usbs, int usbctrl, int *num);
+_hidden libxl_device_usb *libxl_device_usb_list_all(libxl__gc *gc, uint32_t domid, int *num);
+_hidden int libxl__device_usb_setdefault(libxl__gc *gc, uint32_t domid, libxl_device_usb *usb);
+
 /* Internal function to connect a vkb device */
 _hidden int libxl__device_vkb_add(libxl__gc *gc, uint32_t domid,
                                   libxl_device_vkb *vkb);
@@ -2707,6 +2729,10 @@ _hidden void libxl__add_vtpms(libxl__egc *egc, libxl__ao *ao, uint32_t domid,
                              libxl_domain_config *d_config,
                              libxl__multidev *multidev);
 
+_hidden void libxl__add_usbs(libxl__egc *egc, libxl__ao *ao, uint32_t domid,
+                             libxl_domain_config *d_config,
+                             libxl__multidev *multidev);
+
 /*----- device model creation -----*/
 
 /* First layer; wraps libxl__spawn_spawn. */
diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl
index f0f6e34..9057862 100644
--- a/tools/libxl/libxl_types.idl
+++ b/tools/libxl/libxl_types.idl
@@ -85,6 +85,16 @@ libxl_nic_type = Enumeration("nic_type", [
     (2, "VIF"),
     ])
 
+libxl_usbctrl_type = Enumeration("usbctrl_type",[
+    (0, "AUTO"),
+    (1, "PV"),
+    (2, "DEVICEMODEL"),
+    ])
+
+libxl_usb_type = Enumeration("device_usb_type", [
+    (1, "HOSTDEV"),
+    ])
+
 libxl_action_on_shutdown = Enumeration("action_on_shutdown", [
     (1, "DESTROY"),
 
@@ -330,7 +340,7 @@ libxl_domain_build_info = Struct("domain_build_info",[
     ("ioports",          Array(libxl_ioport_range, "num_ioports")),
     ("irqs",             Array(uint32, "num_irqs")),
     ("iomem",            Array(libxl_iomem_range, "num_iomem")),
-    ("claim_mode",	     libxl_defbool),
+    ("claim_mode",       libxl_defbool),
     ("event_channels",   uint32),
     ("u", KeyedUnion(None, libxl_domain_type, "type",
                 [("hvm", Struct(None, [("firmware",         string),
@@ -448,6 +458,27 @@ libxl_device_pci = Struct("device_pci", [
     ("seize", bool),
     ])
 
+libxl_device_usbctrl = Struct("device_usbctrl", [
+    ("name", string),
+    ("type", libxl_usbctrl_type),
+    ("backend_domid", libxl_domid),
+    ("backend_domname", string),
+    ("devid", libxl_devid),
+    ("usb_version", uint8),
+    ("num_ports", uint8),
+    ])
+
+libxl_device_usb = Struct("device_usb", [
+    ("ctrl", integer),
+    ("port", integer),
+    ("intf", string),
+    ("u", KeyedUnion(None, libxl_usb_type, "type",
+        [("hostdev", Struct(None, [
+            ("hostbus",   integer),
+            ("hostaddr",  integer) ]))
+        ]))
+    ]) 
+     
 libxl_device_vtpm = Struct("device_vtpm", [
     ("backend_domid",    libxl_domid),
     ("backend_domname",  string),
@@ -462,10 +493,10 @@ libxl_domain_config = Struct("domain_config", [
     ("disks", Array(libxl_device_disk, "num_disks")),
     ("nics", Array(libxl_device_nic, "num_nics")),
     ("pcidevs", Array(libxl_device_pci, "num_pcidevs")),
+    ("usbs", Array(libxl_device_usb, "num_usbs")),
     ("vfbs", Array(libxl_device_vfb, "num_vfbs")),
     ("vkbs", Array(libxl_device_vkb, "num_vkbs")),
     ("vtpms", Array(libxl_device_vtpm, "num_vtpms")),
-
     ("on_poweroff", libxl_action_on_shutdown),
     ("on_reboot", libxl_action_on_shutdown),
     ("on_watchdog", libxl_action_on_shutdown),
@@ -507,6 +538,30 @@ libxl_vtpminfo = Struct("vtpminfo", [
     ("uuid", libxl_uuid),
     ], dir=DIR_OUT)
 
+libxl_usbctrlinfo = Struct("usbctrlinfo", [
+    ("backend", string),
+    ("backend_id", uint32),
+    ("frontend", string),
+    ("frontend_id", uint32),
+    ("devid", libxl_devid),
+    ("state", integer),
+    ("evtch", integer),
+    ("version", integer),
+    ("type", string),
+    ("ref_urb", integer),
+    ("ref_conn", integer),
+    ("num_ports", integer),
+    ], dir=DIR_OUT)
+
+libxl_usbinfo = Struct("usbinfo", [
+    ("bus", integer),
+    ("devnum", integer),
+    ("idVendor", integer),
+    ("idProduct", integer),
+    ("prod", string),
+    ("manuf", string),
+    ], dir=DIR_OUT)
+
 libxl_vcpuinfo = Struct("vcpuinfo", [
     ("vcpuid", uint32),
     ("cpu", uint32),
diff --git a/tools/libxl/libxl_types_internal.idl b/tools/libxl/libxl_types_internal.idl
index a964851..c5c17e7 100644
--- a/tools/libxl/libxl_types_internal.idl
+++ b/tools/libxl/libxl_types_internal.idl
@@ -20,6 +20,7 @@ libxl__device_kind = Enumeration("device_kind", [
     (6, "VKBD"),
     (7, "CONSOLE"),
     (8, "VTPM"),
+    (9, "VUSB"),
     ])
 
 libxl__console_backend = Enumeration("console_backend", [
diff --git a/tools/libxl/libxl_usb.c b/tools/libxl/libxl_usb.c
new file mode 100644
index 0000000..7a03489
--- /dev/null
+++ b/tools/libxl/libxl_usb.c
@@ -0,0 +1,1277 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * 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 Lesser General Public License for more details.
+ */
+
+#include "libxl_osdeps.h" /* must come before any other headers */
+
+#include "libxl_internal.h"
+//define the usb sys path
+#define SYSFS_USB_DEVS_PATH "/sys/bus/usb/devices"
+#define SYSFS_USBBACK_DRIVER "/sys/bus/usb/drivers/usbback"
+#define USBHUB_CLASS_CODE 9
+
+int libxl__device_usbctrl_setdefault(libxl__gc *gc, 
+                 libxl_device_usbctrl *usbctrl, uint32_t domid)
+{
+    int rc;
+    
+    if (!usbctrl->usb_version)
+        usbctrl->usb_version = 2;
+    if (!usbctrl->num_ports)
+        usbctrl->num_ports = 8;
+
+    if(!usbctrl->backend_domid)
+        usbctrl->backend_domid = 0;
+    
+    rc = libxl__resolve_domid(gc, usbctrl->backend_domname, &usbctrl->backend_domid);
+    if (rc < 0) return rc;
+
+    switch (libxl__domain_type(gc, domid)) {
+    case LIBXL_DOMAIN_TYPE_HVM:
+        if (!usbctrl->type)
+            usbctrl->type = LIBXL_USBCTRL_TYPE_DEVICEMODEL;
+        break;
+    case LIBXL_DOMAIN_TYPE_PV:
+        if (usbctrl->type == LIBXL_USBCTRL_TYPE_DEVICEMODEL) {
+            LOG(ERROR, "trying to create PV guest with an emulated interface");
+            return ERROR_INVAL;
+        }
+        usbctrl->type = LIBXL_USBCTRL_TYPE_PV;
+        break;
+    case LIBXL_DOMAIN_TYPE_INVALID:
+        return ERROR_FAIL;
+    default:
+        abort();
+    }
+    return rc;
+}
+
+static int libxl__device_from_usbctrl(libxl__gc *gc, uint32_t domid,
+                                   libxl_device_usbctrl *usbctrl,
+                                   libxl__device *device)
+{
+    device->backend_devid   = usbctrl->devid;
+    device->backend_domid   = usbctrl->backend_domid;
+    device->backend_kind    = LIBXL__DEVICE_KIND_VUSB;
+    device->devid           = usbctrl->devid;
+    device->domid           = domid;
+    device->kind            = LIBXL__DEVICE_KIND_VUSB;
+
+   return 0;    
+}
+
+static int do_pvusbctrl_add(libxl__gc *gc, uint32_t domid,
+                        libxl_device_usbctrl *usbctrl) 
+{
+    flexarray_t *front;
+    flexarray_t *back;
+    libxl__device *device;
+    unsigned int rc = 0;
+
+    rc = libxl__device_usbctrl_setdefault(gc, usbctrl, domid);
+    if(rc) goto out;
+    
+    front = flexarray_make(gc, 4, 1);
+    back = flexarray_make(gc, 12, 1);
+
+    if (usbctrl->devid == -1) {
+        if ((usbctrl->devid = libxl__device_nextid(gc, domid, "vusb")) < 0) {
+            rc = ERROR_FAIL;
+            goto out;
+        }
+    }
+    
+    GCNEW(device);
+    rc = libxl__device_from_usbctrl(gc, domid, usbctrl, device);
+    if ( rc != 0 ) goto out;
+
+    flexarray_append(back, "frontend-id");
+    flexarray_append(back, libxl__sprintf(gc, "%d", domid));
+    flexarray_append(back, "online");
+    flexarray_append(back, "1");
+    flexarray_append(back, "state");
+    flexarray_append(back, libxl__sprintf(gc, "%d", 1));
+    flexarray_append(back, "usb-ver");
+    flexarray_append(back, libxl__sprintf(gc, "%d", usbctrl->usb_version));
+    flexarray_append(back, "num-ports");
+    flexarray_append(back, libxl__sprintf(gc, "%d", usbctrl->num_ports));
+    flexarray_append(back, "type");
+    switch(usbctrl->type) {
+    case LIBXL_USBCTRL_TYPE_PV:{
+        flexarray_append(back, "PVUSB");
+        break;
+    }
+    case LIBXL_USBCTRL_TYPE_DEVICEMODEL: {
+        flexarray_append(back, "IOEMU");
+        break;
+    }
+    default:
+        abort();
+    }
+    flexarray_append(front, "backend-id");
+    flexarray_append(front, libxl__sprintf(gc, "%d", usbctrl->backend_domid));
+    flexarray_append(front, "state");
+    flexarray_append(front, libxl__sprintf(gc, "%d", 1));
+    libxl__device_generic_add(gc, XBT_NULL, device,
+                              libxl__xs_kvs_of_flexarray(gc, back, back->count),
+                              libxl__xs_kvs_of_flexarray(gc, front, front->count),
+                              NULL);
+    /*If we add usbctrl from usb-add, enable the funciton below will report errors.
+     *This is because the state of usbctrl change too fast for the device_addrm_complete to catch,
+     *from 2 to 4. Since we won't need hot-plug script in this usbctrl_add, it's okay to take if off.
+    aodev->dev = device;
+    aodev->action = LIBXL__DEVICE_ACTION_ADD;
+    //libxl__wait_device_connection(egc, aodev);
+    //ao->complete = 1;
+
+    rc = 0;
+out:
+    aodev->rc = rc;
+    if (rc) aodev->callback(egc, aodev);
+    return 0;
+    */
+out:
+    return rc;
+}
+
+static int libxl_port_add_xenstore(libxl__gc *gc, uint32_t domid,
+                                    libxl_device_usbctrl *usbctrl) {
+    libxl_ctx *ctx = CTX;
+    char *path;
+
+    path = libxl__sprintf(gc, "%s/backend/vusb/%d/%d/port", 
+                        libxl__xs_get_dompath(gc, 0), domid, usbctrl->devid);
+    if (libxl__xs_mkdir(gc, XBT_NULL, path, NULL, 0) ) {
+        return 1;
+    }
+    
+    int i, num_ports = usbctrl->num_ports;
+    for ( i = 1; i <= num_ports; ++i) {
+        if (libxl__xs_write(gc, XBT_NULL, 
+                      libxl__sprintf(gc,"%s/%d", path, i),"%s", "") ) {
+            LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_WARNING,
+                        "Create port %d to %s failed.", i, path);
+            return 1;
+        }
+    }
+    return 0;
+}
+                              
+int libxl__device_usbctrl_add(libxl__gc *gc, uint32_t domid,
+                           libxl_device_usbctrl *usbctrl) 
+{
+    switch (libxl__domain_type(gc, domid)) {
+    case LIBXL_DOMAIN_TYPE_HVM:
+         /* TO_DO */
+        break;
+    case LIBXL_DOMAIN_TYPE_PV:
+        if (do_pvusbctrl_add(gc, domid, usbctrl) ) {
+            return ERROR_FAIL;
+        }
+
+        /* Add sub-port to Xenstore */
+        if (libxl_port_add_xenstore(gc, domid, usbctrl) ) {
+            return ERROR_FAIL;
+        }
+        break;
+    case LIBXL_DOMAIN_TYPE_INVALID:
+            return ERROR_FAIL;
+    }
+
+    return 0;
+}
+
+int libxl_device_usbctrl_add(libxl_ctx *ctx, uint32_t domid, 
+                                libxl_device_usbctrl *usbctrl, const libxl_asyncop_how *ao_how)
+{
+    AO_CREATE(ctx, domid, ao_how);
+    int rc; 
+    
+    rc = libxl__device_usbctrl_add(gc, domid, usbctrl);
+    libxl__ao_complete(egc, ao, rc);
+    return AO_INPROGRESS; 
+}
+
+libxl_device_usbctrl *libxl_device_usbctrl_list(libxl_ctx *ctx, uint32_t domid, int *num)
+{
+    GC_INIT(ctx);
+
+    libxl_device_usbctrl *usbctrls = NULL;
+    char *fe_path = NULL, *result = NULL;
+    char **dir = NULL;
+    unsigned int ndirs = 0;
+    
+    *num = 0;
+    
+    fe_path = libxl__sprintf(gc, "%s/device/vusb", libxl__xs_get_dompath(gc, domid));
+    dir = libxl__xs_directory(gc, XBT_NULL, fe_path, &ndirs);
+
+    if (dir && ndirs) {
+        usbctrls = malloc(sizeof(*usbctrls) * ndirs);
+        libxl_device_usbctrl* usbctrl;
+        libxl_device_usbctrl* end = usbctrls + ndirs;
+        for(usbctrl = usbctrls; usbctrl < end; ++usbctrl, ++dir, (*num)++) {
+            const char *be_path = libxl__xs_read(gc, XBT_NULL,
+                                    GCSPRINTF("%s/%s/backend", fe_path, *dir));
+
+            libxl_device_usbctrl_init(usbctrl);
+
+            usbctrl->devid = atoi(*dir);
+
+            result = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/%s/backend-id",
+                                                   fe_path, *dir));
+            if( result == NULL)
+                goto outerr;
+            usbctrl->backend_domid = atoi(result);
+
+            result = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/usb-ver", be_path));
+            usbctrl->usb_version =  atoi(result);
+
+            result = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/num-ports", be_path));
+            usbctrl->num_ports = atoi(result);
+       }
+    }
+    *num = ndirs;
+    
+    return usbctrls;
+outerr:
+    LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "Unable to list USB Controllers");
+    while (*num) {
+        (*num)--;
+        libxl_device_usbctrl_dispose(&usbctrls[*num]);
+    }
+    free(usbctrls);
+    return NULL;
+}
+
+static int libxl__device_usb_remove_common(libxl__gc *gc, uint32_t domid,
+                                libxl_device_usb *usb, int force);
+
+static int libxl__device_usbctrl_remove_common(libxl_ctx *ctx, uint32_t domid,
+                            libxl_device_usbctrl *usbctrl,
+                            const libxl_asyncop_how *ao_how, int force)
+{
+    AO_CREATE(ctx, domid, ao_how);
+    libxl__device *device;
+    libxl__ao_device *aodev;
+    int hvm = 0, rc;
+    libxl_device_usb *usbs;
+    int i, numusb = 0;
+    
+    GCNEW(device); 
+    rc = libxl__device_from_usbctrl(gc, domid, usbctrl, device);
+    if(rc) goto out;
+
+    switch (libxl__domain_type(gc, domid)) {
+    case LIBXL_DOMAIN_TYPE_HVM:
+        hvm = 1;
+        /* TO_DO */
+        break;
+    case LIBXL_DOMAIN_TYPE_PV:
+        /* Remove usb devives first */
+        rc  = libxl__device_usb_list(gc, domid, &usbs, usbctrl->devid, &numusb);
+        if (rc) goto out;
+        for (i = 0; i < numusb; i++) {
+            if (libxl__device_usb_remove_common(gc, domid, &usbs[i], 0)) {
+                fprintf(stderr, "libxl_device_usb_remove failed.\n");
+                return 1;
+            }
+        }
+        /* remove usbctrl */
+        GCNEW(aodev);
+        libxl__prepare_ao_device(ao, aodev);
+        aodev->action = LIBXL__DEVICE_ACTION_REMOVE; 
+        aodev->dev = device;
+        aodev->callback = device_addrm_aocomplete;
+        aodev->force = force;
+        libxl__initiate_device_remove(egc, aodev);
+        break;
+    default:
+        abort();
+    }
+    
+out:
+    if(rc) return AO_ABORT(rc);
+    return AO_INPROGRESS;
+}
+
+int libxl_device_usbctrl_remove(libxl_ctx *ctx, uint32_t domid,
+                            libxl_device_usbctrl *usbctrl,
+                            const libxl_asyncop_how *ao_how)
+{
+    return libxl__device_usbctrl_remove_common(ctx, domid, usbctrl, ao_how, 0);
+}
+
+int libxl_device_usbctrl_destroy(libxl_ctx *ctx, uint32_t domid,
+                            libxl_device_usbctrl *usbctrl,
+                            const libxl_asyncop_how *ao_how)
+{
+    return libxl__device_usbctrl_remove_common(ctx, domid, usbctrl, ao_how, 1);
+}
+
+
+int libxl_device_usbctrl_getinfo(libxl_ctx *ctx, uint32_t domid,
+                                libxl_device_usbctrl *usbctrl,
+                                libxl_usbctrlinfo *usbctrlinfo)
+{
+    GC_INIT(ctx);
+    char *dompath, *usbctrlpath;
+    char *val;
+
+    dompath = libxl__xs_get_dompath(gc, domid);
+    usbctrlinfo->devid = usbctrl->devid;
+    usbctrlinfo->num_ports = usbctrl->num_ports;
+    usbctrlinfo->version = usbctrl->usb_version;
+
+    usbctrlpath = libxl__sprintf(gc, "%s/device/vusb/%d", dompath, usbctrlinfo->devid);
+    usbctrlinfo->backend = xs_read(ctx->xsh, XBT_NULL,
+                                libxl__sprintf(gc, "%s/backend", usbctrlpath), NULL);
+    if (!usbctrlinfo->backend) {
+        GC_FREE;
+        return ERROR_FAIL;
+    }
+    
+    val = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "%s/backend-id", usbctrlpath));
+    usbctrlinfo->backend_id = val ? strtoul(val, NULL, 10) : -1;
+    val = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "%s/state", usbctrlpath));
+    usbctrlinfo->state = val ? strtoul(val, NULL, 10) : -1;
+    val = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "%s/event-channel", usbctrlpath));
+    usbctrlinfo->evtch = val ? strtoul(val, NULL, 10) : -1;
+    val = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "%s/urb-ring-ref", usbctrlpath));
+    usbctrlinfo->ref_urb = val ? strtoul(val, NULL, 10) : -1;
+    val = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "%s/conn-ring-ref", usbctrlpath));
+    usbctrlinfo->ref_conn= val ? strtoul(val, NULL, 10) : -1;
+    usbctrlinfo->type = xs_read(ctx->xsh, XBT_NULL,
+                                libxl__sprintf(gc, "%s/type", usbctrlinfo->backend), NULL);
+    usbctrlinfo->frontend = xs_read(ctx->xsh, XBT_NULL,
+                                 libxl__sprintf(gc, "%s/frontend", usbctrlinfo->backend), NULL);
+    val = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "%s/frontend-id", usbctrlinfo->backend));
+    usbctrlinfo->frontend_id = val ? strtoul(val, NULL, 10) : -1;
+
+    GC_FREE;
+    return 0;
+}
+
+int libxl_devid_to_device_usbctrl(libxl_ctx *ctx, uint32_t domid,
+                               int devid, libxl_device_usbctrl *usbctrl)
+{
+    GC_INIT(ctx);
+    char* fe_path = NULL, *be_path = NULL, *tmp; 
+
+    fe_path = libxl__sprintf(gc, "%s/device/vusb", libxl__xs_get_dompath(gc, domid));
+    be_path = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/%d/backend", fe_path, devid));
+    
+    libxl_device_usbctrl_init(usbctrl);
+    usbctrl->devid = devid;
+    tmp = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/%d/backend-id",
+                                                   fe_path, devid));
+    if( tmp == NULL)
+        return ERROR_FAIL;
+    usbctrl->backend_domid = atoi(tmp);
+
+    tmp = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/usb-ver", be_path));
+    usbctrl->usb_version =  atoi(tmp);
+
+    tmp = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/num-ports", be_path));
+    usbctrl->num_ports = atoi(tmp);
+
+    GC_FREE;
+    return 0;
+}
+
+static int libxl__device_usb_add_xenstore(libxl__gc *gc, uint32_t domid, libxl_device_usb *usb)
+{
+    libxl_ctx *ctx = CTX; 
+    char *be_path;
+    
+    be_path = libxl__sprintf(gc, "%s/backend/vusb/%d/%d", 
+                        libxl__xs_get_dompath(gc, 0), domid, usb->ctrl);
+    libxl_domain_type domtype = libxl__domain_type(gc, domid);
+    if (domtype == LIBXL_DOMAIN_TYPE_INVALID)
+        return ERROR_FAIL;
+
+    if (domtype == LIBXL_DOMAIN_TYPE_PV) {
+        if (libxl__wait_for_backend(gc, be_path, "4") < 0)
+            return ERROR_FAIL;
+    }
+
+    be_path = libxl__sprintf(gc, "%s/port/%d", be_path, usb->port);
+    LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, "Adding new usb device to xenstore"); 
+    if (libxl__xs_write(gc, XBT_NULL, be_path, "%s", usb->intf) )
+        return 1;
+    
+    return 0;
+}
+
+static int libxl__device_usb_remove_xenstore(libxl__gc *gc, uint32_t domid, libxl_device_usb *usb)
+{
+    libxl_ctx *ctx = CTX;
+    char *be_path;
+
+    be_path = libxl__sprintf(gc, "%s/backend/vusb/%d/%d",
+                        libxl__xs_get_dompath(gc, 0), domid, usb->ctrl);
+    libxl_domain_type domtype = libxl__domain_type(gc, domid);
+    if (domtype == LIBXL_DOMAIN_TYPE_INVALID)
+        return ERROR_FAIL;
+
+    if (domtype == LIBXL_DOMAIN_TYPE_PV) {
+        if (libxl__wait_for_backend(gc, be_path, "4") < 0)
+            return ERROR_FAIL;
+    }
+
+    be_path = libxl__sprintf(gc, "%s/port/%d", be_path, usb->port);
+    LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, "Removing USB device from xenstore");
+
+    if (libxl__xs_write(gc,XBT_NULL, be_path, "") )
+        return 1;
+
+    return 0;
+}
+
+int libxl__device_usb_assigned_list(libxl__gc *gc, libxl_device_usb **list, int *num)
+{
+    char **domlist;
+    unsigned int nd = 0, i, j;
+    char *be_path;
+    libxl_device_usb *usb;
+
+    *list = NULL;
+    *num = 0;
+
+    domlist = libxl__xs_directory(gc, XBT_NULL, "/local/domain", &nd);
+    be_path = libxl__sprintf(gc,"/local/domain/0/backend/vusb");
+    for (i = 0; i < nd; i++) {
+        char *path, *num_ports, **ctrl_list;
+        unsigned int nc = 0;
+        
+        path = libxl__sprintf(gc, "%s/%s", be_path, domlist[i]);
+        ctrl_list = libxl__xs_directory(gc, XBT_NULL, path , &nc);
+
+        for (j = 0; j < nc; j++) {
+            path = libxl__sprintf(gc, "%s/%s/%s/num-ports", be_path, domlist[i], ctrl_list[j]);
+            num_ports = libxl__xs_read(gc, XBT_NULL, path);
+            if ( num_ports ) {
+                int nport = atoi(num_ports), k;
+                char *devpath, *intf;
+
+                for (k = 1; k <= nport; k++) {
+                    devpath = libxl__sprintf(gc, "%s/%s/%s/port/%u", be_path, domlist[i], ctrl_list[j], k);
+                    intf = libxl__xs_read(gc, XBT_NULL, devpath);
+                    /* If there are USB device attached, add it to list */
+                    if (intf && strcmp(intf, "") ) {
+                        *list = realloc(*list, sizeof(libxl_device_usb) * ((*num) + 1));
+                        if (*list == NULL)
+                            return ERROR_NOMEM;
+                        usb = *list + *num;
+                        usb->ctrl = atoi(ctrl_list[j]);
+                        usb->port = k;
+                        usb->intf = strdup(intf);
+                        (*num)++;
+                    }
+                }
+            }
+        }
+    }
+    libxl__ptr_add(gc, *list);
+
+    return 0;
+}
+
+libxl_device_usb *libxl_device_usb_assigned_list(libxl_ctx *ctx, int *num)
+{
+    GC_INIT(ctx);
+    libxl_device_usb *usbs;
+    int rc;
+
+    rc = libxl__device_usb_assigned_list(gc, &usbs, num);
+
+    GC_FREE;
+    return usbs;
+}
+    
+static int is_usb_in_array(libxl_device_usb *assigned, int num_assigned, char *intf)
+{
+    int i;
+    
+    for (i = 0; i < num_assigned; i++) {
+        if (!strcmp(assigned[i].intf, intf) )
+            return 1;
+    }
+
+    return 0;
+}
+
+static int sysfs_write_intf(libxl__gc *gc, const char * sysfs_path,
+                       libxl_device_usb *usb)
+{
+    libxl_ctx *ctx = CTX;
+    char *buf;
+    int rc, fd;
+    
+    fd = open(sysfs_path, O_WRONLY);
+    if (fd < 0) {
+        LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "Couldn't open %s",
+                         sysfs_path);
+        return ERROR_FAIL;
+    }
+
+    /* bind the usb device to usbback */
+    buf = libxl__sprintf(gc,"%s:1.0", usb->intf);
+    rc = write(fd, buf, strlen(buf));
+    // Annoying to have two if's, but we need the errno 
+    if (rc < 0)
+        LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR,
+                         "write to %s returned %d", sysfs_path, rc);
+    close(fd);
+
+    if (rc < 0)
+        return ERROR_FAIL;
+    return 0;
+}
+
+static int get_usb_bDeviceClass(libxl__gc *gc, char *intf, char *buf)
+{
+    char *path;
+    FILE *fd;
+    int rc;
+
+    path = libxl__sprintf(gc, SYSFS_USB_DEVS_PATH"/%s/bDeviceClass", intf);
+    
+    /* Check if this path exist, if not return 1 */
+    if (access(path, R_OK) )
+        return 1;
+    
+    path = libxl__sprintf(gc, "cat %s", path);
+    fd = popen(path, "r");
+    rc = fscanf(fd, "%s", buf);
+    pclose(fd);
+
+    if (rc)
+        return 0;
+    return 1;
+}
+
+static int is_usb_assignable(libxl__gc *gc, char *intf)
+{
+    int usb_classcode;
+    char buf[5];
+
+    if (!get_usb_bDeviceClass(gc, intf, buf) ){
+        usb_classcode = atoi(buf);
+        if (usb_classcode != USBHUB_CLASS_CODE)
+            return 0;
+    }
+    
+    return 1;
+}
+
+libxl_device_usb *libxl_device_usb_assignable_list(libxl_ctx *ctx, int *num)
+{
+    GC_INIT(ctx);
+    libxl_device_usb *usbs = NULL, *new, *assigned;
+    struct dirent *de;
+    DIR *dir;
+    int rc, num_assigned;
+
+    *num = 0;
+
+    rc = libxl__device_usb_assigned_list(gc, &assigned, &num_assigned);
+    if ( rc )
+        goto out;
+
+    dir = opendir(SYSFS_USB_DEVS_PATH);
+    if ( NULL == dir ) {
+        LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "Couldn't open %s", SYSFS_USB_DEVS_PATH);
+        goto out_closedir;
+    }   
+    
+    while( (de = readdir(dir)) ) {
+        if (!de->d_name)
+            continue;
+
+        if ( is_usb_in_array(assigned, num_assigned, de->d_name) )
+            continue;
+
+        if( is_usb_assignable(gc, de->d_name) )
+            continue;
+        new = realloc(usbs, ((*num) + 1) * sizeof(*new));
+        if ( NULL == new )
+            continue;
+
+        usbs = new;
+        new = usbs + *num;
+
+        memset(new, 0, sizeof(*new));
+        new->intf = strdup(de->d_name);
+
+        (*num)++;
+    }
+
+out_closedir:
+    closedir(dir);
+out:
+    GC_FREE;
+    return usbs;
+}
+
+static int sysfs_dev_unbind(libxl__gc *gc, libxl_device_usb *usb, 
+                                        char **driver_path)
+{
+    libxl_ctx *ctx = CTX;
+    char * spath, *dp = NULL;
+    struct stat st;
+
+    spath = libxl__sprintf(gc, SYSFS_USB_DEVS_PATH"/%s:1.0/driver",
+                          usb->intf);
+    if ( !lstat(spath, &st) ) {
+        /* Find the canousbctrlal path to the driver. */
+        dp = libxl__zalloc(gc, PATH_MAX);
+        dp = realpath(spath, dp);
+        if ( !dp ) {
+            LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "realpath() failed");
+            return -1;
+        }
+
+        LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, "Driver re-plug path: %s",
+                   dp);
+
+        /* Unbind from the old driver */
+        spath = libxl__sprintf(gc, "%s/unbind", dp);
+        if ( sysfs_write_intf(gc, spath, usb) < 0 ) {
+            LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "Couldn't unbind device");
+            return -1;
+        }
+    }
+
+    if ( driver_path )
+        *driver_path = dp;
+
+    return 0;
+}
+
+static int usbback_dev_assign(libxl__gc *gc, libxl_device_usb *usb)
+{
+    libxl_ctx *ctx = CTX;
+
+    if ( sysfs_write_intf(gc, SYSFS_USBBACK_DRIVER"/bind", usb) < 0 ) {
+        LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR,
+                         "Couldn't bind device to usbback!");
+        return ERROR_FAIL;
+    }
+    return 0;
+}
+
+static int usbback_dev_unassign(libxl__gc *gc, libxl_device_usb *usb)
+{
+    libxl_ctx *ctx = CTX;
+
+    /* Remove from usbback */
+    if ( sysfs_dev_unbind(gc, usb, NULL) < 0 ) {
+        LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "Couldn't unbind device!");
+        return ERROR_FAIL;
+    }
+    
+    return 0;
+}
+
+#define USBBACK_INFO_PATH "/libxl/usbback"
+
+/*cann't write '.' into Xenstore. So, change all '.' to '_' */
+static void usb_interface_encode(char *interface)
+{
+    int i, len = strlen(interface);
+    for (i = 0; i < len; i++) {
+        if (interface[i] == '.')
+            interface[i] = '_';
+    }
+}
+
+static void usb_assignable_driver_path_write(libxl__gc *gc, libxl_device_usb *usb,
+                                            char *driver_path)
+{
+    libxl_ctx *ctx = CTX;
+    char *path, *intf;
+
+    intf = libxl__strdup(gc, usb->intf);
+    usb_interface_encode(intf);
+
+    path = libxl__sprintf(gc, USBBACK_INFO_PATH"/%s/driver_path", intf);
+    if ( libxl__xs_write(gc, XBT_NULL, path, "%s", driver_path) < 0 ) {
+        LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_WARNING,
+                         "Write of %s to node %s failed.",
+                         driver_path, path);
+    }
+}
+
+static char * usb_assignable_driver_path_read(libxl__gc *gc, libxl_device_usb *usb)
+{
+    char *intf;
+    intf = libxl__strdup(gc, usb->intf);
+    usb_interface_encode(intf);
+
+    return libxl__xs_read(gc, XBT_NULL,libxl__sprintf(gc, 
+                    USBBACK_INFO_PATH"/%s/driver_path", intf));
+}
+
+static void usb_assignable_driver_path_remove(libxl__gc *gc, libxl_device_usb *usb)
+{
+    libxl_ctx *ctx = CTX;
+    char *intf;
+    intf = libxl__strdup(gc, usb->intf);
+    usb_interface_encode(intf);
+
+    /*Remove the xenstore entry */
+    xs_rm(ctx->xsh, XBT_NULL,
+            libxl__sprintf(gc,USBBACK_INFO_PATH"/%s/driver_path", intf));
+}
+
+#undef USBBACK_INFO_PATH
+
+static int do_usb_add (libxl__gc *gc, uint32_t domid, libxl_device_usb *usb)
+{
+    int rc = 0;
+
+    switch (libxl__domain_type(gc, domid)) {
+    case LIBXL_DOMAIN_TYPE_HVM:
+        /* TO-DO */
+        break;
+    case LIBXL_DOMAIN_TYPE_PV:
+        rc = libxl__device_usb_add_xenstore(gc, domid, usb);
+        if(rc) goto out;       
+        /*  Only after usbback automatically add 
+            inft:domid:controllerId:portId to "/sys/bus/usb/drivers/usbback/port_ids
+            can we bind the usb device to usbback. So we need to wait for this to be completed.        
+        */
+        sleep(1);
+
+        rc = usbback_dev_assign(gc, usb);
+        if(rc) {
+            libxl__device_usb_remove_xenstore(gc, domid, usb);
+            goto out;
+        }
+        break;
+    case LIBXL_DOMAIN_TYPE_INVALID:
+        return ERROR_FAIL;
+    }
+    
+out:
+    return rc;
+}
+
+static int libxl__device_set_default_usbctrl(libxl__gc *gc, uint32_t domid, libxl_device_usb *usb)
+{
+    libxl_ctx *ctx = CTX;
+    libxl_device_usbctrl *usbctrls;
+    libxl_device_usb *usbs = NULL;
+    int numctrl, numusb, i, j, rc;
+    char *be_path, *tmp;
+
+    usbctrls = libxl_device_usbctrl_list(ctx, domid, &numctrl);
+    if ( !numctrl)
+        goto out;
+
+    for (i = 0; i < numctrl; i++) {
+        rc = libxl__device_usb_list(gc, domid, &usbs, usbctrls[i].devid, &numusb);
+        if (rc) goto out;
+        if ( !usbctrls[i].num_ports || numusb == usbctrls[i].num_ports )
+            continue;
+        for (j = 1; i <= numusb; j++) {
+            be_path = libxl__sprintf(gc, "%s/backend/vusb/%d/%d/port/%d",
+                             libxl__xs_get_dompath(gc, 0), domid, usbctrls[i].devid, j);
+            tmp = libxl__xs_read(gc, XBT_NULL, be_path);
+            if ( tmp && !strcmp( tmp, "") ) {
+                usb->ctrl = usbctrls[i].devid;
+                usb->port = j;
+                return 0;
+            }
+        }
+        free(usbs);
+    }
+
+out:
+    free(usbctrls);
+    free(usbs);
+    return 1;
+} 
+
+int libxl__device_usb_setdefault(libxl__gc *gc, uint32_t domid, libxl_device_usb *usb)
+{
+    int rc;
+
+    switch (libxl__domain_type(gc, domid)) {
+    case LIBXL_DOMAIN_TYPE_HVM:
+        break;
+    case LIBXL_DOMAIN_TYPE_PV:
+        if (usb->ctrl == -1) {
+            if (usb->port != -1 ) {
+                LOG(ERROR, "USB controller must be specified if you specify port ID");
+                return ERROR_INVAL;
+            }   
+              
+            rc = libxl__device_set_default_usbctrl(gc, domid, usb);
+            /* If no existing ctrl to host this usb device, setup a new one */
+            if (rc) {
+                libxl_device_usbctrl usbctrl;
+                libxl_device_usbctrl_init(&usbctrl);
+                libxl__device_usbctrl_add(gc, domid, &usbctrl);
+                usb->ctrl = usbctrl.devid;
+                usb->port = 1;
+                libxl_device_usbctrl_dispose(&usbctrl);
+            } 
+        }
+
+        if (usb->port == -1) {
+            char *be_path = libxl__sprintf(gc, "%s/backend/vusb/%d/path/%d",
+                        libxl__xs_get_dompath(gc, 0), usb->ctrl, usb->port);
+            char *tmp = libxl__xs_read(gc, XBT_NULL, be_path);
+            if ( !tmp || strcmp(tmp, "") ){
+                LOG(ERROR, "The controller port doesn't exist or it has been assigned to another device");
+                return ERROR_INVAL;
+            }
+        }
+        break;
+    case LIBXL_DOMAIN_TYPE_INVALID:
+        return ERROR_FAIL;
+    default:
+        abort();
+    }
+
+    return 0;
+}
+
+int libxl_device_usb_add(libxl_ctx *ctx, uint32_t domid, libxl_device_usb *usb,
+                    const libxl_asyncop_how *ao_how)
+{
+    AO_CREATE(ctx, domid, ao_how);
+    int rc;
+
+    rc = libxl__device_usb_add(gc, domid, usb);
+    libxl__ao_complete(egc, ao, rc);
+    return AO_INPROGRESS;
+}
+
+int libxl__device_usb_add(libxl__gc *gc, uint32_t domid, libxl_device_usb *usb)
+{
+    libxl_ctx *ctx = CTX;
+    libxl_device_usb *assigned;
+    int rc, num_assigned;
+    char *driver_path;
+
+    rc = libxl__device_usb_setdefault(gc, domid, usb);
+    if (rc) goto out;
+    
+    rc = libxl__device_usb_assigned_list(gc, &assigned, &num_assigned);
+    if ( rc ) {
+        LIBXL__LOG(ctx, LIBXL__LOG_ERROR, 
+             "cannot determine if USB device is assigned, refusing to continue");
+        goto out;
+    }
+
+    if ( is_usb_in_array(assigned, num_assigned, usb->intf) ) {
+        LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "USB device already attached to a domain");
+        rc = ERROR_FAIL;
+        goto out;
+    }
+    
+    /* Check to see if there's already a driver that we need to unbind from */
+    if ( sysfs_dev_unbind(gc, usb, &driver_path ) ) {
+        LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
+                   "Couldn't unbind %s from driver", usb->intf);
+        return ERROR_FAIL;
+    }
+
+    /* Store driver_path for rebinding to dom0 */
+    if ( driver_path ) {
+        usb_assignable_driver_path_write(gc, usb, driver_path);
+    } else {
+        LIBXL__LOG(ctx, LIBXL__LOG_WARNING,
+                   "%s not bound to a driver, will not be rebound.", usb->intf);
+    }
+    
+    if (do_usb_add(gc, domid, usb) ) 
+       return ERROR_FAIL;
+ 
+out:
+    return rc;
+}
+
+static int do_usb_remove(libxl__gc *gc, uint32_t domid,
+                        libxl_device_usb *usb, int force)
+{
+
+    libxl_ctx *ctx = CTX;
+    libxl_device_usb *assigned;
+    int rc, num;
+
+    assigned = libxl_device_usb_list_all(gc, domid, &num);
+    if ( assigned == NULL ) {
+        LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "There is no USB device attached to this domain");
+        return ERROR_FAIL;
+    }
+
+    rc = ERROR_INVAL;
+    if ( !is_usb_in_array(assigned, num, usb->intf) ) {
+        LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "USB device not attached to this domain");
+        goto out_fail;
+    }
+
+    rc = ERROR_FAIL;
+    switch (libxl__domain_type(gc, domid)) {
+    case LIBXL_DOMAIN_TYPE_HVM:
+        //TO-DO
+        break;
+    case LIBXL_DOMAIN_TYPE_PV:
+        //unbind USB device from usbback TO-DO
+        rc = usbback_dev_unassign(gc, usb);
+
+        if (rc) return rc;
+        rc = libxl__device_usb_remove_xenstore(gc, domid, usb);
+        if(rc) 
+            return rc;
+        break;
+    default:
+        abort();
+    }
+out_fail:
+    return 0;
+}
+
+static int libxl__device_usb_remove_common(libxl__gc *gc, uint32_t domid,
+                                libxl_device_usb *usb, int force)
+{
+    libxl_ctx *ctx = CTX;
+    int rc;
+    char *driver_path;
+
+    rc = do_usb_remove(gc, domid, usb, force);
+
+    if (rc)
+        return ERROR_INVAL;
+    
+    /* Rebind if necessary */
+    driver_path = usb_assignable_driver_path_read(gc, usb);
+
+    if ( driver_path ) {
+        LIBXL__LOG(ctx, LIBXL__LOG_INFO, "Rebinding USB device %s to driver at %s",
+                                        usb->intf, driver_path);
+
+        if ( sysfs_write_intf(gc, libxl__sprintf(gc, "%s/bind", driver_path),
+                                 usb) < 0 ) {
+            LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR,
+                             "Couldn't bind device to %s", driver_path);
+            return -1;
+        }
+    }
+
+    usb_assignable_driver_path_remove(gc, usb);
+
+    return 0;
+}
+
+int libxl_device_usb_remove(libxl_ctx *ctx, uint32_t domid,
+                            libxl_device_usb *usb, const libxl_asyncop_how *ao_how)
+
+{
+    AO_CREATE(ctx, domid, ao_how);
+    int rc;
+
+    rc = libxl__device_usb_remove_common(gc, domid, usb, 0);
+
+    libxl__ao_complete(egc, ao, rc);
+    return AO_INPROGRESS;
+}
+            
+int libxl_device_usb_destroy(libxl_ctx *ctx, uint32_t domid,
+                             libxl_device_usb *usb, const libxl_asyncop_how *ao_how)
+{
+    AO_CREATE(ctx, domid, ao_how);
+    int rc;
+
+    rc = libxl__device_usb_remove_common(gc, domid, usb, 1);
+
+    libxl__ao_complete(egc, ao, rc);
+    return AO_INPROGRESS;
+}
+
+
+int libxl__device_usb_list(libxl__gc *gc, uint32_t domid, libxl_device_usb **usbs, int usbctrl, int *num)
+{
+    char *be_path, *num_devs;
+    int n, i;
+    libxl_device_usb *usb;
+    
+    *usbs = NULL;
+    *num = 0;
+
+    be_path = libxl__sprintf(gc, "%s/backend/vusb/%d/%d", libxl__xs_get_dompath(gc, 0), domid, usbctrl);
+    num_devs = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "%s/num-ports", be_path));
+    if (!num_devs)
+        goto out;
+
+    n = atoi(num_devs);
+    *usbs = calloc(n, sizeof(libxl_device_usb));
+
+    char *intf;
+    for (i = 0; i < n; i++) {
+        intf = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc,"%s/port/%d", be_path, i + 1));
+        if ( intf && strcmp(intf, "") ) {
+            usb = *usbs + *num;
+            usb->intf = strdup(intf);
+            usb->port = i + 1;
+            usb->ctrl = usbctrl;
+            (*num)++;
+        }
+    }
+out:
+    return 0;
+}
+
+libxl_device_usb *libxl_device_usb_list(libxl_ctx *ctx, uint32_t domid, int usbctrl, int *num)
+{
+    GC_INIT(ctx);
+    libxl_device_usb *usbs;
+    int rc;
+
+    rc = libxl__device_usb_list(gc, domid, &usbs, usbctrl, num);
+
+    if (rc)
+        free(usbs);
+    GC_FREE;
+    return usbs;
+}
+
+libxl_device_usb *libxl_device_usb_list_all(libxl__gc *gc, uint32_t domid, int *num)
+{
+    char **usblist;
+    unsigned int nd, i, j;
+    char *be_path;
+    int rc;
+    libxl_device_usb *usbs = NULL;
+
+    *num = 0;
+
+    be_path = libxl__sprintf(gc,"/local/domain/0/backend/vusb/%d", domid);
+    usblist = libxl__xs_directory(gc, XBT_NULL, be_path, &nd);
+
+    for (i = 0; i < nd; i++) { 
+        int nc = 0;
+        libxl_device_usb *tmp;
+        rc = libxl__device_usb_list(gc, domid, &tmp, atoi(usblist[i]), &nc);
+        if (!nc) 
+            continue;
+        usbs = realloc(usbs, sizeof(libxl_device_usb)*((*num) + nc));
+        /* TO-DO
+        if (usbs == NULL)
+            return ERROR_NOMEM;
+        */
+        for(j = 0; j < nc; j++) {
+            usbs[*num].ctrl = tmp[j].ctrl;
+            usbs[*num].port = tmp[j].port;
+            usbs[*num].intf = strdup(tmp[j].intf);
+            (*num)++;
+        }
+        free(tmp);
+    }
+    return usbs;
+}
+
+int libxl__device_usb_destroy_all(libxl__gc *gc, uint32_t domid)
+{
+    libxl_ctx *ctx = CTX;
+    libxl_device_usbctrl *usbctrls;
+    int num, i, rc = 0;
+
+    usbctrls = libxl_device_usbctrl_list(ctx, domid, &num);
+    if ( usbctrls == NULL )
+        return 0;
+
+    for (i = 0; i < num; i++) {
+        /* Force remove on shutdown since, on HVM, qemu will not always
+         * respond to SCI interrupt because the guest kernel has shut down the
+         * devices by the time we even get here!
+         */
+        if (libxl__device_usbctrl_remove_common(ctx, domid, usbctrls + i, 0, 1) < 0)
+            rc = ERROR_FAIL;
+    }
+
+    free(usbctrls);
+    return 0;
+}
+
+/* TO-DO: map the "lsusb" bus:addr to the sysfs usb address
+static int libxl_hostdev_to_intf(libxl__gc *gc, libxl_device_usb *usb)
+{
+    return 0;
+}
+*/
+
+#define BUF_SIZE 20
+/*use system call popen to get usb device information */
+static int get_usb_devnum (libxl__gc *gc, const char *intf, char *buf)
+{
+    char *path;
+    int rc;
+    FILE *fd;
+
+    path = libxl__sprintf(gc, "cat "SYSFS_USB_DEVS_PATH"/%s/devnum", intf);
+    fd = popen(path, "r");
+    rc = fscanf(fd, "%s", buf);
+    pclose(fd);
+
+    if (rc) return 0;
+    return 1;
+}
+
+static int get_usb_busnum(libxl__gc *gc, const char *intf, char *buf)
+{
+    char *path;
+    int rc;
+    FILE *fd;
+
+    path = libxl__sprintf(gc, "cat "SYSFS_USB_DEVS_PATH"/%s/busnum", intf);
+    fd = popen(path, "r");
+    rc = fscanf(fd, "%s", buf);
+    pclose(fd);
+
+    if (rc) return 0;
+    return 1;
+}
+
+static int get_usb_idVendor(libxl__gc *gc, const char *intf, char *buf)
+{
+    char *path;
+    int rc;
+    FILE *fd;
+
+    path = libxl__sprintf(gc, "cat "SYSFS_USB_DEVS_PATH"/%s/idVendor", intf);
+    fd = popen(path, "r");
+    rc = fscanf(fd, "%s", buf);
+    pclose(fd);
+
+    if (rc) return 0;
+    return 1;
+}
+
+static int get_usb_idProduct(libxl__gc *gc, const char *intf, char *buf)
+{
+    char *path;
+    int rc;
+    FILE *fd;
+
+    path = libxl__sprintf(gc, "cat "SYSFS_USB_DEVS_PATH"/%s/idProduct", intf);
+    fd = popen(path, "r");
+    rc = fscanf(fd, "%s", buf);
+    pclose(fd);
+
+    if (rc) return 0;
+    return 1;
+}
+
+static int get_usb_manufacturer(libxl__gc *gc, const char *intf, char *buf)
+{
+    char *path;
+    int rc;
+    FILE *fd;
+
+    path = libxl__sprintf(gc, "cat "SYSFS_USB_DEVS_PATH"/%s/manufacturer", intf);
+    fd = popen(path, "r");
+    rc = fscanf(fd, "%s", buf);
+    pclose(fd);
+
+    if (rc) return 0;
+    return 1;
+}
+
+static int get_usb_product(libxl__gc *gc, const char *intf, char *buf)
+{
+    char *path;
+    int rc;
+    FILE *fd;
+
+    path = libxl__sprintf(gc, "cat "SYSFS_USB_DEVS_PATH"/%s/product", intf);
+    fd = popen(path, "r");
+    rc = fscanf(fd, "%s", buf);
+    pclose(fd);
+
+    if (rc) return 0;
+    return 1;
+}
+
+int libxl_device_usb_getinfo(libxl_ctx *ctx, char *intf, libxl_usbinfo *usbinfo)
+{
+    GC_INIT(ctx);
+    char buf[20];
+
+    //change usb, why!!!!????
+    // maybe some better method to get this parameter
+
+    if (!get_usb_devnum(gc, intf, buf) ) 
+        usbinfo->devnum = atoi(buf);
+
+    if ( !get_usb_busnum(gc, intf, buf))
+        usbinfo->bus = atoi(buf);
+
+    if (!get_usb_idVendor(gc, intf, buf) )
+         usbinfo->idVendor = atoi(buf);
+
+    if (!get_usb_idProduct(gc, intf, buf) )
+        usbinfo->idProduct  = atoi(buf);
+
+    if (!get_usb_manufacturer(gc, intf, buf) )
+        usbinfo->manuf = strdup(buf);        
+    
+    if (!get_usb_product(gc, intf, buf) )
+        usbinfo->prod = strdup(buf);
+    
+    GC_FREE;
+    return 0; 
+}
+
+int libxl_hostdev_to_device_usb(libxl_ctx *ctx, uint32_t domid,
+                               int devid, libxl_device_usb *usb)
+{
+    return 0;
+}
+
+//If specified by user, no need to convert; otherwise, search for it
+int libxl_intf_to_device_usb(libxl_ctx *ctx, uint32_t domid,
+                               char *intf, libxl_device_usb *usb)
+{
+    GC_INIT(ctx);
+    libxl_device_usb *usbs;
+
+    int rc, num, i;
+
+    rc = libxl__device_usb_assigned_list(gc, &usbs, &num);
+    if(rc) goto out; 
+    
+    for (i = 0; i < num; i++) {
+        if (!strcmp(intf, usbs[i].intf) ) {
+            usb->ctrl = usbs[i].ctrl;
+            usb->port = usbs[i].port;
+            usb->intf = strdup(usbs[i].intf);
+            free(usbs);
+            return 0;
+        }
+    }
+out:
+    GC_FREE;
+    free(usbs);
+    return 1;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
-- 
1.7.10.4


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel

  reply	other threads:[~2014-08-10 20:23 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-08-10 20:23 [PATCH v0 RFC 0/2] xl/libxl support for PVUSB Bo Cao
2014-08-10 20:23 ` Bo Cao [this message]
2014-08-12 16:11   ` [PATCH v0 RFC 1/2] libxl: Introduce functions in libxl to add and remove USB devices for an PV guest Ian Jackson
2014-08-13 13:18     ` Simon Cao
2014-08-10 20:23 ` [PATCH v0 RFC 2/2] xl: Add commands for usb hot-plug Bo Cao
2014-08-14 15:04 ` [PATCH v0 RFC 0/2] xl/libxl support for PVUSB George Dunlap
2014-08-14 15:46   ` Simon Cao
2014-11-10  8:37 ` Chun Yan Liu
2014-11-10 15:01   ` Konrad Rzeszutek Wilk
2014-11-11  5:06     ` Juergen Gross
2014-11-16  2:36   ` Simon Cao
2014-11-19 21:32     ` Konrad Rzeszutek Wilk

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1407702234-22309-2-git-send-email-caobosimon@gmail.com \
    --to=caobosimon@gmail.com \
    --cc=george.dunlap@eu.citrix.com \
    --cc=ian.campbell@citrix.com \
    --cc=ian.jackson@citrix.com \
    --cc=lars.kurth@citrix.com \
    --cc=xen-devel@lists.xensource.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.