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

[Xen-changelog] [xen master] libxl: rename libxl_pvusb.c to libxl_usb.c



commit 420a342d538f4d96f6a0cb23b219b86251db992a
Author:     Juergen Gross <jgross@xxxxxxxx>
AuthorDate: Thu Sep 8 09:20:21 2016 +0200
Commit:     Wei Liu <wei.liu2@xxxxxxxxxx>
CommitDate: Mon Sep 12 10:17:10 2016 +0100

    libxl: rename libxl_pvusb.c to libxl_usb.c
    
    Rename libxl_pvusb.c to libxl_usb.c in order to reflect future support
    of USB passthrough via qemu emulated USB controllers.
    
    Signed-off-by: Juergen Gross <jgross@xxxxxxxx>
    Acked-by: Wei Liu <wei.liu2@xxxxxxxxxx>
---
 tools/libxl/Makefile      |    2 +-
 tools/libxl/libxl_pvusb.c | 1727 ---------------------------------------------
 tools/libxl/libxl_usb.c   | 1727 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1728 insertions(+), 1728 deletions(-)

diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile
index 14a1a8e..a3c0af8 100644
--- a/tools/libxl/Makefile
+++ b/tools/libxl/Makefile
@@ -114,7 +114,7 @@ LIBXL_OBJS = flexarray.o libxl.o libxl_create.o libxl_dm.o 
libxl_pci.o \
                        libxl_stream_read.o libxl_stream_write.o \
                        libxl_save_callout.o _libxl_save_msgs_callout.o \
                        libxl_qmp.o libxl_event.o libxl_fork.o \
-                       libxl_dom_suspend.o libxl_dom_save.o libxl_pvusb.o \
+                       libxl_dom_suspend.o libxl_dom_save.o libxl_usb.o \
                        libxl_vtpm.o libxl_nic.o \
                         $(LIBXL_OBJS-y)
 LIBXL_OBJS += libxl_genid.o
