[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH v0 RFC 1/2] libxl: Introduce functions in libxl to add and remove USB devices for an PV guest



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@xxxxxxxxx>
---
CC: George Dunlap <george.dunlap@xxxxxxxxxxxxx>
CC: Ian Jackson <ian.jackson@xxxxxxxxxx>
CC: Ian Campbell <ian.campbell@xxxxxxxxxx>
CC: Pasi KÃrkkÃinen <pasik@xxxxxx>
CC: Lars Kurth <lars.kurth@xxxxxxxxxx>
---
 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@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.