diff --git a/tools/libxl/libxl_pvusb.c b/tools/libxl/libxl_pvusb.c
deleted file mode 100644
index 75f7b8b..0000000
--- a/tools/libxl/libxl_pvusb.c
+++ /dev/null
@@ -1,1727 +0,0 @@
-/*
- * Copyright (C) 2015 SUSE LINUX Products GmbH, Nuernberg, Germany.
- * Author Chunyan Liu <cyliu@xxxxxxxx>
- *
- * 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"
-#include <inttypes.h>
-
-#define USBBACK_INFO_PATH "/libxl/usbback"
-
-#define USBHUB_CLASS_CODE 9
-
-static int usbback_is_loaded(libxl__gc *gc)
-{
-    int r;
-    struct stat st;
-
-    r = lstat(SYSFS_USBBACK_DRIVER, &st);
-
-    if (r == 0)
-        return 1;
-    if (r < 0 && errno == ENOENT)
-        return 0;
-    LOGE(ERROR, "Accessing %s", SYSFS_USBBACK_DRIVER);
-    return ERROR_FAIL;
-}
-
-static int libxl__device_usbctrl_setdefault(libxl__gc *gc, uint32_t domid,
-                                            libxl_device_usbctrl *usbctrl)
-{
-    int rc;
-    libxl_domain_type domtype = libxl__domain_type(gc, domid);
-
-    if (!usbctrl->version)
-        usbctrl->version = 2;
-
-    if (!usbctrl->ports)
-        usbctrl->ports = 8;
-
-    if (usbctrl->type == LIBXL_USBCTRL_TYPE_AUTO) {
-        if (domtype == LIBXL_DOMAIN_TYPE_PV) {
-            rc = usbback_is_loaded(gc);
-            if (rc < 0)
-                goto out;
-            usbctrl->type = rc ? LIBXL_USBCTRL_TYPE_PV
-                               : LIBXL_USBCTRL_TYPE_QUSB;
-        } else if (domtype == LIBXL_DOMAIN_TYPE_HVM) {
-            /* FIXME: See if we can detect PV frontend */
-            usbctrl->type = LIBXL_USBCTRL_TYPE_DEVICEMODEL;
-        }
-    }
-
-    rc = libxl__resolve_domid(gc, usbctrl->backend_domname,
-                              &usbctrl->backend_domid);
-
-out:
-    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    = (usbctrl->type == LIBXL_USBCTRL_TYPE_PV)
-                              ? LIBXL__DEVICE_KIND_VUSB
-                              : LIBXL__DEVICE_KIND_QUSB;
-    device->devid           = usbctrl->devid;
-    device->domid           = domid;
-    device->kind            = LIBXL__DEVICE_KIND_VUSB;
-
-    return 0;
-}
-
-/* Add usbctrl information to xenstore.
- *
- * Adding a usb controller will add a new 'qusb' or 'vusb' device in xenstore,
- * and add corresponding frontend, backend information to it. According to
- * "update_json", decide whether to update json config file.
- */
-static int libxl__device_usbctrl_add_xenstore(libxl__gc *gc, uint32_t domid,
-                                              libxl_device_usbctrl *usbctrl,
-                                              bool update_json)
-{
-    libxl__device *device;
-    flexarray_t *front;
-    flexarray_t *back;
-    xs_transaction_t t = XBT_NULL;
-    int i, rc;
-    libxl_domain_config d_config;
-    libxl_device_usbctrl usbctrl_saved;
-    libxl__domain_userdata_lock *lock = NULL;
-
-    libxl_domain_config_init(&d_config);
-    libxl_device_usbctrl_init(&usbctrl_saved);
-    libxl_device_usbctrl_copy(CTX, &usbctrl_saved, usbctrl);
-
-    GCNEW(device);
-    rc = libxl__device_from_usbctrl(gc, domid, usbctrl, device);
-    if (rc) goto out;
-
-    front = flexarray_make(gc, 4, 1);
-    back = flexarray_make(gc, 12, 1);
-
-    flexarray_append_pair(back, "frontend-id", GCSPRINTF("%d", domid));
-    flexarray_append_pair(back, "online", "1");
-    flexarray_append_pair(back, "state",
-                          GCSPRINTF("%d", XenbusStateInitialising));
-    flexarray_append_pair(back, "type",
-                          (char *)libxl_usbctrl_type_to_string(usbctrl->type));
-    flexarray_append_pair(back, "usb-ver", GCSPRINTF("%d", usbctrl->version));
-    flexarray_append_pair(back, "num-ports", GCSPRINTF("%d", usbctrl->ports));
-    flexarray_append_pair(back, "port", "");
-    for (i = 0; i < usbctrl->ports; i++)
-        flexarray_append_pair(back, GCSPRINTF("port/%d", i + 1), "");
-
-    flexarray_append_pair(front, "backend-id",
-                          GCSPRINTF("%d", usbctrl->backend_domid));
-    flexarray_append_pair(front, "state",
-                          GCSPRINTF("%d", XenbusStateInitialising));
-
-    if (update_json) {
-        lock = libxl__lock_domain_userdata(gc, domid);
-        if (!lock) {
-            rc = ERROR_LOCK_FAIL;
-            goto out;
-        }
-
-        rc = libxl__get_domain_configuration(gc, domid, &d_config);
-        if (rc) goto out;
-
-        DEVICE_ADD(usbctrl, usbctrls, domid, &usbctrl_saved,
-                   COMPARE_USBCTRL, &d_config);
-
-        rc = libxl__dm_check_start(gc, &d_config, domid);
-        if (rc) goto out;
-
-        if (usbctrl->type == LIBXL_USBCTRL_TYPE_QUSB) {
-            if (!libxl__query_qemu_backend(gc, domid, usbctrl->backend_domid,
-                                           "qusb", false)) {
-                LOG(ERROR, "backend type not supported by device model");
-                rc = ERROR_FAIL;
-                goto out;
-            }
-        }
-    }
-
-    for (;;) {
-        rc = libxl__xs_transaction_start(gc, &t);
-        if (rc) goto out;
-
-        rc = libxl__device_exists(gc, t, device);
-        if (rc < 0) goto out;
-        if (rc == 1) {
-            /* already exists in xenstore */
-            LOG(ERROR, "device already exists in xenstore");
-            rc = ERROR_DEVICE_EXISTS;
-            goto out;
-        }
-
-        if (update_json) {
-            rc = libxl__set_domain_configuration(gc, domid, &d_config);
-            if (rc) goto out;
-        }
-
-        libxl__device_generic_add(gc, t, device,
-                          libxl__xs_kvs_of_flexarray(gc, back, back->count),
-                          libxl__xs_kvs_of_flexarray(gc, front, front->count),
-                          NULL);
-
-        rc = libxl__xs_transaction_commit(gc, &t);
-        if (!rc) break;
-        if (rc < 0) goto out;
-    }
-
-out:
-    libxl__xs_transaction_abort(gc, &t);
-    if (lock) libxl__unlock_domain_userdata(lock);
-    libxl_device_usbctrl_dispose(&usbctrl_saved);
-    libxl_domain_config_dispose(&d_config);
-    return rc;
-}
-
-static char *pvusb_get_device_type(libxl_usbctrl_type type)
-{
-    switch (type) {
-    case LIBXL_USBCTRL_TYPE_PV:
-        return "vusb";
-    case LIBXL_USBCTRL_TYPE_QUSB:
-        return "qusb";
-    default:
-        return NULL;
-    }
-}
-
-/* AO operation to add a usb controller.
- *
- * Generally, it does:
- * 1) fill in necessary usb controler information with default value
- * 2) write usb controller frontend/backend info to xenstore, update json
- *    config file if necessary.
- * 3) wait for device connection. PVUSB frontend and backend driver will
- *    probe xenstore paths and build connection between frontend and backend.
- *
- * Before calling this function, aodev should be properly filled:
- * aodev->ao, aodev->callback, aodev->update_json, ...
- */
-static void libxl__device_usbctrl_add(libxl__egc *egc, uint32_t domid,
-                                      libxl_device_usbctrl *usbctrl,
-                                      libxl__ao_device *aodev)
-{
-    STATE_AO_GC(aodev->ao);
-    libxl__device *device;
-    int rc;
-
-    rc = libxl__device_usbctrl_setdefault(gc, domid, usbctrl);
-    if (rc < 0) goto out;
-
-    if (usbctrl->devid == -1) {
-        usbctrl->devid = libxl__device_nextid(gc, domid, "vusb");
-        if (usbctrl->devid < 0) {
-            rc = ERROR_FAIL;
-            goto out;
-        }
-    }
-
-    if (usbctrl->type != LIBXL_USBCTRL_TYPE_PV &&
-        usbctrl->type != LIBXL_USBCTRL_TYPE_QUSB) {
-        LOG(ERROR, "Unsupported USB controller type");
-        rc = ERROR_FAIL;
-        goto out;
-    }
-
-    rc = libxl__device_usbctrl_add_xenstore(gc, domid, usbctrl,
-                                            aodev->update_json);
-    if (rc) goto out;
-
-    GCNEW(device);
-    rc = libxl__device_from_usbctrl(gc, domid, usbctrl, device);
-    if (rc) goto out;
-
-    aodev->dev = device;
-    aodev->action = LIBXL__DEVICE_ACTION_ADD;
-    libxl__wait_device_connection(egc, aodev);
-    return;
-
-out:
-    aodev->rc = rc;
-    aodev->callback(egc, aodev);
-    return;
-}
-
-LIBXL_DEFINE_DEVICE_ADD(usbctrl)
-static LIBXL_DEFINE_DEVICES_ADD(usbctrl)
-LIBXL_DEFINE_DEVICE_REMOVE_CUSTOM(usbctrl)
-
-static int libxl__device_usbdev_list_for_usbctrl(libxl__gc *gc, uint32_t domid,
-                                                 libxl_devid usbctrl,
-                                                 libxl_device_usbdev **usbdevs,
-                                                 int *num);
-
-static int libxl__device_usbdev_remove(libxl__gc *gc, uint32_t domid,
-                                       libxl_device_usbdev *usbdev);
-
-/* AO function to remove a usb controller.
- *
- * Generally, it does:
- * 1) check if the usb controller exists or not
- * 2) remove all usb devices under controller
- * 3) remove usb controller information from xenstore
- *
- * Before calling this function, aodev should be properly filled:
- * aodev->ao, aodev->dev, aodev->callback, ...
- */
-void libxl__initiate_device_usbctrl_remove(libxl__egc *egc,
-                                           libxl__ao_device *aodev)
-{
-    STATE_AO_GC(aodev->ao);
-    libxl_device_usbdev *usbdevs = NULL;
-    int num_usbdev = 0;
-    int i, rc;
-    uint32_t domid = ao->domid;
-    int usbctrl_devid = aodev->dev->devid;
-    libxl_device_usbctrl usbctrl;
-    libxl_usbctrlinfo usbctrlinfo;
-
-    libxl_device_usbctrl_init(&usbctrl);
-    libxl_usbctrlinfo_init(&usbctrlinfo);
-    usbctrl.devid = usbctrl_devid;
-
-    rc = libxl_device_usbctrl_getinfo(CTX, domid, &usbctrl, &usbctrlinfo);
-    if (rc) goto out;
-
-    if (usbctrlinfo.type != LIBXL_USBCTRL_TYPE_PV &&
-        usbctrlinfo.type != LIBXL_USBCTRL_TYPE_QUSB) {
-        LOG(ERROR, "Unsupported USB controller type");
-        rc = ERROR_FAIL;
-        goto out;
-    }
-
-    /* Remove usb devices first */
-    rc = libxl__device_usbdev_list_for_usbctrl(gc, domid, usbctrl_devid,
-                                               &usbdevs, &num_usbdev);
-    if (rc) goto out;
-
-    for (i = 0; i < num_usbdev; i++) {
-        rc = libxl__device_usbdev_remove(gc, domid, &usbdevs[i]);
-        if (rc) {
-            LOG(ERROR, "libxl__device_usbdev_remove failed: controller %d, "
-                "port %d", usbdevs[i].ctrl, usbdevs[i].port);
-            goto out;
-        }
-    }
-
-    libxl_device_usbctrl_dispose(&usbctrl);
-    libxl_usbctrlinfo_dispose(&usbctrlinfo);
-
-    /* Remove usbctrl */
-    libxl__initiate_device_generic_remove(egc, aodev);
-    return;
-
-out:
-    libxl_device_usbctrl_dispose(&usbctrl);
-    libxl_usbctrlinfo_dispose(&usbctrlinfo);
-    aodev->rc = rc;
-    aodev->callback(egc, aodev);
-    return;
-}
-
-static const char *vusb_be_from_xs_libxl(libxl__gc *gc, const char *libxl_path)
-{
-    const char *be_path;
-    int r;
-
-    r = libxl__xs_read_checked(gc, XBT_NULL,
-                               GCSPRINTF("%s/backend", libxl_path),
-                               &be_path);
-    if (r || !be_path) return NULL;
-
-    return be_path;
-}
-
-libxl_device_usbctrl *
-libxl_device_usbctrl_list(libxl_ctx *ctx, uint32_t domid, int *num)
-{
-    GC_INIT(ctx);
-    libxl_device_usbctrl *usbctrls = NULL;
-    char *libxl_vusbs_path = NULL;
-    char **entry = NULL;
-    unsigned int nentries = 0;
-
-    *num = 0;
-
-    libxl_vusbs_path = GCSPRINTF("%s/device/vusb",
-                     libxl__xs_libxl_path(gc, domid));
-    entry = libxl__xs_directory(gc, XBT_NULL, libxl_vusbs_path, &nentries);
-
-    if (entry && nentries) {
-        usbctrls = libxl__zalloc(NOGC, sizeof(*usbctrls) * nentries);
-        libxl_device_usbctrl *usbctrl;
-        libxl_device_usbctrl *end = usbctrls + nentries;
-        for (usbctrl = usbctrls;
-             usbctrl < end;
-             usbctrl++, entry++, (*num)++) {
-            const char *tmp, *be_path, *libxl_path;
-            int ret;
-
-            libxl_device_usbctrl_init(usbctrl);
-            usbctrl->devid = atoi(*entry);
-
-#define READ_SUBPATH(path, subpath) ({                                  \
-        ret = libxl__xs_read_checked(gc, XBT_NULL,                      \
-                                     GCSPRINTF("%s/" subpath, path),    \
-                                     &tmp);                             \
-        if (ret) goto out;                                              \
-        (char *)tmp;                                                    \
-    })
-
-#define READ_SUBPATH_INT(path, subpath) ({                              \
-        ret = libxl__xs_read_checked(gc, XBT_NULL,                      \
-                                     GCSPRINTF("%s/" subpath, path),    \
-                                     &tmp);                             \
-        if (ret) goto out;                                              \
-        tmp ? atoi(tmp) : -1;                                           \
-    })
-
-            libxl_path = GCSPRINTF("%s/%s", libxl_vusbs_path, *entry);
-            be_path = READ_SUBPATH(libxl_path, "backend");
-            if (!be_path) goto out;
-            ret = libxl__backendpath_parse_domid(gc, be_path,
-                                                &usbctrl->backend_domid);
-            if (ret) goto out;
-            usbctrl->version = READ_SUBPATH_INT(be_path, "usb-ver");
-            usbctrl->ports = READ_SUBPATH_INT(be_path, "num-ports");
-            libxl_usbctrl_type_from_string(READ_SUBPATH(libxl_path, "type"),
-                                           &usbctrl->type);
-
-#undef READ_SUBPATH
-#undef READ_SUBPATH_INT
-       }
-    }
-
-    GC_FREE;
-    return usbctrls;
-
-out:
-    LOG(ERROR, "Unable to list USB Controllers");
-    libxl_device_usbctrl_list_free(usbctrls, *num);
-    GC_FREE;
-    *num = 0;
-    return NULL;
-}
-
-int libxl_device_usbctrl_getinfo(libxl_ctx *ctx, uint32_t domid,
-                                 libxl_device_usbctrl *usbctrl,
-                                 libxl_usbctrlinfo *usbctrlinfo)
-{
-    GC_INIT(ctx);
-    const char *dompath, *fe_path, *be_path, *tmp;
-    const char *libxl_dom_path, *libxl_path;
-    int rc;
-
-    usbctrlinfo->devid = usbctrl->devid;
-
-#define READ_SUBPATH(path, subpath) ({                                  \
-        rc = libxl__xs_read_checked(gc, XBT_NULL,                       \
-                                    GCSPRINTF("%s/" subpath, path),     \
-                                    &tmp);                              \
-        if (rc) goto out;                                               \
-        (char *)tmp;                                                    \
-    })
-
-#define READ_SUBPATH_INT(path, subpath) ({                              \
-        rc = libxl__xs_read_checked(gc, XBT_NULL,                       \
-                                    GCSPRINTF("%s/" subpath, path),     \
-                                    &tmp);                              \
-        if (rc) goto out;                                               \
-        tmp ? atoi(tmp) : -1;                                           \
-    })
-
-    dompath = libxl__xs_get_dompath(gc, domid);
-    fe_path = GCSPRINTF("%s/device/vusb/%d", dompath, usbctrl->devid);
-    libxl_dom_path = libxl__xs_libxl_path(gc, domid);
-    libxl_path = GCSPRINTF("%s/device/vusb/%d", libxl_dom_path, 
usbctrl->devid);
-    be_path = READ_SUBPATH(libxl_path, "backend");
-    usbctrlinfo->backend = libxl__strdup(NOGC, be_path);
-    rc = libxl__backendpath_parse_domid(gc, be_path, &usbctrl->backend_domid);
-    if (rc) goto out;
-    usbctrlinfo->state = READ_SUBPATH_INT(fe_path, "state");
-    usbctrlinfo->evtch = READ_SUBPATH_INT(fe_path, "event-channel");
-    usbctrlinfo->ref_urb = READ_SUBPATH_INT(fe_path, "urb-ring-ref");
-    usbctrlinfo->ref_conn = READ_SUBPATH_INT(fe_path, "urb-ring-ref");
-    usbctrlinfo->frontend = libxl__strdup(NOGC, fe_path);
-    usbctrlinfo->frontend_id = domid;
-    usbctrlinfo->ports = READ_SUBPATH_INT(be_path, "num-ports");
-    usbctrlinfo->version = READ_SUBPATH_INT(be_path, "usb-ver");;
-    tmp = READ_SUBPATH(libxl_path, "type");
-    libxl_usbctrl_type_from_string(tmp, &usbctrlinfo->type);
-
-#undef READ_SUBPATH
-#undef READ_SUBPATH_INT
-
-    rc = 0;
-
-out:
-    GC_FREE;
-    return rc;
-}
-
-int libxl_devid_to_device_usbctrl(libxl_ctx *ctx,
-                                  uint32_t domid,
-                                  int devid,
-                                  libxl_device_usbctrl *usbctrl)
-{
-    libxl_device_usbctrl *usbctrls;
-    int nb = 0;
-    int i, rc;
-
-    usbctrls = libxl_device_usbctrl_list(ctx, domid, &nb);
-    if (!usbctrls) return ERROR_FAIL;
-
-    rc = ERROR_FAIL;
-    for (i = 0; i < nb; i++) {
-        if (devid == usbctrls[i].devid) {
-            libxl_device_usbctrl_copy(ctx, usbctrl, &usbctrls[i]);
-            rc = 0;
-            break;
-        }
-    }
-
-    libxl_device_usbctrl_list_free(usbctrls, nb);
-    return rc;
-}
-
-static char *usbdev_busaddr_to_busid(libxl__gc *gc, int bus, int addr)
-{
-    DIR *dir;
-    char *busid = NULL;
-    struct dirent *de;
-
-    /* invalid hostbus or hostaddr */
-    if (bus < 1 || addr < 1)
-        return NULL;
-
-    dir = opendir(SYSFS_USB_DEV);
-    if (!dir) {
-        LOGE(ERROR, "opendir failed: '%s'", SYSFS_USB_DEV);
-        return NULL;
-    }
-
-    for (;;) {
-        char *filename;
-        void *buf;
-        int busnum = -1;
-        int devnum = -1;
-
-        errno = 0;
-        de = readdir(dir);
-        if (!de && errno) {
-            LOGE(ERROR, "failed to readdir %s", SYSFS_USB_DEV);
-            break;
-        }
-        if (!de)
-            break;
-
-        if (!strcmp(de->d_name, ".") ||
-            !strcmp(de->d_name, ".."))
-            continue;
-
-        filename = GCSPRINTF(SYSFS_USB_DEV "/%s/devnum", de->d_name);
-        if (!libxl__read_sysfs_file_contents(gc, filename, &buf, NULL))
-            devnum = atoi(buf);
-
-        filename = GCSPRINTF(SYSFS_USB_DEV "/%s/busnum", de->d_name);
-        if (!libxl__read_sysfs_file_contents(gc, filename, &buf, NULL))
-            busnum = atoi(buf);
-
-        if (bus == busnum && addr == devnum) {
-            busid = libxl__strdup(gc, de->d_name);
-            break;
-        }
-    }
-
-    closedir(dir);
-    return busid;
-}
-
-static int usbdev_busaddr_from_busid(libxl__gc *gc, const char *busid,
-                                     uint8_t *bus, uint8_t *addr)
-{
-    char *filename;
-    void *buf;
-
-    filename = GCSPRINTF(SYSFS_USB_DEV "/%s/busnum", busid);
-    if (!libxl__read_sysfs_file_contents(gc, filename, &buf, NULL))
-        *bus = atoi(buf);
-    else
-        return ERROR_FAIL;
-
-    filename = GCSPRINTF(SYSFS_USB_DEV "/%s/devnum", busid);
-    if (!libxl__read_sysfs_file_contents(gc, filename, &buf, NULL))
-        *addr = atoi(buf);
-    else
-        return ERROR_FAIL;
-
-    return 0;
-}
-
-static int get_assigned_devices(libxl__gc *gc,
-                                libxl_device_usbdev **list, int *num)
-{
-    char **domlist;
-    unsigned int ndom = 0;
-    int i, j, k;
-    int rc;
-
-    *list = NULL;
-    *num = 0;
-
-    domlist = libxl__xs_directory(gc, XBT_NULL, "/local/domain", &ndom);
-    for (i = 0; i < ndom; i++) {
-        char *libxl_vusbs_path;
-        char **usbctrls;
-        unsigned int nc = 0;
-        uint32_t domid = atoi(domlist[i]);
-
-        libxl_vusbs_path = GCSPRINTF("%s/device/vusb",
-                                     libxl__xs_libxl_path(gc, domid));
-        usbctrls = libxl__xs_directory(gc, XBT_NULL,
-                                       libxl_vusbs_path, &nc);
-
-        for (j = 0; j < nc; j++) {
-            libxl_device_usbdev *tmp = NULL;
-            int nd = 0;
-
-            rc = libxl__device_usbdev_list_for_usbctrl(gc, domid,
-                                                       atoi(usbctrls[j]),
-                                                       &tmp, &nd);
-            if (rc) goto out;
-
-            if (!nd) continue;
-
-            GCREALLOC_ARRAY(*list, *num + nd);
-            for (k = 0; k < nd; k++) {
-                libxl_device_usbdev_copy(CTX, *list + *num, tmp + k);
-                (*num)++;
-            }
-        }
-    }
-
-    return 0;
-
-out:
-    LOG(ERROR, "fail to get assigned devices");
-    return rc;
-}
-
-static bool is_usbdev_in_array(libxl_device_usbdev *usbdevs, int num,
-                               libxl_device_usbdev *usbdev)
-{
-    int i;
-
-    for (i = 0; i < num; i++) {
-        if (usbdevs[i].u.hostdev.hostbus == usbdev->u.hostdev.hostbus &&
-            usbdevs[i].u.hostdev.hostaddr == usbdev->u.hostdev.hostaddr)
-            return true;
-    }
-
-    return false;
-}
-
-/* check if USB device type is assignable */
-static bool is_usbdev_assignable(libxl__gc *gc, libxl_device_usbdev *usbdev)
-{
-    int classcode;
-    char *filename;
-    void *buf = NULL;
-    char *busid = NULL;
-
-    busid = usbdev_busaddr_to_busid(gc, usbdev->u.hostdev.hostbus,
-                                    usbdev->u.hostdev.hostaddr);
-    if (!busid) return false;
-
-    filename = GCSPRINTF(SYSFS_USB_DEV "/%s/bDeviceClass", busid);
-    if (libxl__read_sysfs_file_contents(gc, filename, &buf, NULL))
-        return false;
-
-    classcode = atoi(buf);
-    return classcode != USBHUB_CLASS_CODE;
-}
-
-/* get usb devices under certain usb controller */
-static int
-libxl__device_usbdev_list_for_usbctrl(libxl__gc *gc,
-                                      uint32_t domid,
-                                      libxl_devid usbctrl,
-                                      libxl_device_usbdev **usbdevs,
-                                      int *num)
-{
-    const char *libxl_path, *be_path, *num_devs;
-    int n, i, rc;
-
-    *usbdevs = NULL;
-    *num = 0;
-
-    libxl_path = GCSPRINTF("%s/device/vusb/%d",
-                           libxl__xs_libxl_path(gc, domid), usbctrl);
-
-    be_path = vusb_be_from_xs_libxl(gc, libxl_path);
-    if (!be_path) {
-        rc = ERROR_FAIL;
-        goto out;
-    }
-
-    rc = libxl__xs_read_checked(gc, XBT_NULL,
-                                GCSPRINTF("%s/num-ports", be_path),
-                                &num_devs);
-    if (rc) goto out;
-
-    n = num_devs ? atoi(num_devs) : 0;
-
-    for (i = 0; i < n; i++) {
-        const char *busid;
-        libxl_device_usbdev *usbdev;
-
-        rc = libxl__xs_read_checked(gc, XBT_NULL,
-                                    GCSPRINTF("%s/port/%d", be_path, i + 1),
-                                    &busid);
-        if (rc) goto out;
-
-        if (busid && strcmp(busid, "")) {
-            GCREALLOC_ARRAY(*usbdevs, *num + 1);
-            usbdev = *usbdevs + *num;
-            (*num)++;
-            libxl_device_usbdev_init(usbdev);
-            usbdev->ctrl = usbctrl;
-            usbdev->port = i + 1;
-            usbdev->type = LIBXL_USBDEV_TYPE_HOSTDEV;
-            rc = usbdev_busaddr_from_busid(gc, busid,
-                                           &usbdev->u.hostdev.hostbus,
-                                           &usbdev->u.hostdev.hostaddr);
-            if (rc) goto out;
-        }
-    }
-
-    rc = 0;
-
-out:
-    return rc;
-}
-
-/* get all usb devices of the domain */
-libxl_device_usbdev *
-libxl_device_usbdev_list(libxl_ctx *ctx, uint32_t domid, int *num)
-{
-    GC_INIT(ctx);
-    libxl_device_usbdev *usbdevs = NULL;
-    const char *libxl_vusbs_path;
-    char **usbctrls;
-    unsigned int nc = 0;
-    int i, j;
-
-    *num = 0;
-
-    libxl_vusbs_path = GCSPRINTF("%s/device/vusb",
-                                 libxl__xs_libxl_path(gc, domid));
-    usbctrls = libxl__xs_directory(gc, XBT_NULL, libxl_vusbs_path, &nc);
-
-    for (i = 0; i < nc; i++) {
-        int rc, nd = 0;
-        libxl_device_usbdev *tmp = NULL;
-
-        rc = libxl__device_usbdev_list_for_usbctrl(gc, domid,
-                                                  atoi(usbctrls[i]),
-                                                  &tmp, &nd);
-        if (rc || !nd) continue;
-
-        usbdevs = libxl__realloc(NOGC, usbdevs,
-                                 sizeof(*usbdevs) * (*num + nd));
-        for (j = 0; j < nd; j++) {
-            libxl_device_usbdev_copy(ctx, usbdevs + *num, tmp + j);
-            (*num)++;
-        }
-    }
-
-    GC_FREE;
-    return usbdevs;
-}
-
-/* find first unused controller:port and give that to usb device */
-static int
-libxl__device_usbdev_set_default_usbctrl(libxl__gc *gc, uint32_t domid,
-                                         libxl_device_usbdev *usbdev)
-{
-    libxl_device_usbctrl *usbctrls = NULL;
-    int numctrl = 0;
-    int i, j, rc;
-
-    usbctrls = libxl_device_usbctrl_list(CTX, domid, &numctrl);
-    if (!numctrl || !usbctrls) {
-        rc = ERROR_FAIL;
-        goto out;
-    }
-
-    for (i = 0; i < numctrl; i++) {
-        for (j = 0; j < usbctrls[i].ports; j++) {
-            const char *path, *tmp;
-
-            path = GCSPRINTF("%s/backend/%s/%d/%d/port/%d",
-                             libxl__xs_get_dompath(gc, LIBXL_TOOLSTACK_DOMID),
-                             pvusb_get_device_type(usbctrls[i].type),
-                             domid, usbctrls[i].devid, j + 1);
-            rc = libxl__xs_read_checked(gc, XBT_NULL, path, &tmp);
-            if (rc) goto out;
-
-            if (tmp && !strcmp(tmp, "")) {
-                usbdev->ctrl = usbctrls[i].devid;
-                usbdev->port = j + 1;
-                rc = 0;
-                goto out;
-            }
-        }
-    }
-
-    /* no available controller:port */
-    rc = ERROR_FAIL;
-
-out:
-    libxl_device_usbctrl_list_free(usbctrls, numctrl);
-    return rc;
-}
-
-/* Fill in usb information with default value.
- *
- * Generally, it does:
- * 1) if "controller" is not specified:
- *    - if "port" is not specified, try to find an available controller:port,
- *      if found, use that; otherwise, create a new controller, use this
- *      controller and its first port
- *    - if "port" is specified, report error.
- * 2) if "controller" is specified, but port is not specified:
- *    try to find an available port under this controller, if found, use
- *    that, otherwise, report error.
- * 3) if both "controller" and "port" are specified:
- *    check the controller:port is available, if not, report error.
- */
-static int libxl__device_usbdev_setdefault(libxl__gc *gc,
-                                           uint32_t domid,
-                                           libxl_device_usbdev *usbdev,
-                                           bool update_json)
-{
-    int rc;
-
-    if (!usbdev->type)
-        usbdev->type = LIBXL_USBDEV_TYPE_HOSTDEV;
-
-    if (usbdev->ctrl == -1) {
-        if (usbdev->port) {
-            LOG(ERROR, "USB controller must be specified if you specify port");
-            return ERROR_INVAL;
-        }
-
-        rc = libxl__device_usbdev_set_default_usbctrl(gc, domid, usbdev);
-        /* If no existing controller to host this usb device, add a new one */
-        if (rc) {
-            libxl_device_usbctrl *usbctrl;
-
-            GCNEW(usbctrl);
-            libxl_device_usbctrl_init(usbctrl);
-            rc = libxl__device_usbctrl_setdefault(gc, domid, usbctrl);
-            if (rc < 0) goto out;
-
-            if (usbctrl->devid == -1) {
-                usbctrl->devid = libxl__device_nextid(gc, domid, "vusb");
-                if (usbctrl->devid < 0) {
-                    rc = ERROR_FAIL;
-                    goto out;
-                }
-            }
-
-            if (usbctrl->type != LIBXL_USBCTRL_TYPE_PV &&
-                usbctrl->type != LIBXL_USBCTRL_TYPE_QUSB) {
-                LOG(ERROR, "Unsupported USB controller type");
-                rc = ERROR_FAIL;
-                goto out;
-            }
-
-            rc = libxl__device_usbctrl_add_xenstore(gc, domid, usbctrl,
-                                                    update_json);
-            if (rc) goto out;
-
-            usbdev->ctrl = usbctrl->devid;
-            usbdev->port = 1;
-        }
-    } else {
-        /* A controller was specified; look it up */
-        const char *libxl_path, *be_path, *tmp;
-
-        libxl_path = GCSPRINTF("%s/device/vusb/%d",
-                            libxl__xs_libxl_path(gc, domid),
-                            usbdev->ctrl);
-
-        be_path = vusb_be_from_xs_libxl(gc, libxl_path);
-        if (!be_path) {
-            rc = ERROR_FAIL;
-            goto out;
-        }
-
-        if (usbdev->port) {
-            /* A specific port was requested; see if it's available */
-            rc = libxl__xs_read_checked(gc, XBT_NULL,
-                                        GCSPRINTF("%s/port/%d",
-                                                  be_path, usbdev->port),
-                                        &tmp);
-            if (rc) goto out;
-
-            if (tmp && strcmp(tmp, "")) {
-                LOG(ERROR, "The controller port isn't available");
-                rc = ERROR_FAIL;
-                goto out;
-            }
-        } else {
-            /* No port was requested. Choose free port. */
-            int i, ports;
-
-            rc = libxl__xs_read_checked(gc, XBT_NULL,
-                                        GCSPRINTF("%s/num-ports", be_path), 
&tmp);
-            if (rc) goto out;
-
-            ports = tmp ? atoi(tmp) : 0;
-
-            for (i = 0; i < ports; i++) {
-                rc = libxl__xs_read_checked(gc, XBT_NULL,
-                                            GCSPRINTF("%s/port/%d", be_path, i 
+ 1),
-                                            &tmp);
-                if (rc) goto out;
-
-                if (tmp && !strcmp(tmp, "")) {
-                    usbdev->port = i + 1;
-                    break;
-                }
-            }
-
-            if (!usbdev->port) {
-                LOG(ERROR, "No available port under specified controller");
-                rc = ERROR_FAIL;
-                goto out;
-            }
-        }
-    }
-
-    rc = 0;
-
-out:
-    return rc;
-}
-
-/* Add usb information to xenstore
- *
- * Adding a usb device won't create new 'qusb'/'vusb' device, but only write
- * the device busid to the controller:port in xenstore.
- */
-static int libxl__device_usbdev_add_xenstore(libxl__gc *gc, uint32_t domid,
-                                             libxl_device_usbdev *usbdev,
-                                             libxl_usbctrl_type type,
-                                             bool update_json)
-{
-    char *be_path, *busid;
-    int rc;
-    xs_transaction_t t = XBT_NULL;
-    libxl_domain_config d_config;
-    libxl_device_usbdev usbdev_saved;
-    libxl__domain_userdata_lock *lock = NULL;
-
-    libxl_domain_config_init(&d_config);
-    libxl_device_usbdev_init(&usbdev_saved);
-    libxl_device_usbdev_copy(CTX, &usbdev_saved, usbdev);
-
-    busid = usbdev_busaddr_to_busid(gc, usbdev->u.hostdev.hostbus,
-                                    usbdev->u.hostdev.hostaddr);
-    if (!busid) {
-        LOG(DEBUG, "Fail to get busid of usb device");
-        rc = ERROR_FAIL;
-        goto out;
-    }
-
-    if (update_json) {
-        lock = libxl__lock_domain_userdata(gc, domid);
-        if (!lock) {
-            rc = ERROR_LOCK_FAIL;
-            goto out;
-        }
-
-        rc = libxl__get_domain_configuration(gc, domid, &d_config);
-        if (rc) goto out;
-
-        DEVICE_ADD(usbdev, usbdevs, domid, &usbdev_saved,
-                   COMPARE_USB, &d_config);
-
-        rc = libxl__dm_check_start(gc, &d_config, domid);
-        if (rc) goto out;
-    }
-
-    for (;;) {
-        rc = libxl__xs_transaction_start(gc, &t);
-        if (rc) goto out;
-
-        if (update_json) {
-            rc = libxl__set_domain_configuration(gc, domid, &d_config);
-            if (rc) goto out;
-        }
-
-        be_path = GCSPRINTF("%s/backend/%s/%d/%d/port/%d",
-                            libxl__xs_get_dompath(gc, LIBXL_TOOLSTACK_DOMID),
-                            pvusb_get_device_type(type),
-                            domid, usbdev->ctrl, usbdev->port);
-
-        LOG(DEBUG, "Adding usb device %s to xenstore: controller %d, port %d",
-            busid, usbdev->ctrl, usbdev->port);
-
-        rc = libxl__xs_write_checked(gc, t, be_path, busid);
-        if (rc) goto out;
-
-        rc = libxl__xs_transaction_commit(gc, &t);
-        if (!rc) break;
-        if (rc < 0) goto out;
-    }
-
-    rc = 0;
-
-out:
-    if (lock) libxl__unlock_domain_userdata(lock);
-    libxl_device_usbdev_dispose(&usbdev_saved);
-    libxl_domain_config_dispose(&d_config);
-    return rc;
-}
-
-static int libxl__device_usbdev_remove_xenstore(libxl__gc *gc, uint32_t domid,
-                                                libxl_device_usbdev *usbdev,
-                                                libxl_usbctrl_type type)
-{
-    char *be_path;
-
-    be_path = GCSPRINTF("%s/backend/%s/%d/%d/port/%d",
-                        libxl__xs_get_dompath(gc, LIBXL_TOOLSTACK_DOMID),
-                        pvusb_get_device_type(type),
-                        domid, usbdev->ctrl, usbdev->port);
-
-    LOG(DEBUG, "Removing usb device from xenstore: controller %d, port %d",
-        usbdev->ctrl, usbdev->port);
-
-    return libxl__xs_write_checked(gc, XBT_NULL, be_path, "");
-}
-
-static char *usbdev_busid_from_ctrlport(libxl__gc *gc, uint32_t domid,
-                                        libxl_device_usbdev *usbdev,
-                                        libxl_usbctrl_type type)
-{
-    return libxl__xs_read(gc, XBT_NULL,
-                          GCSPRINTF("%s/backend/%s/%d/%d/port/%d",
-                              libxl__xs_get_dompath(gc, LIBXL_TOOLSTACK_DOMID),
-                              pvusb_get_device_type(type),
-                              domid, usbdev->ctrl, usbdev->port));
-}
-
-/* get original driver path of usb interface, stored in @drvpath */
-static int usbintf_get_drvpath(libxl__gc *gc, const char *intf, char **drvpath)
-{
-    char *spath, *dp = NULL;
-
-    spath = GCSPRINTF(SYSFS_USB_DEV "/%s/driver", intf);
-
-    /* Find the canonical path to the driver. */
-    dp = libxl__zalloc(gc, PATH_MAX);
-    dp = realpath(spath, dp);
-    if (!dp && errno != ENOENT) {
-        LOGE(ERROR, "get realpath failed: '%s'", spath);
-        return ERROR_FAIL;
-    }
-
-    *drvpath = dp;
-
-    return 0;
-}
-
-static int unbind_usbintf(libxl__gc *gc, const char *intf)
-{
-    char *path;
-    int fd = -1;
-    int rc;
-
-    path = GCSPRINTF(SYSFS_USB_DEV "/%s/driver/unbind", intf);
-
-    fd = open(path, O_WRONLY);
-    if (fd < 0) {
-        LOGE(ERROR, "open file failed: '%s'", path);
-        rc = ERROR_FAIL;
-        goto out;
-    }
-
-    if (libxl_write_exactly(CTX, fd, intf, strlen(intf), path, intf)) {
-        rc = ERROR_FAIL;
-        goto out;
-    }
-
-    rc = 0;
-
-out:
-    if (fd >= 0) close(fd);
-    return rc;
-}
-
-static int bind_usbintf(libxl__gc *gc, const char *intf, const char *drvpath)
-{
-    char *bind_path, *intf_path;
-    struct stat st;
-    int fd = -1;
-    int rc, r;
-
-    intf_path = GCSPRINTF("%s/%s", drvpath, intf);
-
-    /* check through lstat, if intf already exists under drvpath,
-     * it's already bound, return directly; if it doesn't exist,
-     * continue to do bind work; otherwise, return error.
-     */
-    r = lstat(intf_path, &st);
-    if (r == 0)
-        return 0;
-    if (r < 0 && errno != ENOENT)
-        return ERROR_FAIL;
-
-    bind_path = GCSPRINTF("%s/bind", drvpath);
-
-    fd = open(bind_path, O_WRONLY);
-    if (fd < 0) {
-        LOGE(ERROR, "open file failed: '%s'", bind_path);
-        rc = ERROR_FAIL;
-        goto out;
-    }
-
-    if (libxl_write_exactly(CTX, fd, intf, strlen(intf), bind_path, intf)) {
-        rc = ERROR_FAIL;
-        goto out;
-    }
-
-    rc = 0;
-
-out:
-    if (fd >= 0) close(fd);
-    return rc;
-}
-
-/* Is usb interface bound to usbback? */
-static int usbintf_is_assigned(libxl__gc *gc, char *intf)
-{
-    char *spath;
-    int r;
-    struct stat st;
-
-    spath = GCSPRINTF(SYSFS_USBBACK_DRIVER "/%s", intf);
-    r = lstat(spath, &st);
-
-    if (r == 0)
-        return 1;
-    if (r < 0 && errno == ENOENT)
-        return 0;
-    LOGE(ERROR, "Accessing %s", spath);
-    return -1;
-}
-
-static int usbdev_get_all_interfaces(libxl__gc *gc, const char *busid,
-                                     char ***intfs, int *num)
-{
-    DIR *dir;
-    char *buf;
-    struct dirent *de;
-    int rc;
-
-    *intfs = NULL;
-    *num = 0;
-
-    buf = GCSPRINTF("%s:", busid);
-
-    dir = opendir(SYSFS_USB_DEV);
-    if (!dir) {
-        LOGE(ERROR, "opendir failed: '%s'", SYSFS_USB_DEV);
-        return ERROR_FAIL;
-    }
-
-    for (;;) {
-        errno = 0;
-        de = readdir(dir);
-
-        if (!de && errno) {
-            LOGE(ERROR, "failed to readdir %s", SYSFS_USB_DEV);
-            rc = ERROR_FAIL;
-            goto out;
-        }
-        if (!de)
-            break;
-
-        if (!strcmp(de->d_name, ".") ||
-            !strcmp(de->d_name, ".."))
-            continue;
-
-        if (!strncmp(de->d_name, buf, strlen(buf))) {
-            GCREALLOC_ARRAY(*intfs, *num + 1);
-            (*intfs)[*num] = libxl__strdup(gc, de->d_name);
-            (*num)++;
-        }
-    }
-
-    rc = 0;
-
-out:
-    closedir(dir);
-    return rc;
-}
-
-/* Encode usb interface so that it could be written to xenstore as a key.
- *
- * Since xenstore key cannot include '.' or ':', we'll change '.' to '_',
- * change ':' to '@'. For example, 3-1:2.1 will be encoded to 3-1@2_1.
- * This will be used to save original driver of USB device to xenstore.
- */
-static char *usb_interface_xenstore_encode(libxl__gc *gc, const char *busid)
-{
-    char *str = libxl__strdup(gc, busid);
-    int i, len = strlen(str);
-
-    for (i = 0; i < len; i++) {
-        if (str[i] == '.') str[i] = '_';
-        if (str[i] == ':') str[i] = '@';
-    }
-    return str;
-}
-
-/* Unbind USB device from "usbback" driver.
- *
- * If there are many interfaces under USB device, check each interface,
- * unbind from "usbback" driver.
- */
-static int usbback_dev_unassign(libxl__gc *gc, const char *busid)
-{
-    char **intfs = NULL;
-    int i, num = 0;
-    int rc;
-
-    rc = usbdev_get_all_interfaces(gc, busid, &intfs, &num);
-    if (rc) goto out;
-
-    for (i = 0; i < num; i++) {
-        char *intf = intfs[i];
-
-        /* check if the USB interface is already bound to "usbback" */
-        if (usbintf_is_assigned(gc, intf) > 0) {
-            /* unbind interface from usbback driver */
-            rc = unbind_usbintf(gc, intf);
-            if (rc) {
-                LOGE(ERROR, "Couldn't unbind %s from usbback", intf);
-                goto out;
-            }
-        }
-    }
-
-    rc = 0;
-
-out:
-    return rc;
-}
-
-/* rebind USB device to original driver.
- *
- * If there are many interfaces under USB device, for reach interface,
- * read driver_path from xenstore (if there is) and rebind to its
- * original driver, then remove driver_path information from xenstore.
- */
-static int usbdev_rebind(libxl__gc *gc, const char *busid)
-{
-    char **intfs = NULL;
-    char *usbdev_encode = NULL;
-    char *path = NULL;
-    int i, num = 0;
-    int rc;
-
-    rc = usbdev_get_all_interfaces(gc, busid, &intfs, &num);
-    if (rc) goto out;
-
-    usbdev_encode = usb_interface_xenstore_encode(gc, busid);
-
-    for (i = 0; i < num; i++) {
-        char *intf = intfs[i];
-        char *usbintf_encode = NULL;
-        const char *drvpath;
-
-        /* rebind USB interface to its originial driver */
-        usbintf_encode = usb_interface_xenstore_encode(gc, intf);
-        path = GCSPRINTF(USBBACK_INFO_PATH "/%s/%s/driver_path",
-                         usbdev_encode, usbintf_encode);
-        rc = libxl__xs_read_checked(gc, XBT_NULL, path, &drvpath);
-        if (rc) goto out;
-
-        if (drvpath) {
-            rc = bind_usbintf(gc, intf, drvpath);
-            if (rc) {
-                LOGE(ERROR, "Couldn't rebind %s to %s", intf, drvpath);
-                goto out;
-            }
-        }
-    }
-
-out:
-    path = GCSPRINTF(USBBACK_INFO_PATH "/%s", usbdev_encode);
-    libxl__xs_rm_checked(gc, XBT_NULL, path);
-    return rc;
-}
-
-
-/* Bind USB device to "usbback" driver.
- *
- * If there are many interfaces under USB device, check each interface,
- * unbind from original driver and bind to "usbback" driver.
- */
-static int usbback_dev_assign(libxl__gc *gc, const char *busid)
-{
-    char **intfs = NULL;
-    int num = 0, i;
-    int rc;
-    char *usbdev_encode = NULL;
-
-    rc = usbdev_get_all_interfaces(gc, busid, &intfs, &num);
-    if (rc) return rc;
-
-    usbdev_encode = usb_interface_xenstore_encode(gc, busid);
-
-    for (i = 0; i < num; i++) {
-        char *intf = intfs[i];
-        char *drvpath = NULL;
-
-        /* already assigned to usbback */
-        if (usbintf_is_assigned(gc, intf) > 0)
-            continue;
-
-        rc = usbintf_get_drvpath(gc, intf, &drvpath);
-        if (rc) goto out;
-
-        if (drvpath) {
-            /* write driver path to xenstore for later rebinding */
-            char *usbintf_encode = NULL;
-            char *path;
-
-            usbintf_encode = usb_interface_xenstore_encode(gc, intf);
-            path = GCSPRINTF(USBBACK_INFO_PATH "/%s/%s/driver_path",
-                             usbdev_encode, usbintf_encode);
-            rc = libxl__xs_write_checked(gc, XBT_NULL, path, drvpath);
-            if (rc) goto out;
-
-            /* unbind interface from original driver */
-            rc = unbind_usbintf(gc, intf);
-            if (rc) goto out;
-        }
-
-        /* bind interface to usbback */
-        rc = bind_usbintf(gc, intf, SYSFS_USBBACK_DRIVER);
-        if (rc) {
-            LOG(ERROR, "Couldn't bind %s to %s", intf, SYSFS_USBBACK_DRIVER);
-            goto out;
-        }
-    }
-
-    return 0;
-
-out:
-    /* some interfaces might be bound to usbback, unbind it and
-     * rebind it to its original driver
-     */
-    usbback_dev_unassign(gc, busid);
-    usbdev_rebind(gc, busid);
-    return rc;
-}
-
-static int do_usbdev_add(libxl__gc *gc, uint32_t domid,
-                         libxl_device_usbdev *usbdev,
-                         bool update_json)
-{
-    int rc;
-    char *busid;
-    libxl_device_usbctrl usbctrl;
-    libxl_usbctrlinfo usbctrlinfo;
-
-    libxl_device_usbctrl_init(&usbctrl);
-    libxl_usbctrlinfo_init(&usbctrlinfo);
-    usbctrl.devid = usbdev->ctrl;
-
-    rc = libxl_device_usbctrl_getinfo(CTX, domid, &usbctrl, &usbctrlinfo);
-    if (rc) goto out;
-
-    switch (usbctrlinfo.type) {
-    case LIBXL_USBCTRL_TYPE_PV:
-        busid = usbdev_busaddr_to_busid(gc, usbdev->u.hostdev.hostbus,
-                                        usbdev->u.hostdev.hostaddr);
-        if (!busid) {
-            rc = ERROR_FAIL;
-            goto out;
-        }
-
-        rc = libxl__device_usbdev_add_xenstore(gc, domid, usbdev,
-                                               LIBXL_USBCTRL_TYPE_PV,
-                                               update_json);
-        if (rc) goto out;
-
-        rc = usbback_dev_assign(gc, busid);
-        if (rc) {
-            libxl__device_usbdev_remove_xenstore(gc, domid, usbdev,
-                                                 LIBXL_USBCTRL_TYPE_PV);
-            goto out;
-        }
-        break;
-    case LIBXL_USBCTRL_TYPE_QUSB:
-        rc = libxl__device_usbdev_add_xenstore(gc, domid, usbdev,
-                                               LIBXL_USBCTRL_TYPE_QUSB,
-                                               update_json);
-        if (rc) goto out;
-
-        break;
-    case LIBXL_USBCTRL_TYPE_DEVICEMODEL:
-    default:
-        LOG(ERROR, "Unsupported usb controller type");
-        rc = ERROR_FAIL;
-        goto out;
-    }
-
-    rc = 0;
-
-out:
-    libxl_device_usbctrl_dispose(&usbctrl);
-    libxl_usbctrlinfo_dispose(&usbctrlinfo);
-    return rc;
-}
-
-/* AO operation to add a usb device.
- *
- * Generally, it does:
- * 1) check if the usb device type is assignable
- * 2) check if the usb device is already assigned to a domain
- * 3) add 'busid' of the usb device to xenstore contoller/port/.
- *    (PVUSB driver watches the xenstore changes and will detect that.)
- * 4) unbind usb device from original driver and bind to usbback.
- *    If usb device has many interfaces, then:
- *    - unbind each interface from its original driver and bind to usbback.
- *    - store the original driver to xenstore for later rebinding when
- *      detaching the device.
- *
- * Before calling this function, aodev should be properly filled:
- * aodev->ao, aodev->callback, aodev->update_json, ...
- */
-static void libxl__device_usbdev_add(libxl__egc *egc, uint32_t domid,
-                                     libxl_device_usbdev *usbdev,
-                                     libxl__ao_device *aodev)
-{
-    STATE_AO_GC(aodev->ao);
-    int rc;
-    libxl_device_usbdev *assigned;
-    int num_assigned;
-    libxl_device_usbctrl usbctrl;
-    libxl_usbctrlinfo usbctrlinfo;
-
-    libxl_device_usbctrl_init(&usbctrl);
-    libxl_usbctrlinfo_init(&usbctrlinfo);
-
-    /* Currently only support adding USB device from Dom0 backend.
-     * So, if USB controller is specified, check its backend domain,
-     * if it's not Dom0, report error.
-     */
-    if (usbdev->ctrl != -1) {
-        usbctrl.devid = usbdev->ctrl;
-        rc = libxl_device_usbctrl_getinfo(CTX, domid, &usbctrl, &usbctrlinfo);
-        if (rc) goto out;
-
-        if (usbctrlinfo.backend_id != LIBXL_TOOLSTACK_DOMID) {
-            LOG(ERROR, "Don't support adding USB device from non-Dom0 
backend");
-            rc = ERROR_INVAL;
-            goto out;
-        }
-    }
-
-    /* check usb device is assignable type */
-    if (!is_usbdev_assignable(gc, usbdev)) {
-        LOG(ERROR, "USB device is not assignable.");
-        rc = ERROR_FAIL;
-        goto out;
-    }
-
-    /* check usb device is already assigned */
-    rc = get_assigned_devices(gc, &assigned, &num_assigned);
-    if (rc) {
-        LOG(ERROR, "cannot determine if device is assigned,"
-                   " refusing to continue");
-        goto out;
-    }
-
-    if (is_usbdev_in_array(assigned, num_assigned, usbdev)) {
-        LOG(ERROR, "USB device already attached to a domain");
-        rc = ERROR_INVAL;
-        goto out;
-    }
-
-    /* fill default values, e.g, if usbdev->ctrl and usbdev->port
-     * not specified, choose available controller:port and fill in. */
-    rc = libxl__device_usbdev_setdefault(gc, domid, usbdev,
-                                         aodev->update_json);
-    if (rc) goto out;
-
-    /* do actual adding usb device operation */
-    rc = do_usbdev_add(gc, domid, usbdev, aodev->update_json);
-
-out:
-    libxl_device_usbctrl_dispose(&usbctrl);
-    libxl_usbctrlinfo_dispose(&usbctrlinfo);
-    aodev->rc = rc;
-    aodev->callback(egc, aodev);
-    return;
-}
-
-LIBXL_DEFINE_DEVICE_ADD(usbdev)
-static LIBXL_DEFINE_DEVICES_ADD(usbdev)
-
-static int do_usbdev_remove(libxl__gc *gc, uint32_t domid,
-                            libxl_device_usbdev *usbdev)
-{
-    int rc;
-    char *busid;
-    libxl_device_usbctrl usbctrl;
-    libxl_usbctrlinfo usbctrlinfo;
-
-    libxl_device_usbctrl_init(&usbctrl);
-    libxl_usbctrlinfo_init(&usbctrlinfo);
-    usbctrl.devid = usbdev->ctrl;
-
-    rc = libxl_device_usbctrl_getinfo(CTX, domid, &usbctrl, &usbctrlinfo);
-    if (rc) goto out;
-
-    switch (usbctrlinfo.type) {
-    case LIBXL_USBCTRL_TYPE_PV:
-        busid = usbdev_busid_from_ctrlport(gc, domid, usbdev, 
usbctrlinfo.type);
-        if (!busid) {
-            rc = ERROR_FAIL;
-            goto out;
-        }
-
-        /* Things are done in order of:
-         *   unbind USB device from usbback,
-         *   remove USB device from xenstore,
-         *   rebind USB device to original driver.
-         * It is to balance simplicity with robustness in case of failure:
-         * - We unbind all interfaces before rebinding any interfaces, so
-         *   that we never get into a situation where some interfaces are
-         *   assigned to usbback and some are assigned to the original drivers.
-         * - We also unbind the interfaces before removing the pvusb xenstore
-         *   nodes, so that if the unbind fails in the middle, the device still
-         *   shows up in xl usb-list, and the user can re-try removing it.
-         */
-        rc = usbback_dev_unassign(gc, busid);
-        if (rc) {
-            LOG(ERROR, "Error removing device from guest."
-                " Try running usbdev-detach again.");
-            goto out;
-        }
-
-        rc = libxl__device_usbdev_remove_xenstore(gc, domid, usbdev,
-                                                  LIBXL_USBCTRL_TYPE_PV);
-        if (rc) {
-            LOG(ERROR, "Error removing device from guest."
-                " Try running usbdev-detach again.");
-            goto out;
-        }
-
-        rc = usbdev_rebind(gc, busid);
-        if (rc) {
-            LOG(ERROR, "USB device removed from guest, but couldn't"
-                " re-bind to domain 0. Try removing and re-inserting"
-                " the USB device or reloading the driver modules.");
-            goto out;
-        }
-
-        break;
-    case LIBXL_USBCTRL_TYPE_QUSB:
-        rc = libxl__device_usbdev_remove_xenstore(gc, domid, usbdev,
-                                                  LIBXL_USBCTRL_TYPE_QUSB);
-        if (rc) goto out;
-
-        break;
-    case LIBXL_USBCTRL_TYPE_DEVICEMODEL:
-    default:
-        LOG(ERROR, "Unsupported usb controller type");
-        rc = ERROR_FAIL;
-        goto out;
-    }
-
-    rc = 0;
-
-out:
-    libxl_device_usbctrl_dispose(&usbctrl);
-    libxl_usbctrlinfo_dispose(&usbctrlinfo);
-    return rc;
-}
-
-/* Operation to remove usb device.
- *
- * Generally, it does:
- * 1) check if the usb device is assigned to the domain
- * 2) remove the usb device from xenstore controller/port.
- * 3) unbind usb device from usbback and rebind to its original driver.
- *    If usb device has many interfaces, do it to each interface.
- */
-static int libxl__device_usbdev_remove(libxl__gc *gc, uint32_t domid,
-                                       libxl_device_usbdev *usbdev)
-{
-    libxl_usbctrlinfo usbctrlinfo;
-    libxl_device_usbctrl usbctrl;
-    int rc;
-
-    if (usbdev->ctrl < 0 || usbdev->port < 1) {
-        LOG(ERROR, "Invalid USB device");
-        return ERROR_FAIL;
-    }
-
-    libxl_device_usbctrl_init(&usbctrl);
-    libxl_usbctrlinfo_init(&usbctrlinfo);
-    usbctrl.devid = usbdev->ctrl;
-
-    rc = libxl_device_usbctrl_getinfo(CTX, domid, &usbctrl, &usbctrlinfo);
-    if (rc) goto out;
-
-    if (usbctrlinfo.backend_id != LIBXL_TOOLSTACK_DOMID) {
-        LOG(ERROR, "Don't support removing USB device from non-Dom0 backend");
-        rc = ERROR_INVAL;
-        goto out;
-    }
-
-    /* do actual removing usb device operation */
-    rc = do_usbdev_remove(gc, domid, usbdev);
-
-out:
-    libxl_device_usbctrl_dispose(&usbctrl);
-    libxl_usbctrlinfo_dispose(&usbctrlinfo);
-    return rc;
-}
-
-int libxl_device_usbdev_remove(libxl_ctx *ctx, uint32_t domid,
-                               libxl_device_usbdev *usbdev,
-                               const libxl_asyncop_how *ao_how)
-
-{
-    AO_CREATE(ctx, domid, ao_how);
-    int rc;
-
-    rc = libxl__device_usbdev_remove(gc, domid, usbdev);
-
-    libxl__ao_complete(egc, ao, rc);
-    return AO_INPROGRESS;
-}
-
-int libxl_ctrlport_to_device_usbdev(libxl_ctx *ctx,
-                                    uint32_t domid,
-                                    int ctrl,
-                                    int port,
-                                    libxl_device_usbdev *usbdev)
-{
-    GC_INIT(ctx);
-    const char *libxl_dom_path, *libxl_path, *be_path, *busid;
-    int rc;
-
-    libxl_dom_path = libxl__xs_libxl_path(gc, domid);
-
-    libxl_path = GCSPRINTF("%s/device/vusb/%d", libxl_dom_path, ctrl);
-    be_path = vusb_be_from_xs_libxl(gc, libxl_path);
-    if (!be_path) {
-        rc = ERROR_FAIL;
-        goto out;
-    }
-
-    rc = libxl__xs_read_checked(gc, XBT_NULL,
-                           GCSPRINTF("%s/port/%d", be_path, port),
-                           &busid);
-    if (rc) goto out;
-
-    if (!busid || !strcmp(busid, "")) {
-        rc = ERROR_FAIL;
-        goto out;
-    }
-
-    usbdev->ctrl = ctrl;
-    usbdev->port = port;
-    usbdev->type = LIBXL_USBDEV_TYPE_HOSTDEV;
-    rc = usbdev_busaddr_from_busid(gc, busid,
-                                   &usbdev->u.hostdev.hostbus,
-                                   &usbdev->u.hostdev.hostaddr);
-
-out:
-    GC_FREE;
-    return rc;
-}
-
-static int libxl_device_usbctrl_compare(libxl_device_usbctrl *d1,
-                                        libxl_device_usbctrl *d2)
-{
-    return COMPARE_USBCTRL(d1, d2);
-}
-
-static int libxl_device_usbctrl_dm_needed(void *e, unsigned domid)
-{
-    libxl_device_usbctrl *elem = e;
-
-    return elem->type == LIBXL_USBCTRL_TYPE_QUSB &&
-           elem->backend_domid == domid;
-}
-
-static int libxl_device_usbdev_compare(libxl_device_usbdev *d1,
-                                       libxl_device_usbdev *d2)
-{
-    return COMPARE_USB(d1, d2);
-}
-
-void libxl_device_usbctrl_list_free(libxl_device_usbctrl *list, int nr)
-{
-   int i;
-
-   for (i = 0; i < nr; i++)
-       libxl_device_usbctrl_dispose(&list[i]);
-   free(list);
-}
-
-void libxl_device_usbdev_list_free(libxl_device_usbdev *list, int nr)
-{
-   int i;
-
-   for (i = 0; i < nr; i++)
-       libxl_device_usbdev_dispose(&list[i]);
-   free(list);
-}
-
-DEFINE_DEVICE_TYPE_STRUCT(usbctrl,
-    .dm_needed = libxl_device_usbctrl_dm_needed
-);
-DEFINE_DEVICE_TYPE_STRUCT(usbdev);
-
-/*
- * Local variables:
- * mode: C
- * c-basic-offset: 4
- * indent-tabs-mode: nil
- * End:
- */
diff --git a/tools/libxl/libxl_usb.c b/tools/libxl/libxl_usb.c
new file mode 100644
index 0000000..75f7b8b
--- /dev/null
+++ b/tools/libxl/libxl_usb.c
@@ -0,0 +1,1727 @@
+/*
+ * Copyright (C) 2015 SUSE LINUX Products GmbH, Nuernberg, Germany.
+ * Author Chunyan Liu <cyliu@xxxxxxxx>
+ *
+ * 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"
+#include <inttypes.h>
+
+#define USBBACK_INFO_PATH "/libxl/usbback"
+
+#define USBHUB_CLASS_CODE 9
+
+static int usbback_is_loaded(libxl__gc *gc)
+{
+    int r;
+    struct stat st;
+
+    r = lstat(SYSFS_USBBACK_DRIVER, &st);
+
+    if (r == 0)
+        return 1;
+    if (r < 0 && errno == ENOENT)
+        return 0;
+    LOGE(ERROR, "Accessing %s", SYSFS_USBBACK_DRIVER);
+    return ERROR_FAIL;
+}
+
+static int libxl__device_usbctrl_setdefault(libxl__gc *gc, uint32_t domid,
+                                            libxl_device_usbctrl *usbctrl)
+{
+    int rc;
+    libxl_domain_type domtype = libxl__domain_type(gc, domid);
+
+    if (!usbctrl->version)
+        usbctrl->version = 2;
+
+    if (!usbctrl->ports)
+        usbctrl->ports = 8;
+
+    if (usbctrl->type == LIBXL_USBCTRL_TYPE_AUTO) {
+        if (domtype == LIBXL_DOMAIN_TYPE_PV) {
+            rc = usbback_is_loaded(gc);
+            if (rc < 0)
+                goto out;
+            usbctrl->type = rc ? LIBXL_USBCTRL_TYPE_PV
+                               : LIBXL_USBCTRL_TYPE_QUSB;
+        } else if (domtype == LIBXL_DOMAIN_TYPE_HVM) {
+            /* FIXME: See if we can detect PV frontend */
+            usbctrl->type = LIBXL_USBCTRL_TYPE_DEVICEMODEL;
+        }
+    }
+
+    rc = libxl__resolve_domid(gc, usbctrl->backend_domname,
+                              &usbctrl->backend_domid);
+
+out:
+    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    = (usbctrl->type == LIBXL_USBCTRL_TYPE_PV)
+                              ? LIBXL__DEVICE_KIND_VUSB
+                              : LIBXL__DEVICE_KIND_QUSB;
+    device->devid           = usbctrl->devid;
+    device->domid           = domid;
+    device->kind            = LIBXL__DEVICE_KIND_VUSB;
+
+    return 0;
+}
+
+/* Add usbctrl information to xenstore.
+ *
+ * Adding a usb controller will add a new 'qusb' or 'vusb' device in xenstore,
+ * and add corresponding frontend, backend information to it. According to
+ * "update_json", decide whether to update json config file.
+ */
+static int libxl__device_usbctrl_add_xenstore(libxl__gc *gc, uint32_t domid,
+                                              libxl_device_usbctrl *usbctrl,
+                                              bool update_json)
+{
+    libxl__device *device;
+    flexarray_t *front;
+    flexarray_t *back;
+    xs_transaction_t t = XBT_NULL;
+    int i, rc;
+    libxl_domain_config d_config;
+    libxl_device_usbctrl usbctrl_saved;
+    libxl__domain_userdata_lock *lock = NULL;
+
+    libxl_domain_config_init(&d_config);
+    libxl_device_usbctrl_init(&usbctrl_saved);
+    libxl_device_usbctrl_copy(CTX, &usbctrl_saved, usbctrl);
+
+    GCNEW(device);
+    rc = libxl__device_from_usbctrl(gc, domid, usbctrl, device);
+    if (rc) goto out;
+
+    front = flexarray_make(gc, 4, 1);
+    back = flexarray_make(gc, 12, 1);
+
+    flexarray_append_pair(back, "frontend-id", GCSPRINTF("%d", domid));
+    flexarray_append_pair(back, "online", "1");
+    flexarray_append_pair(back, "state",
+                          GCSPRINTF("%d", XenbusStateInitialising));
+    flexarray_append_pair(back, "type",
+                          (char *)libxl_usbctrl_type_to_string(usbctrl->type));
+    flexarray_append_pair(back, "usb-ver", GCSPRINTF("%d", usbctrl->version));
+    flexarray_append_pair(back, "num-ports", GCSPRINTF("%d", usbctrl->ports));
+    flexarray_append_pair(back, "port", "");
+    for (i = 0; i < usbctrl->ports; i++)
+        flexarray_append_pair(back, GCSPRINTF("port/%d", i + 1), "");
+
+    flexarray_append_pair(front, "backend-id",
+                          GCSPRINTF("%d", usbctrl->backend_domid));
+    flexarray_append_pair(front, "state",
+                          GCSPRINTF("%d", XenbusStateInitialising));
+
+    if (update_json) {
+        lock = libxl__lock_domain_userdata(gc, domid);
+        if (!lock) {
+            rc = ERROR_LOCK_FAIL;
+            goto out;
+        }
+
+        rc = libxl__get_domain_configuration(gc, domid, &d_config);
+        if (rc) goto out;
+
+        DEVICE_ADD(usbctrl, usbctrls, domid, &usbctrl_saved,
+                   COMPARE_USBCTRL, &d_config);
+
+        rc = libxl__dm_check_start(gc, &d_config, domid);
+        if (rc) goto out;
+
+        if (usbctrl->type == LIBXL_USBCTRL_TYPE_QUSB) {
+            if (!libxl__query_qemu_backend(gc, domid, usbctrl->backend_domid,
+                                           "qusb", false)) {
+                LOG(ERROR, "backend type not supported by device model");
+                rc = ERROR_FAIL;
+                goto out;
+            }
+        }
+    }
+
+    for (;;) {
+        rc = libxl__xs_transaction_start(gc, &t);
+        if (rc) goto out;
+
+        rc = libxl__device_exists(gc, t, device);
+        if (rc < 0) goto out;
+        if (rc == 1) {
+            /* already exists in xenstore */
+            LOG(ERROR, "device already exists in xenstore");
+            rc = ERROR_DEVICE_EXISTS;
+            goto out;
+        }
+
+        if (update_json) {
+            rc = libxl__set_domain_configuration(gc, domid, &d_config);
+            if (rc) goto out;
+        }
+
+        libxl__device_generic_add(gc, t, device,
+                          libxl__xs_kvs_of_flexarray(gc, back, back->count),
+                          libxl__xs_kvs_of_flexarray(gc, front, front->count),
+                          NULL);
+
+        rc = libxl__xs_transaction_commit(gc, &t);
+        if (!rc) break;
+        if (rc < 0) goto out;
+    }
+
+out:
+    libxl__xs_transaction_abort(gc, &t);
+    if (lock) libxl__unlock_domain_userdata(lock);
+    libxl_device_usbctrl_dispose(&usbctrl_saved);
+    libxl_domain_config_dispose(&d_config);
+    return rc;
+}
+
+static char *pvusb_get_device_type(libxl_usbctrl_type type)
+{
+    switch (type) {
+    case LIBXL_USBCTRL_TYPE_PV:
+        return "vusb";
+    case LIBXL_USBCTRL_TYPE_QUSB:
+        return "qusb";
+    default:
+        return NULL;
+    }
+}
+
+/* AO operation to add a usb controller.
+ *
+ * Generally, it does:
+ * 1) fill in necessary usb controler information with default value
+ * 2) write usb controller frontend/backend info to xenstore, update json
+ *    config file if necessary.
+ * 3) wait for device connection. PVUSB frontend and backend driver will
+ *    probe xenstore paths and build connection between frontend and backend.
+ *
+ * Before calling this function, aodev should be properly filled:
+ * aodev->ao, aodev->callback, aodev->update_json, ...
+ */
+static void libxl__device_usbctrl_add(libxl__egc *egc, uint32_t domid,
+                                      libxl_device_usbctrl *usbctrl,
+                                      libxl__ao_device *aodev)
+{
+    STATE_AO_GC(aodev->ao);
+    libxl__device *device;
+    int rc;
+
+    rc = libxl__device_usbctrl_setdefault(gc, domid, usbctrl);
+    if (rc < 0) goto out;
+
+    if (usbctrl->devid == -1) {
+        usbctrl->devid = libxl__device_nextid(gc, domid, "vusb");
+        if (usbctrl->devid < 0) {
+            rc = ERROR_FAIL;
+            goto out;
+        }
+    }
+
+    if (usbctrl->type != LIBXL_USBCTRL_TYPE_PV &&
+        usbctrl->type != LIBXL_USBCTRL_TYPE_QUSB) {
+        LOG(ERROR, "Unsupported USB controller type");
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    rc = libxl__device_usbctrl_add_xenstore(gc, domid, usbctrl,
+                                            aodev->update_json);
+    if (rc) goto out;
+
+    GCNEW(device);
+    rc = libxl__device_from_usbctrl(gc, domid, usbctrl, device);
+    if (rc) goto out;
+
+    aodev->dev = device;
+    aodev->action = LIBXL__DEVICE_ACTION_ADD;
+    libxl__wait_device_connection(egc, aodev);
+    return;
+
+out:
+    aodev->rc = rc;
+    aodev->callback(egc, aodev);
+    return;
+}
+
+LIBXL_DEFINE_DEVICE_ADD(usbctrl)
+static LIBXL_DEFINE_DEVICES_ADD(usbctrl)
+LIBXL_DEFINE_DEVICE_REMOVE_CUSTOM(usbctrl)
+
+static int libxl__device_usbdev_list_for_usbctrl(libxl__gc *gc, uint32_t domid,
+                                                 libxl_devid usbctrl,
+                                                 libxl_device_usbdev **usbdevs,
+                                                 int *num);
+
+static int libxl__device_usbdev_remove(libxl__gc *gc, uint32_t domid,
+                                       libxl_device_usbdev *usbdev);
+
+/* AO function to remove a usb controller.
+ *
+ * Generally, it does:
+ * 1) check if the usb controller exists or not
+ * 2) remove all usb devices under controller
+ * 3) remove usb controller information from xenstore
+ *
+ * Before calling this function, aodev should be properly filled:
+ * aodev->ao, aodev->dev, aodev->callback, ...
+ */
+void libxl__initiate_device_usbctrl_remove(libxl__egc *egc,
+                                           libxl__ao_device *aodev)
+{
+    STATE_AO_GC(aodev->ao);
+    libxl_device_usbdev *usbdevs = NULL;
+    int num_usbdev = 0;
+    int i, rc;
+    uint32_t domid = ao->domid;
+    int usbctrl_devid = aodev->dev->devid;
+    libxl_device_usbctrl usbctrl;
+    libxl_usbctrlinfo usbctrlinfo;
+
+    libxl_device_usbctrl_init(&usbctrl);
+    libxl_usbctrlinfo_init(&usbctrlinfo);
+    usbctrl.devid = usbctrl_devid;
+
+    rc = libxl_device_usbctrl_getinfo(CTX, domid, &usbctrl, &usbctrlinfo);
+    if (rc) goto out;
+
+    if (usbctrlinfo.type != LIBXL_USBCTRL_TYPE_PV &&
+        usbctrlinfo.type != LIBXL_USBCTRL_TYPE_QUSB) {
+        LOG(ERROR, "Unsupported USB controller type");
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    /* Remove usb devices first */
+    rc = libxl__device_usbdev_list_for_usbctrl(gc, domid, usbctrl_devid,
+                                               &usbdevs, &num_usbdev);
+    if (rc) goto out;
+
+    for (i = 0; i < num_usbdev; i++) {
+        rc = libxl__device_usbdev_remove(gc, domid, &usbdevs[i]);
+        if (rc) {
+            LOG(ERROR, "libxl__device_usbdev_remove failed: controller %d, "
+                "port %d", usbdevs[i].ctrl, usbdevs[i].port);
+            goto out;
+        }
+    }
+
+    libxl_device_usbctrl_dispose(&usbctrl);
+    libxl_usbctrlinfo_dispose(&usbctrlinfo);
+
+    /* Remove usbctrl */
+    libxl__initiate_device_generic_remove(egc, aodev);
+    return;
+
+out:
+    libxl_device_usbctrl_dispose(&usbctrl);
+    libxl_usbctrlinfo_dispose(&usbctrlinfo);
+    aodev->rc = rc;
+    aodev->callback(egc, aodev);
+    return;
+}
+
+static const char *vusb_be_from_xs_libxl(libxl__gc *gc, const char *libxl_path)
+{
+    const char *be_path;
+    int r;
+
+    r = libxl__xs_read_checked(gc, XBT_NULL,
+                               GCSPRINTF("%s/backend", libxl_path),
+                               &be_path);
+    if (r || !be_path) return NULL;
+
+    return be_path;
+}
+
+libxl_device_usbctrl *
+libxl_device_usbctrl_list(libxl_ctx *ctx, uint32_t domid, int *num)
+{
+    GC_INIT(ctx);
+    libxl_device_usbctrl *usbctrls = NULL;
+    char *libxl_vusbs_path = NULL;
+    char **entry = NULL;
+    unsigned int nentries = 0;
+
+    *num = 0;
+
+    libxl_vusbs_path = GCSPRINTF("%s/device/vusb",
+                     libxl__xs_libxl_path(gc, domid));
+    entry = libxl__xs_directory(gc, XBT_NULL, libxl_vusbs_path, &nentries);
+
+    if (entry && nentries) {
+        usbctrls = libxl__zalloc(NOGC, sizeof(*usbctrls) * nentries);
+        libxl_device_usbctrl *usbctrl;
+        libxl_device_usbctrl *end = usbctrls + nentries;
+        for (usbctrl = usbctrls;
+             usbctrl < end;
+             usbctrl++, entry++, (*num)++) {
+            const char *tmp, *be_path, *libxl_path;
+            int ret;
+
+            libxl_device_usbctrl_init(usbctrl);
+            usbctrl->devid = atoi(*entry);
+
+#define READ_SUBPATH(path, subpath) ({                                  \
+        ret = libxl__xs_read_checked(gc, XBT_NULL,                      \
+                                     GCSPRINTF("%s/" subpath, path),    \
+                                     &tmp);                             \
+        if (ret) goto out;                                              \
+        (char *)tmp;                                                    \
+    })
+
+#define READ_SUBPATH_INT(path, subpath) ({                              \
+        ret = libxl__xs_read_checked(gc, XBT_NULL,                      \
+                                     GCSPRINTF("%s/" subpath, path),    \
+                                     &tmp);                             \
+        if (ret) goto out;                                              \
+        tmp ? atoi(tmp) : -1;                                           \
+    })
+
+            libxl_path = GCSPRINTF("%s/%s", libxl_vusbs_path, *entry);
+            be_path = READ_SUBPATH(libxl_path, "backend");
+            if (!be_path) goto out;
+            ret = libxl__backendpath_parse_domid(gc, be_path,
+                                                &usbctrl->backend_domid);
+            if (ret) goto out;
+            usbctrl->version = READ_SUBPATH_INT(be_path, "usb-ver");
+            usbctrl->ports = READ_SUBPATH_INT(be_path, "num-ports");
+            libxl_usbctrl_type_from_string(READ_SUBPATH(libxl_path, "type"),
+                                           &usbctrl->type);
+
+#undef READ_SUBPATH
+#undef READ_SUBPATH_INT
+       }
+    }
+
+    GC_FREE;
+    return usbctrls;
+
+out:
+    LOG(ERROR, "Unable to list USB Controllers");
+    libxl_device_usbctrl_list_free(usbctrls, *num);
+    GC_FREE;
+    *num = 0;
+    return NULL;
+}
+
+int libxl_device_usbctrl_getinfo(libxl_ctx *ctx, uint32_t domid,
+                                 libxl_device_usbctrl *usbctrl,
+                                 libxl_usbctrlinfo *usbctrlinfo)
+{
+    GC_INIT(ctx);
+    const char *dompath, *fe_path, *be_path, *tmp;
+    const char *libxl_dom_path, *libxl_path;
+    int rc;
+
+    usbctrlinfo->devid = usbctrl->devid;
+
+#define READ_SUBPATH(path, subpath) ({                                  \
+        rc = libxl__xs_read_checked(gc, XBT_NULL,                       \
+                                    GCSPRINTF("%s/" subpath, path),     \
+                                    &tmp);                              \
+        if (rc) goto out;                                               \
+        (char *)tmp;                                                    \
+    })
+
+#define READ_SUBPATH_INT(path, subpath) ({                              \
+        rc = libxl__xs_read_checked(gc, XBT_NULL,                       \
+                                    GCSPRINTF("%s/" subpath, path),     \
+                                    &tmp);                              \
+        if (rc) goto out;                                               \
+        tmp ? atoi(tmp) : -1;                                           \
+    })
+
+    dompath = libxl__xs_get_dompath(gc, domid);
+    fe_path = GCSPRINTF("%s/device/vusb/%d", dompath, usbctrl->devid);
+    libxl_dom_path = libxl__xs_libxl_path(gc, domid);
+    libxl_path = GCSPRINTF("%s/device/vusb/%d", libxl_dom_path, 
usbctrl->devid);
+    be_path = READ_SUBPATH(libxl_path, "backend");
+    usbctrlinfo->backend = libxl__strdup(NOGC, be_path);
+    rc = libxl__backendpath_parse_domid(gc, be_path, &usbctrl->backend_domid);
+    if (rc) goto out;
+    usbctrlinfo->state = READ_SUBPATH_INT(fe_path, "state");
+    usbctrlinfo->evtch = READ_SUBPATH_INT(fe_path, "event-channel");
+    usbctrlinfo->ref_urb = READ_SUBPATH_INT(fe_path, "urb-ring-ref");
+    usbctrlinfo->ref_conn = READ_SUBPATH_INT(fe_path, "urb-ring-ref");
+    usbctrlinfo->frontend = libxl__strdup(NOGC, fe_path);
+    usbctrlinfo->frontend_id = domid;
+    usbctrlinfo->ports = READ_SUBPATH_INT(be_path, "num-ports");
+    usbctrlinfo->version = READ_SUBPATH_INT(be_path, "usb-ver");;
+    tmp = READ_SUBPATH(libxl_path, "type");
+    libxl_usbctrl_type_from_string(tmp, &usbctrlinfo->type);
+
+#undef READ_SUBPATH
+#undef READ_SUBPATH_INT
+
+    rc = 0;
+
+out:
+    GC_FREE;
+    return rc;
+}
+
+int libxl_devid_to_device_usbctrl(libxl_ctx *ctx,
+                                  uint32_t domid,
+                                  int devid,
+                                  libxl_device_usbctrl *usbctrl)
+{
+    libxl_device_usbctrl *usbctrls;
+    int nb = 0;
+    int i, rc;
+
+    usbctrls = libxl_device_usbctrl_list(ctx, domid, &nb);
+    if (!usbctrls) return ERROR_FAIL;
+
+    rc = ERROR_FAIL;
+    for (i = 0; i < nb; i++) {
+        if (devid == usbctrls[i].devid) {
+            libxl_device_usbctrl_copy(ctx, usbctrl, &usbctrls[i]);
+            rc = 0;
+            break;
+        }
+    }
+
+    libxl_device_usbctrl_list_free(usbctrls, nb);
+    return rc;
+}
+
+static char *usbdev_busaddr_to_busid(libxl__gc *gc, int bus, int addr)
+{
+    DIR *dir;
+    char *busid = NULL;
+    struct dirent *de;
+
+    /* invalid hostbus or hostaddr */
+    if (bus < 1 || addr < 1)
+        return NULL;
+
+    dir = opendir(SYSFS_USB_DEV);
+    if (!dir) {
+        LOGE(ERROR, "opendir failed: '%s'", SYSFS_USB_DEV);
+        return NULL;
+    }
+
+    for (;;) {
+        char *filename;
+        void *buf;
+        int busnum = -1;
+        int devnum = -1;
+
+        errno = 0;
+        de = readdir(dir);
+        if (!de && errno) {
+            LOGE(ERROR, "failed to readdir %s", SYSFS_USB_DEV);
+            break;
+        }
+        if (!de)
+            break;
+
+        if (!strcmp(de->d_name, ".") ||
+            !strcmp(de->d_name, ".."))
+            continue;
+
+        filename = GCSPRINTF(SYSFS_USB_DEV "/%s/devnum", de->d_name);
+        if (!libxl__read_sysfs_file_contents(gc, filename, &buf, NULL))
+            devnum = atoi(buf);
+
+        filename = GCSPRINTF(SYSFS_USB_DEV "/%s/busnum", de->d_name);
+        if (!libxl__read_sysfs_file_contents(gc, filename, &buf, NULL))
+            busnum = atoi(buf);
+
+        if (bus == busnum && addr == devnum) {
+            busid = libxl__strdup(gc, de->d_name);
+            break;
+        }
+    }
+
+    closedir(dir);
+    return busid;
+}
+
+static int usbdev_busaddr_from_busid(libxl__gc *gc, const char *busid,
+                                     uint8_t *bus, uint8_t *addr)
+{
+    char *filename;
+    void *buf;
+
+    filename = GCSPRINTF(SYSFS_USB_DEV "/%s/busnum", busid);
+    if (!libxl__read_sysfs_file_contents(gc, filename, &buf, NULL))
+        *bus = atoi(buf);
+    else
+        return ERROR_FAIL;
+
+    filename = GCSPRINTF(SYSFS_USB_DEV "/%s/devnum", busid);
+    if (!libxl__read_sysfs_file_contents(gc, filename, &buf, NULL))
+        *addr = atoi(buf);
+    else
+        return ERROR_FAIL;
+
+    return 0;
+}
+
+static int get_assigned_devices(libxl__gc *gc,
+                                libxl_device_usbdev **list, int *num)
+{
+    char **domlist;
+    unsigned int ndom = 0;
+    int i, j, k;
+    int rc;
+
+    *list = NULL;
+    *num = 0;
+
+    domlist = libxl__xs_directory(gc, XBT_NULL, "/local/domain", &ndom);
+    for (i = 0; i < ndom; i++) {
+        char *libxl_vusbs_path;
+        char **usbctrls;
+        unsigned int nc = 0;
+        uint32_t domid = atoi(domlist[i]);
+
+        libxl_vusbs_path = GCSPRINTF("%s/device/vusb",
+                                     libxl__xs_libxl_path(gc, domid));
+        usbctrls = libxl__xs_directory(gc, XBT_NULL,
+                                       libxl_vusbs_path, &nc);
+
+        for (j = 0; j < nc; j++) {
+            libxl_device_usbdev *tmp = NULL;
+            int nd = 0;
+
+            rc = libxl__device_usbdev_list_for_usbctrl(gc, domid,
+                                                       atoi(usbctrls[j]),
+                                                       &tmp, &nd);
+            if (rc) goto out;
+
+            if (!nd) continue;
+
+            GCREALLOC_ARRAY(*list, *num + nd);
+            for (k = 0; k < nd; k++) {
+                libxl_device_usbdev_copy(CTX, *list + *num, tmp + k);
+                (*num)++;
+            }
+        }
+    }
+
+    return 0;
+
+out:
+    LOG(ERROR, "fail to get assigned devices");
+    return rc;
+}
+
+static bool is_usbdev_in_array(libxl_device_usbdev *usbdevs, int num,
+                               libxl_device_usbdev *usbdev)
+{
+    int i;
+
+    for (i = 0; i < num; i++) {
+        if (usbdevs[i].u.hostdev.hostbus == usbdev->u.hostdev.hostbus &&
+            usbdevs[i].u.hostdev.hostaddr == usbdev->u.hostdev.hostaddr)
+            return true;
+    }
+
+    return false;
+}
+
+/* check if USB device type is assignable */
+static bool is_usbdev_assignable(libxl__gc *gc, libxl_device_usbdev *usbdev)
+{
+    int classcode;
+    char *filename;
+    void *buf = NULL;
+    char *busid = NULL;
+
+    busid = usbdev_busaddr_to_busid(gc, usbdev->u.hostdev.hostbus,
+                                    usbdev->u.hostdev.hostaddr);
+    if (!busid) return false;
+
+    filename = GCSPRINTF(SYSFS_USB_DEV "/%s/bDeviceClass", busid);
+    if (libxl__read_sysfs_file_contents(gc, filename, &buf, NULL))
+        return false;
+
+    classcode = atoi(buf);
+    return classcode != USBHUB_CLASS_CODE;
+}
+
+/* get usb devices under certain usb controller */
+static int
+libxl__device_usbdev_list_for_usbctrl(libxl__gc *gc,
+                                      uint32_t domid,
+                                      libxl_devid usbctrl,
+                                      libxl_device_usbdev **usbdevs,
+                                      int *num)
+{
+    const char *libxl_path, *be_path, *num_devs;
+    int n, i, rc;
+
+    *usbdevs = NULL;
+    *num = 0;
+
+    libxl_path = GCSPRINTF("%s/device/vusb/%d",
+                           libxl__xs_libxl_path(gc, domid), usbctrl);
+
+    be_path = vusb_be_from_xs_libxl(gc, libxl_path);
+    if (!be_path) {
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    rc = libxl__xs_read_checked(gc, XBT_NULL,
+                                GCSPRINTF("%s/num-ports", be_path),
+                                &num_devs);
+    if (rc) goto out;
+
+    n = num_devs ? atoi(num_devs) : 0;
+
+    for (i = 0; i < n; i++) {
+        const char *busid;
+        libxl_device_usbdev *usbdev;
+
+        rc = libxl__xs_read_checked(gc, XBT_NULL,
+                                    GCSPRINTF("%s/port/%d", be_path, i + 1),
+                                    &busid);
+        if (rc) goto out;
+
+        if (busid && strcmp(busid, "")) {
+            GCREALLOC_ARRAY(*usbdevs, *num + 1);
+            usbdev = *usbdevs + *num;
+            (*num)++;
+            libxl_device_usbdev_init(usbdev);
+            usbdev->ctrl = usbctrl;
+            usbdev->port = i + 1;
+            usbdev->type = LIBXL_USBDEV_TYPE_HOSTDEV;
+            rc = usbdev_busaddr_from_busid(gc, busid,
+                                           &usbdev->u.hostdev.hostbus,
+                                           &usbdev->u.hostdev.hostaddr);
+            if (rc) goto out;
+        }
+    }
+
+    rc = 0;
+
+out:
+    return rc;
+}
+
+/* get all usb devices of the domain */
+libxl_device_usbdev *
+libxl_device_usbdev_list(libxl_ctx *ctx, uint32_t domid, int *num)
+{
+    GC_INIT(ctx);
+    libxl_device_usbdev *usbdevs = NULL;
+    const char *libxl_vusbs_path;
+    char **usbctrls;
+    unsigned int nc = 0;
+    int i, j;
+
+    *num = 0;
+
+    libxl_vusbs_path = GCSPRINTF("%s/device/vusb",
+                                 libxl__xs_libxl_path(gc, domid));
+    usbctrls = libxl__xs_directory(gc, XBT_NULL, libxl_vusbs_path, &nc);
+
+    for (i = 0; i < nc; i++) {
+        int rc, nd = 0;
+        libxl_device_usbdev *tmp = NULL;
+
+        rc = libxl__device_usbdev_list_for_usbctrl(gc, domid,
+                                                  atoi(usbctrls[i]),
+                                                  &tmp, &nd);
+        if (rc || !nd) continue;
+
+        usbdevs = libxl__realloc(NOGC, usbdevs,
+                                 sizeof(*usbdevs) * (*num + nd));
+        for (j = 0; j < nd; j++) {
+            libxl_device_usbdev_copy(ctx, usbdevs + *num, tmp + j);
+            (*num)++;
+        }
+    }
+
+    GC_FREE;
+    return usbdevs;
+}
+
+/* find first unused controller:port and give that to usb device */
+static int
+libxl__device_usbdev_set_default_usbctrl(libxl__gc *gc, uint32_t domid,
+                                         libxl_device_usbdev *usbdev)
+{
+    libxl_device_usbctrl *usbctrls = NULL;
+    int numctrl = 0;
+    int i, j, rc;
+
+    usbctrls = libxl_device_usbctrl_list(CTX, domid, &numctrl);
+    if (!numctrl || !usbctrls) {
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    for (i = 0; i < numctrl; i++) {
+        for (j = 0; j < usbctrls[i].ports; j++) {
+            const char *path, *tmp;
+
+            path = GCSPRINTF("%s/backend/%s/%d/%d/port/%d",
+                             libxl__xs_get_dompath(gc, LIBXL_TOOLSTACK_DOMID),
+                             pvusb_get_device_type(usbctrls[i].type),
+                             domid, usbctrls[i].devid, j + 1);
+            rc = libxl__xs_read_checked(gc, XBT_NULL, path, &tmp);
+            if (rc) goto out;
+
+            if (tmp && !strcmp(tmp, "")) {
+                usbdev->ctrl = usbctrls[i].devid;
+                usbdev->port = j + 1;
+                rc = 0;
+                goto out;
+            }
+        }
+    }
+
+    /* no available controller:port */
+    rc = ERROR_FAIL;
+
+out:
+    libxl_device_usbctrl_list_free(usbctrls, numctrl);
+    return rc;
+}
+
+/* Fill in usb information with default value.
+ *
+ * Generally, it does:
+ * 1) if "controller" is not specified:
+ *    - if "port" is not specified, try to find an available controller:port,
+ *      if found, use that; otherwise, create a new controller, use this
+ *      controller and its first port
+ *    - if "port" is specified, report error.
+ * 2) if "controller" is specified, but port is not specified:
+ *    try to find an available port under this controller, if found, use
+ *    that, otherwise, report error.
+ * 3) if both "controller" and "port" are specified:
+ *    check the controller:port is available, if not, report error.
+ */
+static int libxl__device_usbdev_setdefault(libxl__gc *gc,
+                                           uint32_t domid,
+                                           libxl_device_usbdev *usbdev,
+                                           bool update_json)
+{
+    int rc;
+
+    if (!usbdev->type)
+        usbdev->type = LIBXL_USBDEV_TYPE_HOSTDEV;
+
+    if (usbdev->ctrl == -1) {
+        if (usbdev->port) {
+            LOG(ERROR, "USB controller must be specified if you specify port");
+            return ERROR_INVAL;
+        }
+
+        rc = libxl__device_usbdev_set_default_usbctrl(gc, domid, usbdev);
+        /* If no existing controller to host this usb device, add a new one */
+        if (rc) {
+            libxl_device_usbctrl *usbctrl;
+
+            GCNEW(usbctrl);
+            libxl_device_usbctrl_init(usbctrl);
+            rc = libxl__device_usbctrl_setdefault(gc, domid, usbctrl);
+            if (rc < 0) goto out;
+
+            if (usbctrl->devid == -1) {
+                usbctrl->devid = libxl__device_nextid(gc, domid, "vusb");
+                if (usbctrl->devid < 0) {
+                    rc = ERROR_FAIL;
+                    goto out;
+                }
+            }
+
+            if (usbctrl->type != LIBXL_USBCTRL_TYPE_PV &&
+                usbctrl->type != LIBXL_USBCTRL_TYPE_QUSB) {
+                LOG(ERROR, "Unsupported USB controller type");
+                rc = ERROR_FAIL;
+                goto out;
+            }
+
+            rc = libxl__device_usbctrl_add_xenstore(gc, domid, usbctrl,
+                                                    update_json);
+            if (rc) goto out;
+
+            usbdev->ctrl = usbctrl->devid;
+            usbdev->port = 1;
+        }
+    } else {
+        /* A controller was specified; look it up */
+        const char *libxl_path, *be_path, *tmp;
+
+        libxl_path = GCSPRINTF("%s/device/vusb/%d",
+                            libxl__xs_libxl_path(gc, domid),
+                            usbdev->ctrl);
+
+        be_path = vusb_be_from_xs_libxl(gc, libxl_path);
+        if (!be_path) {
+            rc = ERROR_FAIL;
+            goto out;
+        }
+
+        if (usbdev->port) {
+            /* A specific port was requested; see if it's available */
+            rc = libxl__xs_read_checked(gc, XBT_NULL,
+                                        GCSPRINTF("%s/port/%d",
+                                                  be_path, usbdev->port),
+                                        &tmp);
+            if (rc) goto out;
+
+            if (tmp && strcmp(tmp, "")) {
+                LOG(ERROR, "The controller port isn't available");
+                rc = ERROR_FAIL;
+                goto out;
+            }
+        } else {
+            /* No port was requested. Choose free port. */
+            int i, ports;
+
+            rc = libxl__xs_read_checked(gc, XBT_NULL,
+                                        GCSPRINTF("%s/num-ports", be_path), 
&tmp);
+            if (rc) goto out;
+
+            ports = tmp ? atoi(tmp) : 0;
+
+            for (i = 0; i < ports; i++) {
+                rc = libxl__xs_read_checked(gc, XBT_NULL,
+                                            GCSPRINTF("%s/port/%d", be_path, i 
+ 1),
+                                            &tmp);
+                if (rc) goto out;
+
+                if (tmp && !strcmp(tmp, "")) {
+                    usbdev->port = i + 1;
+                    break;
+                }
+            }
+
+            if (!usbdev->port) {
+                LOG(ERROR, "No available port under specified controller");
+                rc = ERROR_FAIL;
+                goto out;
+            }
+        }
+    }
+
+    rc = 0;
+
+out:
+    return rc;
+}
+
+/* Add usb information to xenstore
+ *
+ * Adding a usb device won't create new 'qusb'/'vusb' device, but only write
+ * the device busid to the controller:port in xenstore.
+ */
+static int libxl__device_usbdev_add_xenstore(libxl__gc *gc, uint32_t domid,
+                                             libxl_device_usbdev *usbdev,
+                                             libxl_usbctrl_type type,
+                                             bool update_json)
+{
+    char *be_path, *busid;
+    int rc;
+    xs_transaction_t t = XBT_NULL;
+    libxl_domain_config d_config;
+    libxl_device_usbdev usbdev_saved;
+    libxl__domain_userdata_lock *lock = NULL;
+
+    libxl_domain_config_init(&d_config);
+    libxl_device_usbdev_init(&usbdev_saved);
+    libxl_device_usbdev_copy(CTX, &usbdev_saved, usbdev);
+
+    busid = usbdev_busaddr_to_busid(gc, usbdev->u.hostdev.hostbus,
+                                    usbdev->u.hostdev.hostaddr);
+    if (!busid) {
+        LOG(DEBUG, "Fail to get busid of usb device");
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    if (update_json) {
+        lock = libxl__lock_domain_userdata(gc, domid);
+        if (!lock) {
+            rc = ERROR_LOCK_FAIL;
+            goto out;
+        }
+
+        rc = libxl__get_domain_configuration(gc, domid, &d_config);
+        if (rc) goto out;
+
+        DEVICE_ADD(usbdev, usbdevs, domid, &usbdev_saved,
+                   COMPARE_USB, &d_config);
+
+        rc = libxl__dm_check_start(gc, &d_config, domid);
+        if (rc) goto out;
+    }
+
+    for (;;) {
+        rc = libxl__xs_transaction_start(gc, &t);
+        if (rc) goto out;
+
+        if (update_json) {
+            rc = libxl__set_domain_configuration(gc, domid, &d_config);
+            if (rc) goto out;
+        }
+
+        be_path = GCSPRINTF("%s/backend/%s/%d/%d/port/%d",
+                            libxl__xs_get_dompath(gc, LIBXL_TOOLSTACK_DOMID),
+                            pvusb_get_device_type(type),
+                            domid, usbdev->ctrl, usbdev->port);
+
+        LOG(DEBUG, "Adding usb device %s to xenstore: controller %d, port %d",
+            busid, usbdev->ctrl, usbdev->port);
+
+        rc = libxl__xs_write_checked(gc, t, be_path, busid);
+        if (rc) goto out;
+
+        rc = libxl__xs_transaction_commit(gc, &t);
+        if (!rc) break;
+        if (rc < 0) goto out;
+    }
+
+    rc = 0;
+
+out:
+    if (lock) libxl__unlock_domain_userdata(lock);
+    libxl_device_usbdev_dispose(&usbdev_saved);
+    libxl_domain_config_dispose(&d_config);
+    return rc;
+}
+
+static int libxl__device_usbdev_remove_xenstore(libxl__gc *gc, uint32_t domid,
+                                                libxl_device_usbdev *usbdev,
+                                                libxl_usbctrl_type type)
+{
+    char *be_path;
+
+    be_path = GCSPRINTF("%s/backend/%s/%d/%d/port/%d",
+                        libxl__xs_get_dompath(gc, LIBXL_TOOLSTACK_DOMID),
+                        pvusb_get_device_type(type),
+                        domid, usbdev->ctrl, usbdev->port);
+
+    LOG(DEBUG, "Removing usb device from xenstore: controller %d, port %d",
+        usbdev->ctrl, usbdev->port);
+
+    return libxl__xs_write_checked(gc, XBT_NULL, be_path, "");
+}
+
+static char *usbdev_busid_from_ctrlport(libxl__gc *gc, uint32_t domid,
+                                        libxl_device_usbdev *usbdev,
+                                        libxl_usbctrl_type type)
+{
+    return libxl__xs_read(gc, XBT_NULL,
+                          GCSPRINTF("%s/backend/%s/%d/%d/port/%d",
+                              libxl__xs_get_dompath(gc, LIBXL_TOOLSTACK_DOMID),
+                              pvusb_get_device_type(type),
+                              domid, usbdev->ctrl, usbdev->port));
+}
+
+/* get original driver path of usb interface, stored in @drvpath */
+static int usbintf_get_drvpath(libxl__gc *gc, const char *intf, char **drvpath)
+{
+    char *spath, *dp = NULL;
+
+    spath = GCSPRINTF(SYSFS_USB_DEV "/%s/driver", intf);
+
+    /* Find the canonical path to the driver. */
+    dp = libxl__zalloc(gc, PATH_MAX);
+    dp = realpath(spath, dp);
+    if (!dp && errno != ENOENT) {
+        LOGE(ERROR, "get realpath failed: '%s'", spath);
+        return ERROR_FAIL;
+    }
+
+    *drvpath = dp;
+
+    return 0;
+}
+
+static int unbind_usbintf(libxl__gc *gc, const char *intf)
+{
+    char *path;
+    int fd = -1;
+    int rc;
+
+    path = GCSPRINTF(SYSFS_USB_DEV "/%s/driver/unbind", intf);
+
+    fd = open(path, O_WRONLY);
+    if (fd < 0) {
+        LOGE(ERROR, "open file failed: '%s'", path);
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    if (libxl_write_exactly(CTX, fd, intf, strlen(intf), path, intf)) {
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    rc = 0;
+
+out:
+    if (fd >= 0) close(fd);
+    return rc;
+}
+
+static int bind_usbintf(libxl__gc *gc, const char *intf, const char *drvpath)
+{
+    char *bind_path, *intf_path;
+    struct stat st;
+    int fd = -1;
+    int rc, r;
+
+    intf_path = GCSPRINTF("%s/%s", drvpath, intf);
+
+    /* check through lstat, if intf already exists under drvpath,
+     * it's already bound, return directly; if it doesn't exist,
+     * continue to do bind work; otherwise, return error.
+     */
+    r = lstat(intf_path, &st);
+    if (r == 0)
+        return 0;
+    if (r < 0 && errno != ENOENT)
+        return ERROR_FAIL;
+
+    bind_path = GCSPRINTF("%s/bind", drvpath);
+
+    fd = open(bind_path, O_WRONLY);
+    if (fd < 0) {
+        LOGE(ERROR, "open file failed: '%s'", bind_path);
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    if (libxl_write_exactly(CTX, fd, intf, strlen(intf), bind_path, intf)) {
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    rc = 0;
+
+out:
+    if (fd >= 0) close(fd);
+    return rc;
+}
+
+/* Is usb interface bound to usbback? */
+static int usbintf_is_assigned(libxl__gc *gc, char *intf)
+{
+    char *spath;
+    int r;
+    struct stat st;
+
+    spath = GCSPRINTF(SYSFS_USBBACK_DRIVER "/%s", intf);
+    r = lstat(spath, &st);
+
+    if (r == 0)
+        return 1;
+    if (r < 0 && errno == ENOENT)
+        return 0;
+    LOGE(ERROR, "Accessing %s", spath);
+    return -1;
+}
+
+static int usbdev_get_all_interfaces(libxl__gc *gc, const char *busid,
+                                     char ***intfs, int *num)
+{
+    DIR *dir;
+    char *buf;
+    struct dirent *de;
+    int rc;
+
+    *intfs = NULL;
+    *num = 0;
+
+    buf = GCSPRINTF("%s:", busid);
+
+    dir = opendir(SYSFS_USB_DEV);
+    if (!dir) {
+        LOGE(ERROR, "opendir failed: '%s'", SYSFS_USB_DEV);
+        return ERROR_FAIL;
+    }
+
+    for (;;) {
+        errno = 0;
+        de = readdir(dir);
+
+        if (!de && errno) {
+            LOGE(ERROR, "failed to readdir %s", SYSFS_USB_DEV);
+            rc = ERROR_FAIL;
+            goto out;
+        }
+        if (!de)
+            break;
+
+        if (!strcmp(de->d_name, ".") ||
+            !strcmp(de->d_name, ".."))
+            continue;
+
+        if (!strncmp(de->d_name, buf, strlen(buf))) {
+            GCREALLOC_ARRAY(*intfs, *num + 1);
+            (*intfs)[*num] = libxl__strdup(gc, de->d_name);
+            (*num)++;
+        }
+    }
+
+    rc = 0;
+
+out:
+    closedir(dir);
+    return rc;
+}
+
+/* Encode usb interface so that it could be written to xenstore as a key.
+ *
+ * Since xenstore key cannot include '.' or ':', we'll change '.' to '_',
+ * change ':' to '@'. For example, 3-1:2.1 will be encoded to 3-1@2_1.
+ * This will be used to save original driver of USB device to xenstore.
+ */
+static char *usb_interface_xenstore_encode(libxl__gc *gc, const char *busid)
+{
+    char *str = libxl__strdup(gc, busid);
+    int i, len = strlen(str);
+
+    for (i = 0; i < len; i++) {
+        if (str[i] == '.') str[i] = '_';
+        if (str[i] == ':') str[i] = '@';
+    }
+    return str;
+}
+
+/* Unbind USB device from "usbback" driver.
+ *
+ * If there are many interfaces under USB device, check each interface,
+ * unbind from "usbback" driver.
+ */
+static int usbback_dev_unassign(libxl__gc *gc, const char *busid)
+{
+    char **intfs = NULL;
+    int i, num = 0;
+    int rc;
+
+    rc = usbdev_get_all_interfaces(gc, busid, &intfs, &num);
+    if (rc) goto out;
+

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxx
https://lists.xenproject.org/xen-changelog

 


Rackspace

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