All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH RFC V2 0/5] pvusb toolstack work
@ 2015-01-19  8:28 Chunyan Liu
  2015-01-19  8:28 ` [PATCH RFC V2 1/5] libxl: add pvusb definitions Chunyan Liu
                   ` (5 more replies)
  0 siblings, 6 replies; 40+ messages in thread
From: Chunyan Liu @ 2015-01-19  8:28 UTC (permalink / raw)
  To: xen-devel
  Cc: lars.kurth, ian.campbell, george.dunlap, Chunyan Liu,
	ian.jackson, caobosimon

This patch series is based on Simon's work. Since there is no progress
after last August, I hope we can make this work proceed. Any comment will
be very appreciated.

It adds pvusb toolstack implementation, with pvusb kernel side work,
one could attach/detach a usb device to guest.

Changes to Simon's work:
  - fix format issues
  - fix bind/unbind if usb device has multiple interfaces
  - add codes to update json config when hot add a usb device
  - reorganize and update libxl code to make it more readable.
  - split libxl code into several patches for easier review.
  - remove many unused APIs in libxl_internal.h and libxl.h
  - fix xl command implementation issues (many inconsistences
    between cmdtable and cmdimplementation) and update some
    command syntax
  - remove usb-assigned-list

  Known issues in testing:
  - specify 'usb' in vm config file, then create vm, usb controller state
    keeps in not connected; same result when hot add a usb device in
    vm booting process. But hot adding a usb device after vm is booted,
    works very well.
  - hot adding a usb device to 2.0 usb controller, usb device not working
    well in guest. But adding a usb device to 1.x usb controller, works well.

  These issues are also found with old xend toolstack.

Simon's Patches:
  http://lists.xen.org/archives/html/xen-devel/2014-08/msg01203.html

Chunyan Liu (5):
  libxl: add pvusb definitions
  libxl: export some functions for pvusb use
  libxl: add pvusb API
  xl: add pvusb commands
  domcreate: support pvusb in configuration file

 tools/libxl/Makefile                 |    2 +-
 tools/libxl/libxl.c                  |    8 +-
 tools/libxl/libxl.h                  |   58 ++
 tools/libxl/libxl_create.c           |   41 +-
 tools/libxl/libxl_internal.h         |   11 +
 tools/libxl/libxl_types.idl          |   58 +-
 tools/libxl/libxl_types_internal.idl |    1 +
 tools/libxl/libxl_usb.c              | 1277 ++++++++++++++++++++++++++++++++++
 tools/libxl/libxlu_cfg_y.c           |  464 ++++++------
 tools/libxl/libxlu_cfg_y.h           |   38 +-
 tools/libxl/xl.h                     |    6 +
 tools/libxl/xl_cmdimpl.c             |  296 +++++++-
 tools/libxl/xl_cmdtable.c            |   30 +
 13 files changed, 2058 insertions(+), 232 deletions(-)
 create mode 100644 tools/libxl/libxl_usb.c

-- 
1.8.4.5

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH RFC V2 1/5] libxl: add pvusb definitions
  2015-01-19  8:28 [PATCH RFC V2 0/5] pvusb toolstack work Chunyan Liu
@ 2015-01-19  8:28 ` Chunyan Liu
  2015-03-03 11:10   ` Ian Campbell
  2015-03-03 17:15   ` George Dunlap
  2015-01-19  8:28 ` [PATCH RFC V2 2/5] libxl: export some functions for pvusb use Chunyan Liu
                   ` (4 subsequent siblings)
  5 siblings, 2 replies; 40+ messages in thread
From: Chunyan Liu @ 2015-01-19  8:28 UTC (permalink / raw)
  To: xen-devel
  Cc: lars.kurth, ian.campbell, george.dunlap, Chunyan Liu,
	ian.jackson, caobosimon

To attach a usb device, a virtual usb controller should be created first.
This patch defines usbctrl and usbdevice related structs.

Signed-off-by: Chunyan Liu <cyliu@suse.com>
Signed-off-by: Simon Cao <caobosimon@gmail.com>
---
 tools/libxl/libxl_types.idl          | 58 +++++++++++++++++++++++++++++++++++-
 tools/libxl/libxl_types_internal.idl |  1 +
 2 files changed, 58 insertions(+), 1 deletion(-)

diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl
index 1214d2e..0639434 100644
--- a/tools/libxl/libxl_types.idl
+++ b/tools/libxl/libxl_types.idl
@@ -111,6 +111,16 @@ libxl_nic_type = Enumeration("nic_type", [
     (2, "VIF"),
     ])
 
+libxl_usbctrl_type = Enumeration("usbctrl_type",[
+    (0, "AUTO"),
+    (1, "PV"),
+    (2, "DEVICEMODEL"),
+    ])
+
+libxl_usb_type = Enumeration("device_usb_type", [
+    (1, "HOSTDEV"),
+    ])
+
 libxl_action_on_shutdown = Enumeration("action_on_shutdown", [
     (1, "DESTROY"),
 
@@ -394,7 +404,7 @@ libxl_domain_build_info = Struct("domain_build_info",[
     ("ioports",          Array(libxl_ioport_range, "num_ioports")),
     ("irqs",             Array(uint32, "num_irqs")),
     ("iomem",            Array(libxl_iomem_range, "num_iomem")),
-    ("claim_mode",	     libxl_defbool),
+    ("claim_mode",       libxl_defbool),
     ("event_channels",   uint32),
     ("kernel",           string),
     ("cmdline",          string),
@@ -521,6 +531,27 @@ libxl_device_pci = Struct("device_pci", [
     ("seize", bool),
     ])
 
+libxl_device_usbctrl = Struct("device_usbctrl", [
+    ("name", string),
+    ("type", libxl_usbctrl_type),
+    ("backend_domid", libxl_domid),
+    ("backend_domname", string),
+    ("devid", libxl_devid),
+    ("usb_version", uint8),
+    ("num_ports", uint8),
+    ])
+
+libxl_device_usb = Struct("device_usb", [
+    ("ctrl", integer),
+    ("port", integer),
+    ("intf", string),
+    ("u", KeyedUnion(None, libxl_usb_type, "type",
+        [("hostdev", Struct(None, [
+            ("hostbus",   integer),
+            ("hostaddr",  integer) ]))
+        ]))
+    ])
+
 libxl_device_vtpm = Struct("device_vtpm", [
     ("backend_domid",    libxl_domid),
     ("backend_domname",  string),
@@ -547,6 +578,7 @@ libxl_domain_config = Struct("domain_config", [
     ("disks", Array(libxl_device_disk, "num_disks")),
     ("nics", Array(libxl_device_nic, "num_nics")),
     ("pcidevs", Array(libxl_device_pci, "num_pcidevs")),
+    ("usbs", Array(libxl_device_usb, "num_usbs")),
     ("vfbs", Array(libxl_device_vfb, "num_vfbs")),
     ("vkbs", Array(libxl_device_vkb, "num_vkbs")),
     ("vtpms", Array(libxl_device_vtpm, "num_vtpms")),
@@ -595,6 +627,30 @@ libxl_vtpminfo = Struct("vtpminfo", [
     ("uuid", libxl_uuid),
     ], dir=DIR_OUT)
 
+libxl_usbctrlinfo = Struct("usbctrlinfo", [
+    ("backend", string),
+    ("backend_id", uint32),
+    ("frontend", string),
+    ("frontend_id", uint32),
+    ("devid", libxl_devid),
+    ("state", integer),
+    ("evtch", integer),
+    ("version", integer),
+    ("type", string),
+    ("ref_urb", integer),
+    ("ref_conn", integer),
+    ("num_ports", integer),
+    ], dir=DIR_OUT)
+
+libxl_usbinfo = Struct("usbinfo", [
+    ("bus", integer),
+    ("devnum", integer),
+    ("idVendor", integer),
+    ("idProduct", integer),
+    ("prod", string),
+    ("manuf", string),
+    ], dir=DIR_OUT)
+
 libxl_vcpuinfo = Struct("vcpuinfo", [
     ("vcpuid", uint32),
     ("cpu", uint32),
diff --git a/tools/libxl/libxl_types_internal.idl b/tools/libxl/libxl_types_internal.idl
index 5e55685..696f5f8 100644
--- a/tools/libxl/libxl_types_internal.idl
+++ b/tools/libxl/libxl_types_internal.idl
@@ -22,6 +22,7 @@ libxl__device_kind = Enumeration("device_kind", [
     (6, "VKBD"),
     (7, "CONSOLE"),
     (8, "VTPM"),
+    (9, "VUSB"),
     ])
 
 libxl__console_backend = Enumeration("console_backend", [
-- 
1.8.4.5

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH RFC V2 2/5] libxl: export some functions for pvusb use
  2015-01-19  8:28 [PATCH RFC V2 0/5] pvusb toolstack work Chunyan Liu
  2015-01-19  8:28 ` [PATCH RFC V2 1/5] libxl: add pvusb definitions Chunyan Liu
@ 2015-01-19  8:28 ` Chunyan Liu
  2015-03-03 11:10   ` Ian Campbell
  2015-01-19  8:28 ` [PATCH RFC V2 3/5] libxl: add pvusb API Chunyan Liu
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 40+ messages in thread
From: Chunyan Liu @ 2015-01-19  8:28 UTC (permalink / raw)
  To: xen-devel
  Cc: lars.kurth, ian.campbell, george.dunlap, Chunyan Liu,
	ian.jackson, caobosimon

Signed-off-by: Chunyan Liu <cyliu@suse.com>
Signed-off-by: Simon Cao <caobosimon@gmail.com>
---
 tools/libxl/libxl.c          | 6 +++---
 tools/libxl/libxl_internal.h | 5 +++++
 2 files changed, 8 insertions(+), 3 deletions(-)

diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
index 11cf0e1..3cd13db 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -1906,7 +1906,7 @@ out:
 /******************************************************************************/
 
 /* generic callback for devices that only need to set ao_complete */
-static void device_addrm_aocomplete(libxl__egc *egc, libxl__ao_device *aodev)
+void device_addrm_aocomplete(libxl__egc *egc, libxl__ao_device *aodev)
 {
     STATE_AO_GC(aodev->ao);
 
@@ -1929,7 +1929,7 @@ out:
 }
 
 /* common function to get next device id */
-static int libxl__device_nextid(libxl__gc *gc, uint32_t domid, char *device)
+int libxl__device_nextid(libxl__gc *gc, uint32_t domid, char *device)
 {
     char *dompath, **l;
     unsigned int nb;
@@ -1948,7 +1948,7 @@ static int libxl__device_nextid(libxl__gc *gc, uint32_t domid, char *device)
     return nextid;
 }
 
-static int libxl__resolve_domid(libxl__gc *gc, const char *name,
+int libxl__resolve_domid(libxl__gc *gc, const char *name,
                                 uint32_t *domid)
 {
     if (!name)
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 934465a..bcf43fb 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -1057,6 +1057,9 @@ _hidden int libxl__init_console_from_channel(libxl__gc *gc,
                                              libxl__device_console *console,
                                              int dev_num,
                                              libxl_device_channel *channel);
+_hidden int libxl__device_nextid(libxl__gc *gc, uint32_t domid, char *device);
+_hidden int libxl__resolve_domid(libxl__gc *gc, const char *name,
+                                 uint32_t *domid);
 
 /*
  * For each aggregate type which can be used as an input we provide:
@@ -2181,6 +2184,8 @@ struct libxl__ao_device {
 
 /* Starts preparing to add/remove a bunch of devices. */
 _hidden void libxl__multidev_begin(libxl__ao *ao, libxl__multidev*);
+/* generic callback for devices that only need to set ao_complete */
+_hidden void device_addrm_aocomplete(libxl__egc *egc, libxl__ao_device *aodev);
 
 /* Prepares to add/remove one of many devices.
  * Calls libxl__prepare_ao_device on libxl__ao_device argument provided and
-- 
1.8.4.5

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH RFC V2 3/5] libxl: add pvusb API
  2015-01-19  8:28 [PATCH RFC V2 0/5] pvusb toolstack work Chunyan Liu
  2015-01-19  8:28 ` [PATCH RFC V2 1/5] libxl: add pvusb definitions Chunyan Liu
  2015-01-19  8:28 ` [PATCH RFC V2 2/5] libxl: export some functions for pvusb use Chunyan Liu
@ 2015-01-19  8:28 ` Chunyan Liu
  2015-01-28 15:54   ` Ian Campbell
                     ` (5 more replies)
  2015-01-19  8:28 ` [PATCH RFC V2 4/5] xl: add pvusb commands Chunyan Liu
                   ` (2 subsequent siblings)
  5 siblings, 6 replies; 40+ messages in thread
From: Chunyan Liu @ 2015-01-19  8:28 UTC (permalink / raw)
  To: xen-devel
  Cc: lars.kurth, ian.campbell, george.dunlap, Chunyan Liu,
	ian.jackson, caobosimon

Add pvusb APIs, including:
 - attach/detach (create/destroy) virtual usb controller.
 - attach/detach usb device
 - list assignable usb devices in host
 - some other helper functions

Signed-off-by: Chunyan Liu <cyliu@suse.com>
Signed-off-by: Simon Cao <caobosimon@gmail.com>
---
 tools/libxl/Makefile         |    2 +-
 tools/libxl/libxl.c          |    2 +
 tools/libxl/libxl.h          |   58 ++
 tools/libxl/libxl_internal.h |    6 +
 tools/libxl/libxl_usb.c      | 1277 ++++++++++++++++++++++++++++++++++++++++++
 tools/libxl/libxlu_cfg_y.c   |  464 ++++++++-------
 tools/libxl/libxlu_cfg_y.h   |   38 +-
 7 files changed, 1623 insertions(+), 224 deletions(-)
 create mode 100644 tools/libxl/libxl_usb.c

diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile
index b417372..08cdb12 100644
--- a/tools/libxl/Makefile
+++ b/tools/libxl/Makefile
@@ -95,7 +95,7 @@ LIBXL_OBJS = flexarray.o libxl.o libxl_create.o libxl_dm.o libxl_pci.o \
 			libxl_internal.o libxl_utils.o libxl_uuid.o \
 			libxl_json.o libxl_aoutils.o libxl_numa.o \
 			libxl_save_callout.o _libxl_save_msgs_callout.o \
-			libxl_qmp.o libxl_event.o libxl_fork.o $(LIBXL_OBJS-y)
+			libxl_qmp.o libxl_event.o libxl_fork.o libxl_usb.o $(LIBXL_OBJS-y)
 LIBXL_OBJS += libxl_genid.o
 LIBXL_OBJS += _libxl_types.o libxl_flask.o _libxl_types_internal.o
 
diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
index 3cd13db..dd76ac3 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -1594,6 +1594,8 @@ void libxl__destroy_domid(libxl__egc *egc, libxl__destroy_domid_state *dis)
 
     if (libxl__device_pci_destroy_all(gc, domid) < 0)
         LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "pci shutdown failed for domid %d", domid);
+    if (libxl__device_usb_destroy_all(gc, domid) < 0)
+         LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "usb shutdown failed for domid %d", domid);
     rc = xc_domain_pause(ctx->xch, domid);
     if (rc < 0) {
         LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc, "xc_domain_pause failed for %d", domid);
diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
index 0a123f1..2e89244 100644
--- a/tools/libxl/libxl.h
+++ b/tools/libxl/libxl.h
@@ -98,6 +98,12 @@
 #define LIBXL_HAVE_DOMAIN_NODEAFFINITY 1
 
 /*
+ * LIBXL_HAVE_DEVICE_USB indicates the functions for doing hot-plug of
+ * USB devices.
+ */
+#define LIBXL_HAVE_DEVICE_USB 1
+
+/*
  * LIBXL_HAVE_BUILDINFO_HVM_VENDOR_DEVICE indicates that the
  * libxl_vendor_device field is present in the hvm sections of
  * libxl_domain_build_info. This field tells libxl which
@@ -1168,6 +1174,56 @@ int libxl_cdrom_insert(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *disk,
                        const libxl_asyncop_how *ao_how)
                        LIBXL_EXTERNAL_CALLERS_ONLY;
 
+/* USB Controllers*/
+int libxl_device_usbctrl_add(libxl_ctx *ctx, uint32_t domid,
+                         libxl_device_usbctrl *usbctrl,
+                         const libxl_asyncop_how *ao_how)
+                         LIBXL_EXTERNAL_CALLERS_ONLY;
+
+int libxl_device_usbctrl_remove(libxl_ctx *ctx, uint32_t domid,
+                         libxl_device_usbctrl *usbctrl,
+                         const libxl_asyncop_how *ao_how)
+                         LIBXL_EXTERNAL_CALLERS_ONLY;
+
+int libxl_device_usbctrl_destroy(libxl_ctx *ctx, uint32_t domid,
+                         libxl_device_usbctrl *usbctrl,
+                         const libxl_asyncop_how *ao_how)
+                         LIBXL_EXTERNAL_CALLERS_ONLY;
+
+libxl_device_usbctrl *libxl_device_usbctrl_list(libxl_ctx *ctx,
+                            uint32_t domid, int *num);
+
+int libxl_devid_to_device_usbctrl(libxl_ctx *ctx, uint32_t domid,
+                            int devid, libxl_device_usbctrl *usbctrl)
+                            LIBXL_EXTERNAL_CALLERS_ONLY;
+
+int libxl_device_usbctrl_getinfo(libxl_ctx *ctx, uint32_t domid,
+                                libxl_device_usbctrl *usbctrl,
+                                libxl_usbctrlinfo *usbctrlinfo)
+                                LIBXL_EXTERNAL_CALLERS_ONLY;
+
+/* USB Devices */
+int libxl_device_usb_add(libxl_ctx *ctx, uint32_t domid, libxl_device_usb *usb,
+                         const libxl_asyncop_how *ao_how)
+                         LIBXL_EXTERNAL_CALLERS_ONLY;
+
+int libxl_device_usb_remove(libxl_ctx *ctx, uint32_t domid, libxl_device_usb *usb,
+                            const libxl_asyncop_how *ao_how)
+                            LIBXL_EXTERNAL_CALLERS_ONLY;
+
+int libxl_device_usb_destroy(libxl_ctx *ctx, uint32_t domid, libxl_device_usb *usb,
+                            const libxl_asyncop_how *ao_how)
+                            LIBXL_EXTERNAL_CALLERS_ONLY;
+
+libxl_device_usb *libxl_device_usb_list(libxl_ctx *ctx, uint32_t domid,
+                                        int usbctrl, int *num);
+
+int libxl_intf_to_device_usb(libxl_ctx *ctx, uint32_t domid,
+                            char *intf, libxl_device_usb *usb)
+                            LIBXL_EXTERNAL_CALLERS_ONLY;
+
+int libxl_device_usb_getinfo(libxl_ctx *ctx, char *intf, libxl_usbinfo *usbinfo)
+                             LIBXL_EXTERNAL_CALLERS_ONLY;
 /* Network Interfaces */
 int libxl_device_nic_add(libxl_ctx *ctx, uint32_t domid, libxl_device_nic *nic,
                          const libxl_asyncop_how *ao_how)
@@ -1294,6 +1350,8 @@ int libxl_device_pci_assignable_add(libxl_ctx *ctx, libxl_device_pci *pcidev, in
 int libxl_device_pci_assignable_remove(libxl_ctx *ctx, libxl_device_pci *pcidev, int rebind);
 libxl_device_pci *libxl_device_pci_assignable_list(libxl_ctx *ctx, int *num);
 
+libxl_device_usb *libxl_device_usb_assignable_list(libxl_ctx *ctx, int *num);
+
 /* CPUID handling */
 int libxl_cpuid_parse_config(libxl_cpuid_policy_list *cpuid, const char* str);
 int libxl_cpuid_parse_config_xend(libxl_cpuid_policy_list *cpuid,
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index bcf43fb..dba1326 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -2395,6 +2395,11 @@ _hidden void libxl__device_vtpm_add(libxl__egc *egc, uint32_t domid,
                                    libxl_device_vtpm *vtpm,
                                    libxl__ao_device *aodev);
 
+/* from libxl_usb */
+_hidden int libxl__device_usb_add(libxl__gc *gc, uint32_t domid,
+                            libxl_device_usb *usb);
+_hidden int libxl__device_usb_destroy_all(libxl__gc *gc, uint32_t domid);
+
 /* Internal function to connect a vkb device */
 _hidden int libxl__device_vkb_add(libxl__gc *gc, uint32_t domid,
                                   libxl_device_vkb *vkb);
@@ -3574,6 +3579,7 @@ static inline void libxl__update_config_vtpm(libxl__gc *gc,
 #define COMPARE_PCI(a, b) ((a)->func == (b)->func &&    \
                            (a)->bus == (b)->bus &&      \
                            (a)->dev == (b)->dev)
+#define COMPARE_USB(a, b) (!strcmp((a)->intf, (b)->intf))
 
 /* DEVICE_ADD
  *
diff --git a/tools/libxl/libxl_usb.c b/tools/libxl/libxl_usb.c
new file mode 100644
index 0000000..830a846
--- /dev/null
+++ b/tools/libxl/libxl_usb.c
@@ -0,0 +1,1277 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ */
+
+#include "libxl_osdeps.h" /* must come before any other headers */
+
+#include "libxl_internal.h"
+
+#define SYSFS_USB_DEVS_PATH "/sys/bus/usb/devices"
+#define SYSFS_USBBACK_DRIVER "/sys/bus/usb/drivers/usbback"
+#define USBBACK_INFO_PATH "/libxl/usbback"
+
+#define USBHUB_CLASS_CODE "09"
+
+static int libxl__device_usbctrl_setdefault(libxl__gc *gc, uint32_t domid,
+                                            libxl_device_usbctrl *usbctrl)
+{
+    int rc;
+
+    if (!usbctrl->usb_version)
+        usbctrl->usb_version = 2;
+
+    if (!usbctrl->num_ports)
+        usbctrl->num_ports = 8;
+
+    if(!usbctrl->backend_domid)
+        usbctrl->backend_domid = 0;
+
+    if (!usbctrl->type)
+        usbctrl->type = LIBXL_USBCTRL_TYPE_PV;
+
+    rc = libxl__resolve_domid(gc, usbctrl->backend_domname,
+                              &usbctrl->backend_domid);
+
+    return rc;
+}
+
+static int libxl__device_from_usbctrl(libxl__gc *gc, uint32_t domid,
+                                      libxl_device_usbctrl *usbctrl,
+                                      libxl__device *device)
+{
+    device->backend_devid   = usbctrl->devid;
+    device->backend_domid   = usbctrl->backend_domid;
+    device->backend_kind    = LIBXL__DEVICE_KIND_VUSB;
+    device->devid           = usbctrl->devid;
+    device->domid           = domid;
+    device->kind            = LIBXL__DEVICE_KIND_VUSB;
+
+    return 0;
+}
+
+static int libxl__usbport_add_xenstore(libxl__gc *gc,
+                                       xs_transaction_t tran,
+                                       uint32_t domid,
+                                       libxl_device_usbctrl *usbctrl)
+{
+    char *path;
+    int i;
+
+    path = GCSPRINTF("%s/backend/vusb/%d/%d/port",
+                     libxl__xs_get_dompath(gc, 0), domid, usbctrl->devid);
+
+    libxl__xs_mkdir(gc, tran, path, NULL, 0);
+
+    for (i = 1; i <= usbctrl->num_ports; i++) {
+        if (libxl__xs_write_checked(gc, tran, GCSPRINTF("%s/%d", path, i), ""))
+            return ERROR_FAIL;
+    }
+
+    return 0;
+}
+
+static int libxl__usbctrl_add_xenstore(libxl__gc *gc, uint32_t domid,
+                                       libxl_device_usbctrl *usbctrl)
+{
+    libxl_ctx *ctx = libxl__gc_owner(gc);
+    flexarray_t *front;
+    flexarray_t *back;
+    libxl__device *device;
+    xs_transaction_t tran;
+    int rc = 0;
+
+    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(back, "frontend-id");
+    flexarray_append(back, libxl__sprintf(gc, "%d", domid));
+    flexarray_append(back, "online");
+    flexarray_append(back, "1");
+    flexarray_append(back, "state");
+    flexarray_append(back, libxl__sprintf(gc, "%d", 1));
+    flexarray_append(back, "usb-ver");
+    flexarray_append(back, libxl__sprintf(gc, "%d", usbctrl->usb_version));
+    flexarray_append(back, "num-ports");
+    flexarray_append(back, libxl__sprintf(gc, "%d", usbctrl->num_ports));
+    flexarray_append(back, "type");
+    switch(usbctrl->type) {
+    case LIBXL_USBCTRL_TYPE_PV:{
+        flexarray_append(back, "PVUSB");
+        break;
+    }
+    case LIBXL_USBCTRL_TYPE_DEVICEMODEL: {
+        flexarray_append(back, "IOEMU");
+        break;
+    }
+    default:
+        /* not supported */
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    flexarray_append(front, "backend-id");
+    flexarray_append(front, libxl__sprintf(gc, "%d", usbctrl->backend_domid));
+    flexarray_append(front, "state");
+    flexarray_append(front, libxl__sprintf(gc, "%d", 1));
+
+retry_transaction:
+    tran = xs_transaction_start(ctx->xsh);
+
+    libxl__device_generic_add(gc, tran, device,
+                              libxl__xs_kvs_of_flexarray(gc, back, back->count),
+                              libxl__xs_kvs_of_flexarray(gc, front, front->count),
+                              NULL);
+    libxl__usbport_add_xenstore(gc, tran, domid, usbctrl);
+
+    if (!xs_transaction_end(ctx->xsh, tran, 0)) {
+        if (errno == EAGAIN)
+            goto retry_transaction;
+        else {
+            rc = ERROR_FAIL;
+            goto out;
+        }
+    }
+
+out:
+    return rc;
+}
+
+static int libxl__device_usbctrl_add(libxl__gc *gc, uint32_t domid,
+                                     libxl_device_usbctrl *usbctrl)
+{
+    int rc = 0;
+
+    rc = libxl__device_usbctrl_setdefault(gc, domid, usbctrl);
+    if(rc) goto out;
+
+    if (usbctrl->devid == -1) {
+        if ((usbctrl->devid = libxl__device_nextid(gc, domid, "vusb")) < 0) {
+            rc = ERROR_FAIL;
+            goto out;
+        }
+    }
+
+    if (libxl__usbctrl_add_xenstore(gc, domid, usbctrl) < 0){
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+out:
+    return rc;
+}
+
+int libxl_device_usbctrl_add(libxl_ctx *ctx, uint32_t domid,
+                             libxl_device_usbctrl *usbctrl,
+                             const libxl_asyncop_how *ao_how)
+{
+    AO_CREATE(ctx, domid, ao_how);
+    int rc;
+
+    rc = libxl__device_usbctrl_add(gc, domid, usbctrl);
+    libxl__ao_complete(egc, ao, rc);
+    return AO_INPROGRESS;
+}
+
+libxl_device_usbctrl *
+libxl_device_usbctrl_list(libxl_ctx *ctx, uint32_t domid, int *num)
+{
+    GC_INIT(ctx);
+
+    libxl_device_usbctrl *usbctrls = NULL;
+    char *fe_path = NULL;
+    char **dir = NULL;
+    unsigned int ndirs = 0;
+
+    *num = 0;
+
+    fe_path = libxl__sprintf(gc, "%s/device/vusb",
+                             libxl__xs_get_dompath(gc, domid));
+    dir = libxl__xs_directory(gc, XBT_NULL, fe_path, &ndirs);
+
+    if (dir && ndirs) {
+        usbctrls = malloc(sizeof(*usbctrls) * ndirs);
+        libxl_device_usbctrl* usbctrl;
+        libxl_device_usbctrl* end = usbctrls + ndirs;
+        for(usbctrl = usbctrls; usbctrl < end; usbctrl++, dir++, (*num)++) {
+            char *tmp;
+            const char *be_path = libxl__xs_read(gc, XBT_NULL,
+                                    GCSPRINTF("%s/%s/backend", fe_path, *dir));
+
+            libxl_device_usbctrl_init(usbctrl);
+
+            usbctrl->devid = atoi(*dir);
+
+            tmp = libxl__xs_read(gc, XBT_NULL,
+                                 GCSPRINTF("%s/%s/backend-id", fe_path, *dir));
+            if (!tmp) goto outerr;
+            usbctrl->backend_domid = atoi(tmp);
+
+            tmp = libxl__xs_read(gc, XBT_NULL,
+                                 GCSPRINTF("%s/usb-ver", be_path));
+            if (!tmp) goto outerr;
+            usbctrl->usb_version = atoi(tmp);
+
+            tmp = libxl__xs_read(gc, XBT_NULL,
+                                 GCSPRINTF("%s/num-ports", be_path));
+            if (!tmp) goto outerr;
+            usbctrl->num_ports = atoi(tmp);
+       }
+    }
+    *num = ndirs;
+
+    return usbctrls;
+
+outerr:
+    LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "Unable to list USB Controllers");
+    for (int i = 0; i < *num; i++) {
+        libxl_device_usbctrl_dispose(usbctrls + i);
+    }
+    free(usbctrls);
+    *num = 0;
+    return NULL;
+}
+
+static int libxl__device_usb_list(libxl__gc *gc, uint32_t domid, int usbctrl,
+                                  libxl_device_usb **usbs, int *num);
+
+static int libxl__device_usb_remove_common(libxl__gc *gc, uint32_t domid,
+                                libxl_device_usb *usb, int force);
+
+static int
+libxl__device_usbctrl_remove_common(libxl_ctx *ctx, uint32_t domid,
+                                    libxl_device_usbctrl *usbctrl,
+                                    const libxl_asyncop_how *ao_how,
+                                    int force)
+{
+    AO_CREATE(ctx, domid, ao_how);
+    libxl__device *device;
+    libxl__ao_device *aodev;
+    libxl_device_usb *usbs = NULL;
+    int numusb = 0;
+    int i, rc;
+
+    GCNEW(device);
+    rc = libxl__device_from_usbctrl(gc, domid, usbctrl, device);
+    if(rc) goto out;
+
+    /* Remove usb devives first */
+    rc  = libxl__device_usb_list(gc, domid, usbctrl->devid, &usbs, &numusb);
+    if (rc) goto out;
+    for (i = 0; i < numusb; i++) {
+        if (libxl__device_usb_remove_common(gc, domid, &usbs[i], 0)) {
+            fprintf(stderr, "libxl_device_usb_remove failed.\n");
+            return -1;
+        }
+    }
+    /* remove usbctrl */
+    GCNEW(aodev);
+    libxl__prepare_ao_device(ao, aodev);
+    aodev->action = LIBXL__DEVICE_ACTION_REMOVE;
+    aodev->dev = device;
+    aodev->callback = device_addrm_aocomplete;
+    aodev->force = force;
+    libxl__initiate_device_remove(egc, aodev);
+
+out:
+    if(rc) return AO_ABORT(rc);
+    return AO_INPROGRESS;
+}
+
+int libxl_device_usbctrl_remove(libxl_ctx *ctx, uint32_t domid,
+                                libxl_device_usbctrl *usbctrl,
+                                const libxl_asyncop_how *ao_how)
+{
+    return libxl__device_usbctrl_remove_common(ctx, domid, usbctrl, ao_how, 0);
+}
+
+int libxl_device_usbctrl_destroy(libxl_ctx *ctx, uint32_t domid,
+                                 libxl_device_usbctrl *usbctrl,
+                                 const libxl_asyncop_how *ao_how)
+{
+    return libxl__device_usbctrl_remove_common(ctx, domid, usbctrl, ao_how, 1);
+}
+
+int libxl_device_usbctrl_getinfo(libxl_ctx *ctx, uint32_t domid,
+                                libxl_device_usbctrl *usbctrl,
+                                libxl_usbctrlinfo *usbctrlinfo)
+{
+    GC_INIT(ctx);
+    char *dompath, *usbctrlpath;
+    char *val;
+    int rc = 0;
+
+    dompath = libxl__xs_get_dompath(gc, domid);
+    usbctrlinfo->devid = usbctrl->devid;
+    usbctrlinfo->num_ports = usbctrl->num_ports;
+    usbctrlinfo->version = usbctrl->usb_version;
+
+    usbctrlpath = libxl__sprintf(gc, "%s/device/vusb/%d", dompath, usbctrlinfo->devid);
+    usbctrlinfo->backend = libxl__xs_read(gc, XBT_NULL,
+                                libxl__sprintf(gc, "%s/backend", usbctrlpath));
+    if (!usbctrlinfo->backend) {
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    val = libxl__xs_read(gc, XBT_NULL,
+                         GCSPRINTF("%s/backend-id", usbctrlpath));
+    usbctrlinfo->backend_id = val ? strtoul(val, NULL, 10) : -1;
+
+    val = libxl__xs_read(gc, XBT_NULL,
+                         GCSPRINTF("%s/state", usbctrlpath));
+    usbctrlinfo->state = val ? strtoul(val, NULL, 10) : -1;
+
+    val = libxl__xs_read(gc, XBT_NULL,
+                         GCSPRINTF("%s/event-channel", usbctrlpath));
+    usbctrlinfo->evtch = val ? strtoul(val, NULL, 10) : -1;
+
+    val = libxl__xs_read(gc, XBT_NULL,
+                         GCSPRINTF("%s/urb-ring-ref", usbctrlpath));
+    usbctrlinfo->ref_urb = val ? strtoul(val, NULL, 10) : -1;
+
+    val = libxl__xs_read(gc, XBT_NULL,
+                         GCSPRINTF("%s/conn-ring-ref", usbctrlpath));
+    usbctrlinfo->ref_conn= val ? strtoul(val, NULL, 10) : -1;
+
+    usbctrlinfo->type = libxl__xs_read(gc, XBT_NULL,
+                                GCSPRINTF("%s/type", usbctrlinfo->backend));
+
+    usbctrlinfo->frontend = libxl__xs_read(gc, XBT_NULL,
+                                GCSPRINTF("%s/frontend", usbctrlinfo->backend));
+
+    val = libxl__xs_read(gc, XBT_NULL,
+                         GCSPRINTF("%s/frontend-id", usbctrlinfo->backend));
+    usbctrlinfo->frontend_id = val ? strtoul(val, NULL, 10) : -1;
+
+out:
+    GC_FREE;
+    return rc;
+}
+
+int libxl_devid_to_device_usbctrl(libxl_ctx *ctx, uint32_t domid,
+                                  int devid, libxl_device_usbctrl *usbctrl)
+{
+    GC_INIT(ctx);
+    char* fe_path = NULL, *be_path = NULL, *tmp;
+    int rc = 0;
+
+    libxl_device_usbctrl_init(usbctrl);
+    usbctrl->devid = devid;
+
+    fe_path = libxl__sprintf(gc, "%s/device/vusb",
+                             libxl__xs_get_dompath(gc, domid));
+    be_path = libxl__xs_read(gc, XBT_NULL,
+                             GCSPRINTF("%s/%d/backend", fe_path, devid));
+
+    tmp = libxl__xs_read(gc, XBT_NULL,
+                         GCSPRINTF("%s/%d/backend-id", fe_path, devid));
+    if (!tmp) {
+        rc = ERROR_FAIL;
+        goto out;
+    }
+    usbctrl->backend_domid = atoi(tmp);
+
+    tmp = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/usb-ver", be_path));
+    usbctrl->usb_version = atoi(tmp);
+
+    tmp = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/num-ports", be_path));
+    usbctrl->num_ports = atoi(tmp);
+
+out:
+    GC_FREE;
+    return rc;
+}
+
+/* usb device functions */
+
+/* Following functions are to get assignable usb devices */
+static int
+libxl__device_usb_assigned_list(libxl__gc *gc,
+                                libxl_device_usb **list, int *num)
+{
+    char **domlist;
+    unsigned int nd = 0, i, j;
+    char *be_path;
+    libxl_device_usb *usb;
+
+    *list = NULL;
+    *num = 0;
+
+    domlist = libxl__xs_directory(gc, XBT_NULL, "/local/domain", &nd);
+    be_path = libxl__sprintf(gc,"/local/domain/0/backend/vusb");
+    for (i = 0; i < nd; i++) {
+        char *path, *num_ports, **ctrl_list;
+        unsigned int nc = 0;
+        path = libxl__sprintf(gc, "%s/%s", be_path, domlist[i]);
+        ctrl_list = libxl__xs_directory(gc, XBT_NULL, path , &nc);
+
+        for (j = 0; j < nc; j++) {
+            path = libxl__sprintf(gc, "%s/%s/%s/num-ports", be_path,
+                                  domlist[i], ctrl_list[j]);
+            num_ports = libxl__xs_read(gc, XBT_NULL, path);
+            if ( num_ports ) {
+                int nport = atoi(num_ports), k;
+                char *devpath, *intf;
+
+                for (k = 1; k <= nport; k++) {
+                    devpath = libxl__sprintf(gc, "%s/%s/%s/port/%u", be_path,
+                                             domlist[i], ctrl_list[j], k);
+                    intf = libxl__xs_read(gc, XBT_NULL, devpath);
+                    /* If there are USB device attached, add it to list */
+                    if (intf && strcmp(intf, "") ) {
+                        *list = realloc(*list,
+                                  sizeof(libxl_device_usb) * ((*num) + 1));
+                        if (*list == NULL)
+                            return ERROR_NOMEM;
+                        usb = *list + *num;
+                        usb->ctrl = atoi(ctrl_list[j]);
+                        usb->port = k;
+                        usb->intf = strdup(intf);
+                        (*num)++;
+                    }
+                }
+            }
+        }
+    }
+    libxl__ptr_add(gc, *list);
+
+    return 0;
+}
+
+static bool is_usb_in_array(libxl_device_usb *usbs, int num, char *intf)
+{
+    int i;
+
+    for (i = 0; i < num; i++) {
+        if (!strcmp(usbs[i].intf, intf) )
+            return true;
+    }
+
+    return false;
+}
+
+static int get_usb_bDeviceClass(libxl__gc *gc, char *intf, char *buf)
+{
+    char *path;
+    FILE *fd;
+    int rc;
+
+    path = libxl__sprintf(gc, SYSFS_USB_DEVS_PATH"/%s/bDeviceClass", intf);
+
+    /* Check if this path exist, if not return -1 */
+    if (access(path, R_OK) )
+        return -1;
+
+    fd = popen(GCSPRINTF("cat %s", path), "r");
+    rc = fscanf(fd, "%s", buf);
+    pclose(fd);
+
+    return (rc > 0) ? 0 : -1;
+}
+
+static bool is_usb_assignable(libxl__gc *gc, char *intf)
+{
+    char buf[5];
+
+    if (get_usb_bDeviceClass(gc, intf, buf) < 0)
+        return false;
+
+    if (strcmp(buf, USBHUB_CLASS_CODE))
+        return false;
+
+    return true;
+}
+
+libxl_device_usb *
+libxl_device_usb_assignable_list(libxl_ctx *ctx, int *num)
+{
+    GC_INIT(ctx);
+    libxl_device_usb *usbs = NULL;
+    libxl_device_usb *assigned;
+    int num_assigned;
+    struct dirent *de;
+    DIR *dir;
+
+    *num = 0;
+
+    if (libxl__device_usb_assigned_list(gc, &assigned, &num_assigned) < 0)
+        goto out;
+
+    if (!(dir = opendir(SYSFS_USB_DEVS_PATH)))
+        goto out;
+
+    while((de = readdir(dir))) {
+        if (!de->d_name)
+            continue;
+
+        if(is_usb_assignable(gc, de->d_name))
+            continue;
+
+        if (is_usb_in_array(assigned, num_assigned, de->d_name))
+            continue;
+
+        usbs = realloc(usbs, sizeof(*usbs)*((*num) + 1));
+        usbs[*num].intf = strdup(de->d_name);
+        (*num)++;
+    }
+
+    closedir(dir);
+
+out:
+    GC_FREE;
+    return usbs;
+}
+
+/* get usb devices under certain usb controller */
+static int libxl__device_usb_list(libxl__gc *gc, uint32_t domid, int usbctrl,
+                                  libxl_device_usb **usbs, int *num)
+{
+    char *be_path, *num_devs;
+    int n, i;
+    libxl_device_usb *usb = NULL;
+
+    usbs = NULL;
+    *num = 0;
+
+    be_path = libxl__sprintf(gc, "%s/backend/vusb/%d/%d",
+                             libxl__xs_get_dompath(gc, 0), domid, usbctrl);
+    num_devs = libxl__xs_read(gc, XBT_NULL,
+                              libxl__sprintf(gc, "%s/num-ports", be_path));
+    if (!num_devs)
+        return 0;
+
+    n = atoi(num_devs);
+    usb = calloc(n, sizeof(libxl_device_usb));
+    usbs = &usb;
+
+    for (i = 0; i < n; i++) {
+        char *intf;
+        intf = libxl__xs_read(gc, XBT_NULL,
+                              libxl__sprintf(gc,"%s/port/%d", be_path, i + 1));
+        if (intf && strcmp(intf, "") ) {
+            usbs[i]->ctrl = usbctrl;
+            usbs[i]->port = i + 1;
+            usbs[i]->intf = strdup(intf);
+            (*num)++;
+        }
+    }
+
+    return 0;
+}
+
+libxl_device_usb *libxl_device_usb_list(libxl_ctx *ctx, uint32_t domid,
+                                        int usbctrl, int *num)
+{
+    GC_INIT(ctx);
+    libxl_device_usb *usbs = NULL;
+
+    libxl__device_usb_list(gc, domid, usbctrl, &usbs, num);
+
+    GC_FREE;
+    return usbs;
+}
+
+/* get all usb devices of the domain */
+static libxl_device_usb *
+libxl_device_usb_list_all(libxl__gc *gc, uint32_t domid, int *num)
+{
+    char **usbctrls;
+    unsigned int nd, i, j;
+    char *be_path;
+    int rc;
+    libxl_device_usb *usbs = NULL;
+
+    *num = 0;
+
+    be_path = GCSPRINTF("/local/domain/0/backend/vusb/%d", domid);
+    usbctrls = libxl__xs_directory(gc, XBT_NULL, be_path, &nd);
+
+    for (i = 0; i < nd; i++) {
+        int nc = 0;
+        libxl_device_usb *tmp = NULL;
+        rc = libxl__device_usb_list(gc, domid, atoi(usbctrls[i]), &tmp, &nc);
+        if (!nc) continue;
+
+        usbs = realloc(usbs, sizeof(libxl_device_usb)*((*num) + nc));
+        for(j = 0; j < nc; j++) {
+            usbs[*num].ctrl = tmp[j].ctrl;
+            usbs[*num].port = tmp[j].port;
+            usbs[*num].intf = strdup(tmp[j].intf);
+            (*num)++;
+        }
+        free(tmp);
+    }
+    return usbs;
+}
+
+/* set default value */
+
+/* find first unused controller:port and give that to usb device */
+static int
+libxl__device_usb_set_default_usbctrl(libxl__gc *gc, uint32_t domid,
+                                      libxl_device_usb *usb)
+{
+    libxl_ctx *ctx = CTX;
+    libxl_device_usbctrl *usbctrls;
+    libxl_device_usb *usbs = NULL;
+    int numctrl, numusb, i, j, rc = -1;
+    char *be_path, *tmp;
+
+    usbctrls = libxl_device_usbctrl_list(ctx, domid, &numctrl);
+    if ( !numctrl)
+        goto out;
+
+    for (i = 0; i < numctrl; i++) {
+        rc = libxl__device_usb_list(gc, domid, usbctrls[i].devid,
+                                    &usbs, &numusb);
+        if (rc) continue;
+
+        if (!usbctrls[i].num_ports || numusb == usbctrls[i].num_ports)
+            continue;
+
+        for (j = 1; i <= numusb; j++) {
+            be_path = libxl__sprintf(gc, "%s/backend/vusb/%d/%d/port/%d",
+                                     libxl__xs_get_dompath(gc, 0), domid,
+                                     usbctrls[i].devid, j);
+            tmp = libxl__xs_read(gc, XBT_NULL, be_path);
+            if (tmp && !strcmp( tmp, "")) {
+                usb->ctrl = usbctrls[i].devid;
+                usb->port = j;
+                break;
+            }
+        }
+    }
+
+    rc = 0;
+
+out:
+    if (usbctrls)
+        free(usbctrls);
+    if (usbs)
+        free(usbs);
+    return rc;
+}
+
+static int libxl__device_usb_setdefault(libxl__gc *gc, uint32_t domid,
+                                        libxl_device_usb *usb)
+{
+    char *be_path, *tmp;
+
+    if (usb->ctrl == -1) {
+        int ret = libxl__device_usb_set_default_usbctrl(gc, domid, usb);
+        /* If no existing ctrl to host this usb device, setup a new one */
+        if (ret) {
+            libxl_device_usbctrl usbctrl;
+            libxl_device_usbctrl_init(&usbctrl);
+            libxl__device_usbctrl_add(gc, domid, &usbctrl);
+            usb->ctrl = usbctrl.devid;
+            usb->port = 1;
+            libxl_device_usbctrl_dispose(&usbctrl);
+        }
+    }
+
+    be_path = libxl__sprintf(gc, "%s/backend/vusb/%d/path/%d",
+                    libxl__xs_get_dompath(gc, 0), usb->ctrl, usb->port);
+    tmp = libxl__xs_read(gc, XBT_NULL, be_path);
+    if (!tmp || strcmp(tmp, "") ){
+        LOG(ERROR, "The controller port isn't available.");
+        return ERROR_INVAL;
+    }
+
+    return 0;
+}
+
+/* xenstore usb data */
+static int libxl__device_usb_add_xenstore(libxl__gc *gc, uint32_t domid,
+                                          libxl_device_usb *usb)
+{
+    libxl_ctx *ctx = CTX;
+    char *be_path;
+    int rc;
+    libxl_domain_config d_config;
+    libxl_device_usb usb_saved;
+    libxl__domain_userdata_lock *lock = NULL;
+
+    libxl_domain_config_init(&d_config);
+    libxl_device_usb_init(&usb_saved);
+    libxl_device_usb_copy(CTX, &usb_saved, usb);
+
+    be_path = libxl__sprintf(gc, "%s/backend/vusb/%d/%d",
+                        libxl__xs_get_dompath(gc, 0), domid, usb->ctrl);
+    if (libxl__wait_for_backend(gc, be_path, "4") < 0) {
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    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(usb, usbs, domid, &usb_saved, COMPARE_USB, &d_config);
+
+    rc = libxl__set_domain_configuration(gc, domid, &d_config);
+    if (rc) goto out;
+
+    be_path = libxl__sprintf(gc, "%s/port/%d", be_path, usb->port);
+    LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, "Adding new usb device to xenstore");
+    if (libxl__xs_write_checked(gc, XBT_NULL, be_path, usb->intf)) {
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    rc = 0;
+
+out:
+    if (lock) libxl__unlock_domain_userdata(lock);
+    libxl_device_usb_dispose(&usb_saved);
+    libxl_domain_config_dispose(&d_config);
+    return rc;
+
+}
+
+static int libxl__device_usb_remove_xenstore(libxl__gc *gc, uint32_t domid,
+                                             libxl_device_usb *usb)
+{
+    libxl_ctx *ctx = CTX;
+    char *be_path;
+
+    be_path = libxl__sprintf(gc, "%s/backend/vusb/%d/%d",
+                        libxl__xs_get_dompath(gc, 0), domid, usb->ctrl);
+    if (libxl__wait_for_backend(gc, be_path, "4") < 0)
+        return ERROR_FAIL;
+
+    be_path = libxl__sprintf(gc, "%s/port/%d", be_path, usb->port);
+    LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, "Removing USB device from xenstore");
+    if (libxl__xs_write_checked(gc,XBT_NULL, be_path, ""))
+        return ERROR_FAIL;
+
+    return 0;
+}
+
+/* bind/unbind usb device interface */
+static int unbind_usb_intf(libxl__gc *gc, char *intf, char *drvpath)
+{
+    char *path;
+    int fd, rc = 0;
+
+    drvpath = GCSPRINTF(SYSFS_USB_DEVS_PATH"/%s/driver", intf);
+
+    /* if not bound to a driver, return directly */
+    if (!drvpath)
+        return 0;
+
+    /* else, unbind from driver */
+    path = GCSPRINTF("%s/unbind", drvpath);
+    fd = open(path, O_WRONLY);
+    if (fd < 0) {
+        rc = ERROR_FAIL;
+        goto out;
+    }
+    if (write(fd, intf, strlen(intf)) < 0) {
+        rc = ERROR_FAIL;
+        goto out;
+    }
+    close(fd);
+
+out:
+    return rc;
+}
+
+static int bind_usb_intf(libxl__gc *gc, char *intf, char *drvpath)
+{
+    char *path;
+    int fd, rc = 0;
+
+    path = GCSPRINTF("%s/bind", drvpath);
+    fd = open(path, O_WRONLY);
+    if (fd < 0) {
+        rc = ERROR_FAIL;
+        goto out;
+    }
+    if (write(fd, intf, strlen(intf)) < 0) {
+        rc = ERROR_FAIL;
+        goto out;
+    }
+    close(fd);
+
+out:
+    return rc;
+}
+
+static int usb_get_all_interfaces(libxl__gc *gc, libxl_device_usb *usb,
+                                  char **intfs, int *num)
+{
+    DIR *dir;
+    struct dirent *entry;
+    char *buf;
+    int rc = 0;
+
+    intfs = NULL;
+    *num = 0;
+
+    buf = GCSPRINTF("%s:", usb->intf);
+
+    if (!(dir = opendir(SYSFS_USB_DEVS_PATH))) {
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    while ((entry = readdir(dir)) != NULL) {
+        if (!strncmp(entry->d_name, buf, strlen(buf))){
+            intfs = realloc(intfs, sizeof(char *) * (*num + 1));
+            if (!intfs) {
+                rc = ERROR_FAIL;
+                goto out;
+            }
+            intfs[*num] = strdup(entry->d_name);
+            (*num)++;
+        }
+    }
+
+    closedir(dir);
+
+out:
+    return rc;
+}
+
+/* unbind usb device from usbback driver, if there are many interfaces
+ * under the usb device, then check each interface, unbind from usbback
+ * driver and rebind to original driver
+ */
+static int unbind_usb_device_from_usbback(libxl__gc *gc, libxl_device_usb *usb)
+{
+    char **intfs = NULL;
+    char *path;
+    int num = 0, i;
+    int rc = 0;
+
+    if (usb_get_all_interfaces(gc, usb, intfs, &num) < 0)
+        return ERROR_FAIL;
+
+    for (i = 0; i < num; i++){
+        char *intf = intfs[i];
+        char *drvpath = NULL;
+        char *tmp = NULL;
+
+        drvpath = GCSPRINTF(SYSFS_USB_DEVS_PATH"/%s/driver", intf);
+        if (!drvpath || strcmp(drvpath, SYSFS_USBBACK_DRIVER))
+            continue;
+
+        /* unbind interface from usbback driver */
+        if (unbind_usb_intf(gc, intf, NULL) < 0) {
+            rc = ERROR_FAIL;
+            goto out;
+        }
+
+        /* bind interface to its originial driver */
+        tmp = libxl__xs_read(gc, XBT_NULL,
+                  GCSPRINTF(USBBACK_INFO_PATH"/%s/%s/driver_path",
+                  usb->intf, intf));
+        if (tmp) {
+            if (bind_usb_intf(gc, intf, GCSPRINTF("%s/bind", tmp)) < 0) {
+                free(tmp);
+                rc = ERROR_FAIL;
+                goto out;
+            }
+            free(tmp);
+        }
+    }
+
+    /* finally, remove xs driver path */
+    path = GCSPRINTF(USBBACK_INFO_PATH"/%s", usb->intf);
+    if (libxl__xs_rm_checked(gc, XBT_NULL, path) < 0)
+        rc = ERROR_FAIL;
+
+out:
+    if (intfs) {
+        for (i = 0; i < num; i++)
+            free(intfs[i]);
+        free(intfs);
+    }
+    return rc;
+}
+
+/* bind usb device to "usbback" driver, if there are many interfaces
+ * under the usb device, check each interface, unbind from original
+ * driver and bind to usbback driver.
+ */
+static int bind_usb_device_to_usbback(libxl__gc *gc, libxl_device_usb *usb)
+{
+    char **intfs = NULL;
+    int num = 0, i;
+    int rc = 0;
+
+    if (usb_get_all_interfaces(gc, usb, intfs, &num) < 0)
+        return ERROR_FAIL;
+
+    for (i = 0; i < num; i++){
+        char *intf = intfs[i];
+        char *path = NULL;
+        char *drvpath = NULL;
+
+        /* unbind interface from original driver */
+        if (unbind_usb_intf(gc, intf, drvpath) < 0) {
+            rc = ERROR_FAIL;
+            goto out_rebind;
+        }
+
+        if (drvpath) {
+            /* write driver path to xenstore for later rebinding */
+            path = GCSPRINTF(USBBACK_INFO_PATH"/%s/%s/driver_path",
+                             usb->intf, intf);
+            if (libxl__xs_write_checked(gc, XBT_NULL, path, drvpath) < 0) {
+                rc = ERROR_FAIL;
+                goto out_rebind;
+            }
+        }
+
+        /* bind interface to usbback */
+        if (bind_usb_intf(gc, intf, SYSFS_USBBACK_DRIVER) < 0){
+            rc = ERROR_FAIL;
+            goto out_rebind;
+        }
+    }
+
+    goto out;
+
+out_rebind:
+    /* some interfaces might be bound to usbback, unbind it then and
+     * rebind to its original driver
+     */
+    unbind_usb_device_from_usbback(gc, usb);
+out:
+    if (intfs) {
+        for (i = 0; i < num; i++)
+            free(intfs[i]);
+        free(intfs);
+    }
+
+    return rc;
+}
+
+static int do_usb_add(libxl__gc *gc, uint32_t domid, libxl_device_usb *usb)
+{
+    int rc = 0;
+
+    rc = libxl__device_usb_add_xenstore(gc, domid, usb);
+    if (rc) goto out;
+
+    rc = bind_usb_device_to_usbback(gc, usb);
+    if (rc)
+        libxl__device_usb_remove_xenstore(gc, domid, usb);
+
+out:
+    return rc;
+}
+
+int libxl__device_usb_add(libxl__gc *gc, uint32_t domid, libxl_device_usb *usb)
+{
+    libxl_ctx *ctx = CTX;
+    libxl_device_usb *usbs;
+    int rc, num;
+
+    rc = libxl__device_usb_setdefault(gc, domid, usb);
+    if (rc) goto out;
+
+    rc = libxl__device_usb_assigned_list(gc, &usbs, &num);
+    if (rc) {
+        LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "Fail to get assigned usb list");
+        goto out;
+    }
+
+    if (is_usb_in_array(usbs, num, usb->intf)) {
+        LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
+                   "USB device is already attached to a domain");
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    rc = do_usb_add(gc, domid, usb);
+
+out:
+    return rc;
+}
+
+int libxl_device_usb_add(libxl_ctx *ctx, uint32_t domid,
+                         libxl_device_usb *usb,
+                         const libxl_asyncop_how *ao_how)
+{
+    AO_CREATE(ctx, domid, ao_how);
+    int rc;
+
+    rc = libxl__device_usb_add(gc, domid, usb);
+    libxl__ao_complete(egc, ao, rc);
+    return AO_INPROGRESS;
+}
+
+static int do_usb_remove(libxl__gc *gc, uint32_t domid,
+                         libxl_device_usb *usb, int force)
+{
+
+    libxl_ctx *ctx = CTX;
+    libxl_device_usb *usbs = NULL;
+    int rc = -1, num;
+
+    usbs = libxl_device_usb_list_all(gc, domid, &num);
+    if (!usbs) {
+        LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
+                   "No USB device attached to this domain");
+        goto out;
+    }
+
+    if (!is_usb_in_array(usbs, num, usb->intf)) {
+        LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
+                   "USB device is not attached to this domain");
+        goto out;
+    }
+
+    if (libxl__device_usb_remove_xenstore(gc, domid, usb))
+        goto out;
+
+    if (unbind_usb_device_from_usbback(gc, usb))
+        goto out;
+
+    rc = 0;
+
+out:
+    return rc;
+}
+
+static int libxl__device_usb_remove_common(libxl__gc *gc, uint32_t domid,
+                                           libxl_device_usb *usb, int force)
+{
+    return do_usb_remove(gc, domid, usb, force);
+}
+
+int libxl_device_usb_remove(libxl_ctx *ctx, uint32_t domid,
+                            libxl_device_usb *usb,
+                            const libxl_asyncop_how *ao_how)
+
+{
+    AO_CREATE(ctx, domid, ao_how);
+    int rc;
+
+    rc = libxl__device_usb_remove_common(gc, domid, usb, 0);
+
+    libxl__ao_complete(egc, ao, rc);
+    return AO_INPROGRESS;
+}
+
+int libxl_device_usb_destroy(libxl_ctx *ctx, uint32_t domid,
+                             libxl_device_usb *usb,
+                             const libxl_asyncop_how *ao_how)
+{
+    AO_CREATE(ctx, domid, ao_how);
+    int rc;
+
+    rc = libxl__device_usb_remove_common(gc, domid, usb, 1);
+
+    libxl__ao_complete(egc, ao, rc);
+    return AO_INPROGRESS;
+}
+
+int libxl__device_usb_destroy_all(libxl__gc *gc, uint32_t domid)
+{
+    libxl_ctx *ctx = CTX;
+    libxl_device_usbctrl *usbctrls;
+    int num, i, rc = 0;
+
+    usbctrls = libxl_device_usbctrl_list(ctx, domid, &num);
+    if (!usbctrls)
+        return 0;
+
+    for (i = 0; i < num; i++) {
+        /* Force remove on shutdown since, on HVM, qemu will not always
+         * respond to SCI interrupt because the guest kernel has shut
+         * down the devices by the time we even get here!
+         */
+        if (libxl__device_usbctrl_remove_common(ctx, domid,
+                                          usbctrls + i, 0, 1) < 0) {
+            rc = ERROR_FAIL;
+            goto out;
+        }
+    }
+
+out:
+    if (usbctrls)
+        free(usbctrls);
+    return rc;
+}
+
+/*Get usb device information */
+static int get_usb_devnum (libxl__gc *gc, const char *intf, char *buf)
+{
+    char *path;
+    int rc = 0;
+    FILE *fd;
+
+    path = libxl__sprintf(gc, "cat "SYSFS_USB_DEVS_PATH"/%s/devnum", intf);
+    fd = popen(path, "r");
+    if (fgets(buf, 512, fd) == NULL || ferror(fd))
+        rc = -1;
+    pclose(fd);
+
+    return rc;
+}
+
+static int get_usb_busnum(libxl__gc *gc, const char *intf, char *buf)
+{
+    char *path;
+    int rc = 0;
+    FILE *fd;
+
+    path = libxl__sprintf(gc, "cat "SYSFS_USB_DEVS_PATH"/%s/busnum", intf);
+    fd = popen(path, "r");
+    if (fgets(buf, 512, fd) == NULL || ferror(fd))
+        rc = -1;
+    pclose(fd);
+
+    return rc;
+}
+
+static int get_usb_idVendor(libxl__gc *gc, const char *intf, char *buf)
+{
+    char *path;
+    int rc = 0;
+    FILE *fd;
+
+    path = libxl__sprintf(gc, "cat "SYSFS_USB_DEVS_PATH"/%s/idVendor", intf);
+    fd = popen(path, "r");
+    if (fgets(buf, 512, fd) == NULL || ferror(fd))
+        rc = -1;
+    pclose(fd);
+
+    return rc;
+}
+
+static int get_usb_idProduct(libxl__gc *gc, const char *intf, char *buf)
+{
+    char *path;
+    int rc = 0;
+    FILE *fd;
+
+    path = libxl__sprintf(gc, "cat "SYSFS_USB_DEVS_PATH"/%s/idProduct", intf);
+    fd = popen(path, "r");
+    if (fgets(buf, 512, fd) == NULL || ferror(fd))
+        rc = -1;
+    pclose(fd);
+
+    return rc;
+}
+
+static int get_usb_manufacturer(libxl__gc *gc, const char *intf, char *buf)
+{
+    char *path;
+    int rc = 0;
+    FILE *fd;
+
+    path = libxl__sprintf(gc, "cat "SYSFS_USB_DEVS_PATH"/%s/manufacturer", intf);
+    fd = popen(path, "r");
+    if (fgets(buf, 512, fd) == NULL || ferror(fd))
+        rc = -1;
+    pclose(fd);
+
+    return rc;
+}
+
+static int get_usb_product(libxl__gc *gc, const char *intf, char *buf)
+{
+    char *path;
+    int rc = 0;
+    FILE *fd;
+
+    path = libxl__sprintf(gc, "cat "SYSFS_USB_DEVS_PATH"/%s/product", intf);
+    fd = popen(path, "r");
+    if (fgets(buf, 512, fd) == NULL || ferror(fd))
+        rc = -1;
+    pclose(fd);
+
+    return rc;
+}
+
+int libxl_device_usb_getinfo(libxl_ctx *ctx, char *intf, libxl_usbinfo *usbinfo)
+{
+    GC_INIT(ctx);
+    char buf[512];
+
+    if (!get_usb_devnum(gc, intf, buf) )
+        usbinfo->devnum = atoi(buf);
+
+    if ( !get_usb_busnum(gc, intf, buf))
+        usbinfo->bus = atoi(buf);
+
+    if (!get_usb_idVendor(gc, intf, buf) )
+        usbinfo->idVendor = atoi(buf);
+
+    if (!get_usb_idProduct(gc, intf, buf) )
+        usbinfo->idProduct  = atoi(buf);
+
+    if (!get_usb_manufacturer(gc, intf, buf) )
+        usbinfo->manuf = strdup(buf);
+
+    if (!get_usb_product(gc, intf, buf) )
+        usbinfo->prod = strdup(buf);
+
+    GC_FREE;
+    return 0;
+}
+
+int libxl_intf_to_device_usb(libxl_ctx *ctx, uint32_t domid,
+                             char *intf, libxl_device_usb *usb)
+{
+    GC_INIT(ctx);
+    libxl_device_usb *usbs = NULL;
+    int num, i, rc;
+    bool find = false;
+
+    usbs = libxl_device_usb_list_all(gc, domid, &num);
+
+    for (i = 0; i < num; i++) {
+        if (!strcmp(intf, usbs[i].intf) ) {
+            usb->ctrl = usbs[i].ctrl;
+            usb->port = usbs[i].port;
+            usb->intf = strdup(usbs[i].intf);
+            find = 1;
+            break;
+        }
+    }
+
+    /* doesn't find the usb device in domain's usb device list*/
+    if (!find) {
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    rc = 0;
+
+out:
+    GC_FREE;
+    if (usbs)
+        free(usbs);
+    return rc;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tools/libxl/libxlu_cfg_y.c b/tools/libxl/libxlu_cfg_y.c
index 07b5a1d..78eccf2 100644
--- a/tools/libxl/libxlu_cfg_y.c
+++ b/tools/libxl/libxlu_cfg_y.c
@@ -1,8 +1,8 @@
-/* A Bison parser, made by GNU Bison 2.5.  */
+/* A Bison parser, made by GNU Bison 2.7.  */
 
 /* Bison implementation for Yacc-like parsers in C
    
-      Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc.
+      Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc.
    
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -44,7 +44,7 @@
 #define YYBISON 1
 
 /* Bison version.  */
-#define YYBISON_VERSION "2.5"
+#define YYBISON_VERSION "2.7"
 
 /* Skeleton name.  */
 #define YYSKELETON_NAME "yacc.c"
@@ -58,8 +58,6 @@
 /* Pull parsers.  */
 #define YYPULL 1
 
-/* Using locations.  */
-#define YYLSP_NEEDED 1
 
 /* Substitute the variable and function names.  */
 #define yyparse         xlu__cfg_yyparse
@@ -72,22 +70,23 @@
 #define yylloc          xlu__cfg_yylloc
 
 /* Copy the first part of user declarations.  */
-
-/* Line 268 of yacc.c  */
+/* Line 371 of yacc.c  */
 #line 19 "libxlu_cfg_y.y"
 
 #define ctx_scanner ctx->scanner
 #include "libxlu_cfg_i.h"
 #include "libxlu_cfg_l.h"
 
+/* Line 371 of yacc.c  */
+#line 82 "libxlu_cfg_y.c"
 
-/* Line 268 of yacc.c  */
-#line 86 "libxlu_cfg_y.c"
-
-/* Enabling traces.  */
-#ifndef YYDEBUG
-# define YYDEBUG 0
-#endif
+# ifndef YY_NULL
+#  if defined __cplusplus && 201103L <= __cplusplus
+#   define YY_NULL nullptr
+#  else
+#   define YY_NULL 0
+#  endif
+# endif
 
 /* Enabling verbose error messages.  */
 #ifdef YYERROR_VERBOSE
@@ -97,11 +96,17 @@
 # define YYERROR_VERBOSE 1
 #endif
 
-/* Enabling the token table.  */
-#ifndef YYTOKEN_TABLE
-# define YYTOKEN_TABLE 0
+/* In a future release of Bison, this section will be replaced
+   by #include "libxlu_cfg_y.h".  */
+#ifndef YY_XLU_CFG_YY_LIBXLU_CFG_Y_H_INCLUDED
+# define YY_XLU_CFG_YY_LIBXLU_CFG_Y_H_INCLUDED
+/* Enabling traces.  */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+#if YYDEBUG
+extern int xlu__cfg_yydebug;
 #endif
-
 
 /* Tokens.  */
 #ifndef YYTOKENTYPE
@@ -117,21 +122,18 @@
 #endif
 
 
-
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
 typedef union YYSTYPE
 {
-
-/* Line 293 of yacc.c  */
+/* Line 387 of yacc.c  */
 #line 25 "libxlu_cfg_y.y"
 
   char *string;
   XLU_ConfigSetting *setting;
 
 
-
-/* Line 293 of yacc.c  */
-#line 135 "libxlu_cfg_y.c"
+/* Line 387 of yacc.c  */
+#line 137 "libxlu_cfg_y.c"
 } YYSTYPE;
 # define YYSTYPE_IS_TRIVIAL 1
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
@@ -152,11 +154,26 @@ typedef struct YYLTYPE
 #endif
 
 
-/* Copy the second part of user declarations.  */
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int xlu__cfg_yyparse (void *YYPARSE_PARAM);
+#else
+int xlu__cfg_yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int xlu__cfg_yyparse (CfgParseContext *ctx);
+#else
+int xlu__cfg_yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
 
+#endif /* !YY_XLU_CFG_YY_LIBXLU_CFG_Y_H_INCLUDED  */
+
+/* Copy the second part of user declarations.  */
 
-/* Line 343 of yacc.c  */
-#line 160 "libxlu_cfg_y.c"
+/* Line 390 of yacc.c  */
+#line 177 "libxlu_cfg_y.c"
 
 #ifdef short
 # undef short
@@ -209,24 +226,24 @@ typedef short int yytype_int16;
 # if defined YYENABLE_NLS && YYENABLE_NLS
 #  if ENABLE_NLS
 #   include <libintl.h> /* INFRINGES ON USER NAME SPACE */
-#   define YY_(msgid) dgettext ("bison-runtime", msgid)
+#   define YY_(Msgid) dgettext ("bison-runtime", Msgid)
 #  endif
 # endif
 # ifndef YY_
-#  define YY_(msgid) msgid
+#  define YY_(Msgid) Msgid
 # endif
 #endif
 
 /* Suppress unused-variable warnings by "using" E.  */
 #if ! defined lint || defined __GNUC__
-# define YYUSE(e) ((void) (e))
+# define YYUSE(E) ((void) (E))
 #else
-# define YYUSE(e) /* empty */
+# define YYUSE(E) /* empty */
 #endif
 
 /* Identity function, used to suppress warnings about constant conditions.  */
 #ifndef lint
-# define YYID(n) (n)
+# define YYID(N) (N)
 #else
 #if (defined __STDC__ || defined __C99__FUNC__ \
      || defined __cplusplus || defined _MSC_VER)
@@ -262,6 +279,7 @@ YYID (yyi)
 #    if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
      || defined __cplusplus || defined _MSC_VER)
 #     include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+      /* Use EXIT_SUCCESS as a witness for stdlib.h.  */
 #     ifndef EXIT_SUCCESS
 #      define EXIT_SUCCESS 0
 #     endif
@@ -355,20 +373,20 @@ union yyalloc
 #endif
 
 #if defined YYCOPY_NEEDED && YYCOPY_NEEDED
-/* Copy COUNT objects from FROM to TO.  The source and destination do
+/* Copy COUNT objects from SRC to DST.  The source and destination do
    not overlap.  */
 # ifndef YYCOPY
 #  if defined __GNUC__ && 1 < __GNUC__
-#   define YYCOPY(To, From, Count) \
-      __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+#   define YYCOPY(Dst, Src, Count) \
+      __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src)))
 #  else
-#   define YYCOPY(To, From, Count)		\
-      do					\
-	{					\
-	  YYSIZE_T yyi;				\
-	  for (yyi = 0; yyi < (Count); yyi++)	\
-	    (To)[yyi] = (From)[yyi];		\
-	}					\
+#   define YYCOPY(Dst, Src, Count)              \
+      do                                        \
+        {                                       \
+          YYSIZE_T yyi;                         \
+          for (yyi = 0; yyi < (Count); yyi++)   \
+            (Dst)[yyi] = (Src)[yyi];            \
+        }                                       \
       while (YYID (0))
 #  endif
 # endif
@@ -457,14 +475,14 @@ static const yytype_uint8 yyrline[] =
 };
 #endif
 
-#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+#if YYDEBUG || YYERROR_VERBOSE || 1
 /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
    First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
 static const char *const yytname[] =
 {
   "$end", "error", "$undefined", "IDENT", "STRING", "NUMBER", "NEWLINE",
   "'='", "';'", "'['", "']'", "','", "$accept", "file", "stmts", "stmt",
-  "assignment", "endstmt", "value", "atom", "valuelist", "values", "nlok", 0
+  "assignment", "endstmt", "value", "atom", "valuelist", "values", "nlok", YY_NULL
 };
 #endif
 
@@ -539,10 +557,10 @@ static const yytype_int8 yytable[] =
       16,    26,    25,    20,    13
 };
 
-#define yypact_value_is_default(yystate) \
-  ((yystate) == (-18))
+#define yypact_value_is_default(Yystate) \
+  (!!((Yystate) == (-18)))
 
-#define yytable_value_is_error(yytable_value) \
+#define yytable_value_is_error(Yytable_value) \
   YYID (0)
 
 static const yytype_uint8 yycheck[] =
@@ -588,23 +606,24 @@ static const yytype_uint8 yystos[] =
 
 #define YYRECOVERING()  (!!yyerrstatus)
 
-#define YYBACKUP(Token, Value)					\
-do								\
-  if (yychar == YYEMPTY && yylen == 1)				\
-    {								\
-      yychar = (Token);						\
-      yylval = (Value);						\
-      YYPOPSTACK (1);						\
-      goto yybackup;						\
-    }								\
-  else								\
-    {								\
+#define YYBACKUP(Token, Value)                                  \
+do                                                              \
+  if (yychar == YYEMPTY)                                        \
+    {                                                           \
+      yychar = (Token);                                         \
+      yylval = (Value);                                         \
+      YYPOPSTACK (yylen);                                       \
+      yystate = *yyssp;                                         \
+      goto yybackup;                                            \
+    }                                                           \
+  else                                                          \
+    {                                                           \
       yyerror (&yylloc, ctx, YY_("syntax error: cannot back up")); \
       YYERROR;							\
     }								\
 while (YYID (0))
 
-
+/* Error token number */
 #define YYTERROR	1
 #define YYERRCODE	256
 
@@ -613,27 +632,28 @@ while (YYID (0))
    If N is 0, then set CURRENT to the empty location which ends
    the previous symbol: RHS[0] (always defined).  */
 
-#define YYRHSLOC(Rhs, K) ((Rhs)[K])
 #ifndef YYLLOC_DEFAULT
-# define YYLLOC_DEFAULT(Current, Rhs, N)				\
-    do									\
-      if (YYID (N))                                                    \
-	{								\
-	  (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;	\
-	  (Current).first_column = YYRHSLOC (Rhs, 1).first_column;	\
-	  (Current).last_line    = YYRHSLOC (Rhs, N).last_line;		\
-	  (Current).last_column  = YYRHSLOC (Rhs, N).last_column;	\
-	}								\
-      else								\
-	{								\
-	  (Current).first_line   = (Current).last_line   =		\
-	    YYRHSLOC (Rhs, 0).last_line;				\
-	  (Current).first_column = (Current).last_column =		\
-	    YYRHSLOC (Rhs, 0).last_column;				\
-	}								\
+# define YYLLOC_DEFAULT(Current, Rhs, N)                                \
+    do                                                                  \
+      if (YYID (N))                                                     \
+        {                                                               \
+          (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;        \
+          (Current).first_column = YYRHSLOC (Rhs, 1).first_column;      \
+          (Current).last_line    = YYRHSLOC (Rhs, N).last_line;         \
+          (Current).last_column  = YYRHSLOC (Rhs, N).last_column;       \
+        }                                                               \
+      else                                                              \
+        {                                                               \
+          (Current).first_line   = (Current).last_line   =              \
+            YYRHSLOC (Rhs, 0).last_line;                                \
+          (Current).first_column = (Current).last_column =              \
+            YYRHSLOC (Rhs, 0).last_column;                              \
+        }                                                               \
     while (YYID (0))
 #endif
 
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+
 
 /* YY_LOCATION_PRINT -- Print the location on the stream.
    This macro was not mandated originally: define only if we know
@@ -641,10 +661,46 @@ while (YYID (0))
 
 #ifndef YY_LOCATION_PRINT
 # if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
-#  define YY_LOCATION_PRINT(File, Loc)			\
-     fprintf (File, "%d.%d-%d.%d",			\
-	      (Loc).first_line, (Loc).first_column,	\
-	      (Loc).last_line,  (Loc).last_column)
+
+/* Print *YYLOCP on YYO.  Private, do not rely on its existence. */
+
+__attribute__((__unused__))
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static unsigned
+yy_location_print_ (FILE *yyo, YYLTYPE const * const yylocp)
+#else
+static unsigned
+yy_location_print_ (yyo, yylocp)
+    FILE *yyo;
+    YYLTYPE const * const yylocp;
+#endif
+{
+  unsigned res = 0;
+  int end_col = 0 != yylocp->last_column ? yylocp->last_column - 1 : 0;
+  if (0 <= yylocp->first_line)
+    {
+      res += fprintf (yyo, "%d", yylocp->first_line);
+      if (0 <= yylocp->first_column)
+        res += fprintf (yyo, ".%d", yylocp->first_column);
+    }
+  if (0 <= yylocp->last_line)
+    {
+      if (yylocp->first_line < yylocp->last_line)
+        {
+          res += fprintf (yyo, "-%d", yylocp->last_line);
+          if (0 <= end_col)
+            res += fprintf (yyo, ".%d", end_col);
+        }
+      else if (0 <= end_col && yylocp->first_column < end_col)
+        res += fprintf (yyo, "-%d", end_col);
+    }
+  return res;
+ }
+
+#  define YY_LOCATION_PRINT(File, Loc)          \
+  yy_location_print_ (File, &(Loc))
+
 # else
 #  define YY_LOCATION_PRINT(File, Loc) ((void) 0)
 # endif
@@ -652,7 +708,6 @@ while (YYID (0))
 
 
 /* YYLEX -- calling `yylex' with the right arguments.  */
-
 #ifdef YYLEX_PARAM
 # define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM)
 #else
@@ -704,6 +759,8 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, ctx)
     CfgParseContext *ctx;
 #endif
 {
+  FILE *yyo = yyoutput;
+  YYUSE (yyo);
   if (!yyvaluep)
     return;
   YYUSE (yylocationp);
@@ -717,7 +774,7 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, ctx)
   switch (yytype)
     {
       default:
-	break;
+        break;
     }
 }
 
@@ -963,12 +1020,11 @@ static int
 yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
                 yytype_int16 *yyssp, int yytoken)
 {
-  YYSIZE_T yysize0 = yytnamerr (0, yytname[yytoken]);
+  YYSIZE_T yysize0 = yytnamerr (YY_NULL, yytname[yytoken]);
   YYSIZE_T yysize = yysize0;
-  YYSIZE_T yysize1;
   enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
   /* Internationalized format string. */
-  const char *yyformat = 0;
+  const char *yyformat = YY_NULL;
   /* Arguments of yyformat. */
   char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
   /* Number of reported tokens (one for the "unexpected", one per
@@ -1028,11 +1084,13 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
                     break;
                   }
                 yyarg[yycount++] = yytname[yyx];
-                yysize1 = yysize + yytnamerr (0, yytname[yyx]);
-                if (! (yysize <= yysize1
-                       && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
-                  return 2;
-                yysize = yysize1;
+                {
+                  YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULL, yytname[yyx]);
+                  if (! (yysize <= yysize1
+                         && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+                    return 2;
+                  yysize = yysize1;
+                }
               }
         }
     }
@@ -1052,10 +1110,12 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
 # undef YYCASE_
     }
 
-  yysize1 = yysize + yystrlen (yyformat);
-  if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
-    return 2;
-  yysize = yysize1;
+  {
+    YYSIZE_T yysize1 = yysize + yystrlen (yyformat);
+    if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+      return 2;
+    yysize = yysize1;
+  }
 
   if (*yymsg_alloc < yysize)
     {
@@ -1117,90 +1177,62 @@ yydestruct (yymsg, yytype, yyvaluep, yylocationp, ctx)
 
   switch (yytype)
     {
-      case 3: /* "IDENT" */
-
-/* Line 1391 of yacc.c  */
+      case 3: /* IDENT */
+/* Line 1398 of yacc.c  */
 #line 40 "libxlu_cfg_y.y"
-	{ free((yyvaluep->string)); };
-
-/* Line 1391 of yacc.c  */
-#line 1128 "libxlu_cfg_y.c"
-	break;
-      case 4: /* "STRING" */
-
-/* Line 1391 of yacc.c  */
+        { free(((*yyvaluep).string)); };
+/* Line 1398 of yacc.c  */
+#line 1186 "libxlu_cfg_y.c"
+        break;
+      case 4: /* STRING */
+/* Line 1398 of yacc.c  */
 #line 40 "libxlu_cfg_y.y"
-	{ free((yyvaluep->string)); };
-
-/* Line 1391 of yacc.c  */
-#line 1137 "libxlu_cfg_y.c"
-	break;
-      case 5: /* "NUMBER" */
-
-/* Line 1391 of yacc.c  */
+        { free(((*yyvaluep).string)); };
+/* Line 1398 of yacc.c  */
+#line 1193 "libxlu_cfg_y.c"
+        break;
+      case 5: /* NUMBER */
+/* Line 1398 of yacc.c  */
 #line 40 "libxlu_cfg_y.y"
-	{ free((yyvaluep->string)); };
-
-/* Line 1391 of yacc.c  */
-#line 1146 "libxlu_cfg_y.c"
-	break;
-      case 18: /* "value" */
-
-/* Line 1391 of yacc.c  */
+        { free(((*yyvaluep).string)); };
+/* Line 1398 of yacc.c  */
+#line 1200 "libxlu_cfg_y.c"
+        break;
+      case 18: /* value */
+/* Line 1398 of yacc.c  */
 #line 43 "libxlu_cfg_y.y"
-	{ xlu__cfg_set_free((yyvaluep->setting)); };
-
-/* Line 1391 of yacc.c  */
-#line 1155 "libxlu_cfg_y.c"
-	break;
-      case 19: /* "atom" */
-
-/* Line 1391 of yacc.c  */
+        { xlu__cfg_set_free(((*yyvaluep).setting)); };
+/* Line 1398 of yacc.c  */
+#line 1207 "libxlu_cfg_y.c"
+        break;
+      case 19: /* atom */
+/* Line 1398 of yacc.c  */
 #line 40 "libxlu_cfg_y.y"
-	{ free((yyvaluep->string)); };
-
-/* Line 1391 of yacc.c  */
-#line 1164 "libxlu_cfg_y.c"
-	break;
-      case 20: /* "valuelist" */
-
-/* Line 1391 of yacc.c  */
+        { free(((*yyvaluep).string)); };
+/* Line 1398 of yacc.c  */
+#line 1214 "libxlu_cfg_y.c"
+        break;
+      case 20: /* valuelist */
+/* Line 1398 of yacc.c  */
 #line 43 "libxlu_cfg_y.y"
-	{ xlu__cfg_set_free((yyvaluep->setting)); };
-
-/* Line 1391 of yacc.c  */
-#line 1173 "libxlu_cfg_y.c"
-	break;
-      case 21: /* "values" */
-
-/* Line 1391 of yacc.c  */
+        { xlu__cfg_set_free(((*yyvaluep).setting)); };
+/* Line 1398 of yacc.c  */
+#line 1221 "libxlu_cfg_y.c"
+        break;
+      case 21: /* values */
+/* Line 1398 of yacc.c  */
 #line 43 "libxlu_cfg_y.y"
-	{ xlu__cfg_set_free((yyvaluep->setting)); };
-
-/* Line 1391 of yacc.c  */
-#line 1182 "libxlu_cfg_y.c"
-	break;
+        { xlu__cfg_set_free(((*yyvaluep).setting)); };
+/* Line 1398 of yacc.c  */
+#line 1228 "libxlu_cfg_y.c"
+        break;
 
       default:
-	break;
+        break;
     }
 }
 
 
-/* Prevent warnings from -Wmissing-prototypes.  */
-#ifdef YYPARSE_PARAM
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void *YYPARSE_PARAM);
-#else
-int yyparse ();
-#endif
-#else /* ! YYPARSE_PARAM */
-#if defined __STDC__ || defined __cplusplus
-int yyparse (CfgParseContext *ctx);
-#else
-int yyparse ();
-#endif
-#endif /* ! YYPARSE_PARAM */
 
 
 /*----------.
@@ -1232,11 +1264,40 @@ yyparse (ctx)
 /* The lookahead symbol.  */
 int yychar;
 
+
+#if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__
+/* Suppress an incorrect diagnostic about yylval being uninitialized.  */
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \
+    _Pragma ("GCC diagnostic push") \
+    _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\
+    _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END \
+    _Pragma ("GCC diagnostic pop")
+#else
+/* Default value used for initialization, for pacifying older GCCs
+   or non-GCC compilers.  */
+static YYSTYPE yyval_default;
+# define YY_INITIAL_VALUE(Value) = Value
+#endif
+static YYLTYPE yyloc_default
+# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+  = { 1, 1, 1, 1 }
+# endif
+;
+#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END
+#endif
+#ifndef YY_INITIAL_VALUE
+# define YY_INITIAL_VALUE(Value) /* Nothing. */
+#endif
+
 /* The semantic value of the lookahead symbol.  */
-YYSTYPE yylval;
+YYSTYPE yylval YY_INITIAL_VALUE(yyval_default);
 
 /* Location data for the lookahead symbol.  */
-YYLTYPE yylloc;
+YYLTYPE yylloc = yyloc_default;
+
 
     /* Number of syntax errors so far.  */
     int yynerrs;
@@ -1250,7 +1311,7 @@ YYLTYPE yylloc;
        `yyvs': related to semantic values.
        `yyls': related to locations.
 
-       Refer to the stacks thru separate pointers, to allow yyoverflow
+       Refer to the stacks through separate pointers, to allow yyoverflow
        to reallocate them elsewhere.  */
 
     /* The state stack.  */
@@ -1276,7 +1337,7 @@ YYLTYPE yylloc;
   int yyn;
   int yyresult;
   /* Lookahead token as an internal (translated) token number.  */
-  int yytoken;
+  int yytoken = 0;
   /* The variables used to return semantic value and location from the
      action routines.  */
   YYSTYPE yyval;
@@ -1295,10 +1356,9 @@ YYLTYPE yylloc;
      Keep to zero when no symbol should be popped.  */
   int yylen = 0;
 
-  yytoken = 0;
-  yyss = yyssa;
-  yyvs = yyvsa;
-  yyls = yylsa;
+  yyssp = yyss = yyssa;
+  yyvsp = yyvs = yyvsa;
+  yylsp = yyls = yylsa;
   yystacksize = YYINITDEPTH;
 
   YYDPRINTF ((stderr, "Starting parse\n"));
@@ -1307,21 +1367,7 @@ YYLTYPE yylloc;
   yyerrstatus = 0;
   yynerrs = 0;
   yychar = YYEMPTY; /* Cause a token to be read.  */
-
-  /* Initialize stack pointers.
-     Waste one element of value and location stack
-     so that they stay on the same level as the state stack.
-     The wasted elements are never initialized.  */
-  yyssp = yyss;
-  yyvsp = yyvs;
-  yylsp = yyls;
-
-#if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
-  /* Initialize the default location before parsing starts.  */
-  yylloc.first_line   = yylloc.last_line   = 1;
-  yylloc.first_column = yylloc.last_column = 1;
-#endif
-
+  yylsp[0] = yylloc;
   goto yysetstate;
 
 /*------------------------------------------------------------.
@@ -1467,7 +1513,9 @@ yybackup:
   yychar = YYEMPTY;
 
   yystate = yyn;
+  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
   *++yyvsp = yylval;
+  YY_IGNORE_MAYBE_UNINITIALIZED_END
   *++yylsp = yylloc;
   goto yynewstate;
 
@@ -1505,79 +1553,68 @@ yyreduce:
   switch (yyn)
     {
         case 9:
-
-/* Line 1806 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 57 "libxlu_cfg_y.y"
     { xlu__cfg_set_store(ctx,(yyvsp[(1) - (3)].string),(yyvsp[(3) - (3)].setting),(yylsp[(3) - (3)]).first_line); }
     break;
 
   case 12:
-
-/* Line 1806 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 62 "libxlu_cfg_y.y"
     { (yyval.setting)= xlu__cfg_set_mk(ctx,1,(yyvsp[(1) - (1)].string)); }
     break;
 
   case 13:
-
-/* Line 1806 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 63 "libxlu_cfg_y.y"
     { (yyval.setting)= (yyvsp[(3) - (4)].setting); }
     break;
 
   case 14:
-
-/* Line 1806 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 65 "libxlu_cfg_y.y"
     { (yyval.string)= (yyvsp[(1) - (1)].string); }
     break;
 
   case 15:
-
-/* Line 1806 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 66 "libxlu_cfg_y.y"
     { (yyval.string)= (yyvsp[(1) - (1)].string); }
     break;
 
   case 16:
-
-/* Line 1806 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 68 "libxlu_cfg_y.y"
     { (yyval.setting)= xlu__cfg_set_mk(ctx,0,0); }
     break;
 
   case 17:
-
-/* Line 1806 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 69 "libxlu_cfg_y.y"
     { (yyval.setting)= (yyvsp[(1) - (1)].setting); }
     break;
 
   case 18:
-
-/* Line 1806 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 70 "libxlu_cfg_y.y"
     { (yyval.setting)= (yyvsp[(1) - (3)].setting); }
     break;
 
   case 19:
-
-/* Line 1806 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 72 "libxlu_cfg_y.y"
     { (yyval.setting)= xlu__cfg_set_mk(ctx,2,(yyvsp[(1) - (2)].string)); }
     break;
 
   case 20:
-
-/* Line 1806 of yacc.c  */
+/* Line 1792 of yacc.c  */
 #line 73 "libxlu_cfg_y.y"
     { xlu__cfg_set_add(ctx,(yyvsp[(1) - (5)].setting),(yyvsp[(4) - (5)].string)); (yyval.setting)= (yyvsp[(1) - (5)].setting); }
     break;
 
 
-
-/* Line 1806 of yacc.c  */
-#line 1581 "libxlu_cfg_y.c"
+/* Line 1792 of yacc.c  */
+#line 1618 "libxlu_cfg_y.c"
       default: break;
     }
   /* User semantic actions sometimes alter yychar, and that requires
@@ -1742,7 +1779,9 @@ yyerrlab1:
       YY_STACK_PRINT (yyss, yyssp);
     }
 
+  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
   *++yyvsp = yylval;
+  YY_IGNORE_MAYBE_UNINITIALIZED_END
 
   yyerror_range[2] = yylloc;
   /* Using YYLLOC is tempting, but would change the location of
@@ -1771,7 +1810,7 @@ yyabortlab:
   yyresult = 1;
   goto yyreturn;
 
-#if !defined(yyoverflow) || YYERROR_VERBOSE
+#if !defined yyoverflow || YYERROR_VERBOSE
 /*-------------------------------------------------.
 | yyexhaustedlab -- memory exhaustion comes here.  |
 `-------------------------------------------------*/
@@ -1813,4 +1852,3 @@ yyreturn:
 }
 
 
-
diff --git a/tools/libxl/libxlu_cfg_y.h b/tools/libxl/libxlu_cfg_y.h
index d7dfaf2..54d4f61 100644
--- a/tools/libxl/libxlu_cfg_y.h
+++ b/tools/libxl/libxlu_cfg_y.h
@@ -1,8 +1,8 @@
-/* A Bison parser, made by GNU Bison 2.5.  */
+/* A Bison parser, made by GNU Bison 2.7.  */
 
 /* Bison interface for Yacc-like parsers in C
    
-      Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc.
+      Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc.
    
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -30,6 +30,15 @@
    This special exception was added by the Free Software Foundation in
    version 2.2 of Bison.  */
 
+#ifndef YY_XLU_CFG_YY_LIBXLU_CFG_Y_H_INCLUDED
+# define YY_XLU_CFG_YY_LIBXLU_CFG_Y_H_INCLUDED
+/* Enabling traces.  */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+#if YYDEBUG
+extern int xlu__cfg_yydebug;
+#endif
 
 /* Tokens.  */
 #ifndef YYTOKENTYPE
@@ -45,29 +54,24 @@
 #endif
 
 
-
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
 typedef union YYSTYPE
 {
-
-/* Line 2068 of yacc.c  */
+/* Line 2058 of yacc.c  */
 #line 25 "libxlu_cfg_y.y"
 
   char *string;
   XLU_ConfigSetting *setting;
 
 
-
-/* Line 2068 of yacc.c  */
-#line 63 "libxlu_cfg_y.h"
+/* Line 2058 of yacc.c  */
+#line 69 "libxlu_cfg_y.h"
 } YYSTYPE;
 # define YYSTYPE_IS_TRIVIAL 1
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
 # define YYSTYPE_IS_DECLARED 1
 #endif
 
-
-
 #if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
 typedef struct YYLTYPE
 {
@@ -82,4 +86,18 @@ typedef struct YYLTYPE
 #endif
 
 
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int xlu__cfg_yyparse (void *YYPARSE_PARAM);
+#else
+int xlu__cfg_yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int xlu__cfg_yyparse (CfgParseContext *ctx);
+#else
+int xlu__cfg_yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
 
+#endif /* !YY_XLU_CFG_YY_LIBXLU_CFG_Y_H_INCLUDED  */
-- 
1.8.4.5

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH RFC V2 4/5] xl: add pvusb commands
  2015-01-19  8:28 [PATCH RFC V2 0/5] pvusb toolstack work Chunyan Liu
                   ` (2 preceding siblings ...)
  2015-01-19  8:28 ` [PATCH RFC V2 3/5] libxl: add pvusb API Chunyan Liu
@ 2015-01-19  8:28 ` Chunyan Liu
  2015-02-10  6:25   ` Jürgen Groß
                     ` (2 more replies)
  2015-01-19  8:28 ` [PATCH RFC V2 5/5] domcreate: support pvusb in configuration file Chunyan Liu
  2015-01-28 15:51 ` [PATCH RFC V2 0/5] pvusb toolstack work Ian Campbell
  5 siblings, 3 replies; 40+ messages in thread
From: Chunyan Liu @ 2015-01-19  8:28 UTC (permalink / raw)
  To: xen-devel
  Cc: lars.kurth, ian.campbell, george.dunlap, Chunyan Liu,
	ian.jackson, caobosimon

Add pvusb commands.

To attach a usb device to guest through pvusb, one could follow
following example:

 #xl usb-ctrl-attach test_vm version=1 num_ports=8

 #xl usb-list test_vm
 will show the usb controllers and port usage under the domain.

 #xl usb-assignable-list
 will list all assignable usb devices now in host, with their
 sysfs interface. (This is very useful since later we will use
 sysfs interface to attach a usb devie to guest)

 #xl usb-attach test_vm 2-1.1
 will find the first usable controller:port, and attach usb
 device with sysfs interface 2-1.1 (sys/bus/usb/devices/2-1.1)
 to it. One could also specify which <controller> and which <port>

 #xl usb-detach test_vm 2-1.1

 #xl usb-ctrl-detach test_vm dev_id
 will destroy the controller with dev_id as specified. Dev_id
 can be traced in usb-list info

Signed-off-by: Chunyan Liu <cyliu@suse.com>
Signed-off-by: Simon Cao <caobosimon@gmail.com>
---
 tools/libxl/xl.h          |   6 ++
 tools/libxl/xl_cmdimpl.c  | 256 ++++++++++++++++++++++++++++++++++++++++++++++
 tools/libxl/xl_cmdtable.c |  30 ++++++
 3 files changed, 292 insertions(+)

diff --git a/tools/libxl/xl.h b/tools/libxl/xl.h
index 5bc138c..f37a99f 100644
--- a/tools/libxl/xl.h
+++ b/tools/libxl/xl.h
@@ -86,6 +86,12 @@ int main_blockdetach(int argc, char **argv);
 int main_vtpmattach(int argc, char **argv);
 int main_vtpmlist(int argc, char **argv);
 int main_vtpmdetach(int argc, char **argv);
+int main_usbassignable_list(int argc, char **argv);
+int main_usbctrl_attach(int argc, char **argv);
+int main_usbctrl_detach(int argc, char **argv);
+int main_usbattach(int argc, char **argv);
+int main_usbdetach(int argc, char **argv);
+int main_usblist(int argc, char **argv);
 int main_uptime(int argc, char **argv);
 int main_claims(int argc, char **argv);
 int main_tmem_list(int argc, char **argv);
diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c
index 0b02a6c..a28f460 100644
--- a/tools/libxl/xl_cmdimpl.c
+++ b/tools/libxl/xl_cmdimpl.c
@@ -3000,6 +3000,262 @@ int main_cd_insert(int argc, char **argv)
     return 0;
 }
 
+static void usbinfo_print(libxl_device_usb *usbs, int num) {
+    int i;
+    if ( usbs == NULL )
+         return;
+    libxl_usbinfo usbinfo;
+    for (i = 0; i < num; i++) {
+        /* TO BE Improved */
+        if (usbs[i].port )
+            printf("Port %d:", usbs[i].port);
+        printf("Interface %8s ", usbs[i].intf);
+        if (!libxl_device_usb_getinfo(ctx, usbs[i].intf, &usbinfo)) {
+            printf("Bus %03d Dev %03d: %04d:%04d %s %s\n",
+                    usbinfo.bus, usbinfo.devnum, usbinfo.idVendor,
+                    usbinfo.idProduct, usbinfo.manuf, usbinfo.prod);
+        }
+        libxl_usbinfo_dispose(&usbinfo);
+    }
+}
+
+
+static void usb_assignable_list(void)
+{
+    libxl_device_usb *usbs;
+    int num;
+
+    usbs = libxl_device_usb_assignable_list(ctx, &num);
+
+    usbinfo_print(usbs, num);
+
+    free(usbs);
+}
+
+int main_usbassignable_list(int argc, char **argv)
+{
+    int opt;
+
+    SWITCH_FOREACH_OPT(opt, "", NULL, "usb-assignable-list", 0) {
+        /* No options */
+    }
+
+    usb_assignable_list();
+    return 0;
+}
+
+int main_usbctrl_attach(int argc, char **argv)
+{
+    uint32_t domid;
+    int opt;
+    char *oparg;
+    libxl_device_usbctrl usbctrl;
+
+    SWITCH_FOREACH_OPT(opt, "", NULL, "usb-controller-attach", 1) {
+        /* No options */
+    }
+
+    domid = find_domain(argv[optind++]);
+
+    libxl_device_usbctrl_init(&usbctrl);
+
+    while (argc >= optind) {
+        if (MATCH_OPTION("type",  argv[optind], oparg)) {
+            if (!strcmp("pv", oparg)) {
+                usbctrl.type = LIBXL_USBCTRL_TYPE_PV;
+            } else if(!strcmp("ioemu", oparg)) {
+                usbctrl.type = LIBXL_USBCTRL_TYPE_DEVICEMODEL;
+            } else {
+                fprintf(stderr, "Invalid parameter `type'.\n");
+                exit(-1);
+            }
+        } else if (MATCH_OPTION("version", argv[optind], oparg)) {
+            usbctrl.usb_version = atoi(oparg);
+        } else if (MATCH_OPTION("num_ports", argv[optind], oparg)) {
+            usbctrl.num_ports = atoi(oparg);
+        }  else {
+            fprintf(stderr, "unrecognized argument `%s'\n", argv[optind]);
+            exit(-1);
+        }
+        optind++;
+    }
+
+    if (dryrun_only) {
+       char* json = libxl_device_usbctrl_to_json(ctx, &usbctrl);
+       printf("usb controller: %s\n", json);
+       free(json);
+       libxl_device_usbctrl_dispose(&usbctrl);
+       if (ferror(stdout) || fflush(stdout)) {
+           perror("stdout");
+           exit(-1);
+       }
+       return 0;
+    }
+
+    if (libxl_device_usbctrl_add(ctx, domid, &usbctrl, 0)) {
+        fprintf(stderr, "libxl_device_usbctrl_add failed.\n");
+        exit(-1);
+    }
+    libxl_device_usbctrl_dispose(&usbctrl);
+    return 0;
+}
+
+int main_usbctrl_detach(int argc, char **argv)
+{
+    uint32_t domid;
+    int devid;
+    int opt;
+    libxl_device_usbctrl usbctrl;
+
+    SWITCH_FOREACH_OPT(opt, "", NULL, "usb-controller-detach", 2) {
+        /* No options */
+    }
+
+    domid = find_domain(argv[optind]);
+    devid = atoi(argv[optind+1]);
+
+    libxl_device_usbctrl_init(&usbctrl);
+
+    if (libxl_devid_to_device_usbctrl(ctx, domid, devid, &usbctrl)) {
+        fprintf(stderr, "Unknown usb controller %d.\n", devid);
+        exit(-1);
+    }
+
+    if(libxl_device_usbctrl_remove(ctx, domid, &usbctrl, 0)) {
+        fprintf(stderr, "libxl_device_usbctrl_add failed.\n");
+        exit(-1);
+    }
+    libxl_device_usbctrl_dispose(&usbctrl);
+    return 0;
+
+}
+
+int main_usbattach(int argc, char **argv)
+{
+    uint32_t domid;
+    int opt;
+    char *oparg;
+    libxl_device_usb usb;
+
+    SWITCH_FOREACH_OPT(opt, "", NULL, "usb-attach", 2) {
+        /* No options */
+    }
+
+    domid = find_domain(argv[optind++]);
+    libxl_device_usb_init(&usb);
+    replace_string(&usb.intf, argv[optind++]);
+    while (argc >= optind) {
+        if (MATCH_OPTION("controller", argv[optind], oparg)) {
+            usb.ctrl = atoi(oparg);
+        } else if (MATCH_OPTION("port", argv[optind], oparg)) {
+            usb.port = atoi(oparg);
+        } else {
+            fprintf(stderr, "unrecognized argument `%s'\n", argv[optind]);
+            exit(-1);
+        }
+        optind++;
+    }
+
+    if (dryrun_only) {
+        char *json = libxl_device_usb_to_json(ctx, &usb);
+        printf("usb: %s\n", json);
+        free(json);
+        libxl_device_usb_dispose(&usb);
+        if (ferror(stdout) || fflush(stdout)) {
+            perror("stdout");
+            exit(-1);
+        }
+        return 0;
+    }
+
+    if (libxl_device_usb_add(ctx, domid, &usb, 0)) {
+        fprintf(stderr, "libxl_device_usb_add failed.\n");
+        exit(-1);
+    }
+
+    libxl_device_usb_dispose(&usb);
+    return 0;
+}
+
+int main_usbdetach(int argc, char **argv)
+{
+    uint32_t domid;
+    int opt;
+    libxl_device_usb usb;
+
+    SWITCH_FOREACH_OPT(opt, "", NULL, "usb-detach", 2) {
+        /* No options */
+    }
+
+    domid = find_domain(argv[optind++]);
+    libxl_device_usb_init(&usb);
+    replace_string(&usb.intf, argv[optind++]);
+
+    if (argc > optind) {
+        fprintf(stderr, "Invalid arguments.\n");
+        exit(-1);
+    }
+
+    if (libxl_intf_to_device_usb(ctx, domid, usb.intf, &usb) ) {
+        fprintf(stderr, "libxl_intf_to_device_usb failed.\n");
+        exit(-1);
+    }
+
+    if (libxl_device_usb_remove(ctx, domid, &usb, 0) ) {
+        fprintf(stderr, "libxl_device_usb_remove failed.\n");
+        exit(-1);
+    }
+    libxl_device_usb_dispose(&usb);
+    return 0;
+}
+
+int main_usblist(int argc, char **argv)
+{
+    uint32_t domid;
+    libxl_device_usbctrl *usbctrls;
+    libxl_device_usb *usbs;
+    libxl_usbctrlinfo usbctrlinfo;
+    int numctrl, numusb, i, opt;
+
+    SWITCH_FOREACH_OPT(opt, "", NULL, "usb-list", 1) {
+        /* No options */
+    }
+
+    domid = find_domain(argv[optind++]);
+
+    if (argc > optind) {
+        fprintf(stderr, "Invalid arguments.\n");
+        exit(-1);
+    }
+
+    usbctrls = libxl_device_usbctrl_list(ctx, domid, &numctrl);
+    if (!usbctrls) {
+        return 0;
+    }
+
+    for (i = 0; i < numctrl; ++i) {
+        printf("%-3s %-5s %-3s %-5s %-7s  %-30s\n",
+                "Idx", "type", "BE", "state", "usb-ver", "BE-path");
+
+        if (!libxl_device_usbctrl_getinfo(ctx, domid,
+                                &usbctrls[i], &usbctrlinfo)) {
+            printf("%-3d %-5s %-3d %-5d %-7d %-30s\n",
+                    i, usbctrlinfo.type, usbctrlinfo.backend_id,
+                    usbctrlinfo.state, usbctrlinfo.version,
+                    usbctrlinfo.backend );
+
+            usbs = libxl_device_usb_list(ctx, domid, usbctrlinfo.devid, &numusb);
+            usbinfo_print(usbs, numusb);
+
+            libxl_usbctrlinfo_dispose(&usbctrlinfo);
+        }
+        libxl_device_usbctrl_dispose(&usbctrls[i]);
+    }
+
+    free(usbctrls);
+    return 0;
+}
+
 int main_console(int argc, char **argv)
 {
     uint32_t domid;
diff --git a/tools/libxl/xl_cmdtable.c b/tools/libxl/xl_cmdtable.c
index 4b30d3d..b29bc2e 100644
--- a/tools/libxl/xl_cmdtable.c
+++ b/tools/libxl/xl_cmdtable.c
@@ -541,6 +541,36 @@ struct cmd_spec cmd_table[] = {
       "\"cache_occupancy\":         Show L3 cache occupancy\n",
     },
 #endif
+    { "usb-ctrl-attach",
+      &main_usbctrl_attach, 1, 1,
+      "Create a virtual USB controller for a domain",
+      "<Domain> [version=<version>] [num_ports=<number>]",
+    },
+    { "usb-ctrl-detach",
+      &main_usbctrl_detach, 0, 1,
+      "Destory the virtual USB controller specified by <DevId> for a domain",
+      "<Domain> <DevId>",
+    },
+    { "usb-attach",
+      &main_usbattach, 1, 2,
+      "Attach a USB device to a domain",
+      "<Domain> <BusId> [controller=<DevId> port=<port>]",
+    },
+    { "usb-detach",
+      &main_usbdetach, 0, 1,
+      "Detach a USB device from a domain",
+      "<Domain> <BusId>",
+    },
+    { "usb-list",
+      &main_usblist, 0, 0,
+      "List information about USB devices for a domain",
+      "<Domain>",
+    },
+    { "usb-assignable-list",
+      &main_usbassignable_list, 0, 0,
+      "List all the assignable USB devices",
+    },
+
 };
 
 int cmdtable_len = sizeof(cmd_table)/sizeof(struct cmd_spec);
-- 
1.8.4.5

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH RFC V2 5/5] domcreate: support pvusb in configuration file
  2015-01-19  8:28 [PATCH RFC V2 0/5] pvusb toolstack work Chunyan Liu
                   ` (3 preceding siblings ...)
  2015-01-19  8:28 ` [PATCH RFC V2 4/5] xl: add pvusb commands Chunyan Liu
@ 2015-01-19  8:28 ` Chunyan Liu
  2015-03-03 11:44   ` Ian Campbell
  2015-01-28 15:51 ` [PATCH RFC V2 0/5] pvusb toolstack work Ian Campbell
  5 siblings, 1 reply; 40+ messages in thread
From: Chunyan Liu @ 2015-01-19  8:28 UTC (permalink / raw)
  To: xen-devel
  Cc: lars.kurth, ian.campbell, george.dunlap, Chunyan Liu,
	ian.jackson, caobosimon

Add code to support pvusb from domain create. One could specify
usb in domain's configuration file and create domain, then usb
device would be attached to guest automatically.

One could specify usb device in config file like this:
usb=['2-1.1']

Signed-off-by: Chunyan Liu <cyliu@suse.com>
Signed-off-by: Simon Cao <caobosimon@gmail.com>
---
 tools/libxl/libxl_create.c | 41 ++++++++++++++++++++++++++++++++++++++---
 tools/libxl/xl_cmdimpl.c   | 40 +++++++++++++++++++++++++++++++++++++++-
 2 files changed, 77 insertions(+), 4 deletions(-)

diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c
index 6f87d1c..dc09c04 100644
--- a/tools/libxl/libxl_create.c
+++ b/tools/libxl/libxl_create.c
@@ -730,6 +730,8 @@ static void domcreate_launch_dm(libxl__egc *egc, libxl__multidev *aodevs,
 
 static void domcreate_attach_vtpms(libxl__egc *egc, libxl__multidev *multidev,
                                    int ret);
+static void domcreate_attach_usbs(libxl__egc *egc, libxl__multidev *multidev,
+                                   int ret);
 static void domcreate_attach_pci(libxl__egc *egc, libxl__multidev *aodevs,
                                  int ret);
 
@@ -1367,13 +1369,13 @@ static void domcreate_attach_vtpms(libxl__egc *egc,
    if (d_config->num_vtpms > 0) {
        /* Attach vtpms */
        libxl__multidev_begin(ao, &dcs->multidev);
-       dcs->multidev.callback = domcreate_attach_pci;
+       dcs->multidev.callback = domcreate_attach_usbs;
        libxl__add_vtpms(egc, ao, domid, d_config, &dcs->multidev);
        libxl__multidev_prepared(egc, &dcs->multidev, 0);
        return;
    }
 
-   domcreate_attach_pci(egc, multidev, 0);
+   domcreate_attach_usbs(egc, multidev, 0);
    return;
 
 error_out:
@@ -1381,6 +1383,39 @@ error_out:
    domcreate_complete(egc, dcs, ret);
 }
 
+static void domcreate_attach_usbs(libxl__egc *egc, libxl__multidev *multidev,
+                                int ret)
+{
+    libxl__domain_create_state *dcs = CONTAINER_OF(multidev, *dcs, multidev);
+    STATE_AO_GC(dcs->ao);
+    int i;
+    libxl_ctx *ctx = CTX;
+    int domid = dcs->guest_domid;
+
+    libxl_domain_config *const d_config = dcs->guest_config;
+
+    if (ret) {
+        LOG(ERROR, "unable to add vtpm devices");
+        goto error_out;
+    }
+
+    for (i = 0; i < d_config->num_usbs; i++) {
+        ret = libxl__device_usb_add(gc, domid, &d_config->usbs[i]);
+        if (ret < 0) {
+            LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
+                       "libxl__device_usb_add failed: %d", ret);
+            goto error_out;
+        }
+    }
+
+    domcreate_attach_pci(egc, multidev, 0);
+    return;
+
+error_out:
+   assert(ret);
+   domcreate_complete(egc, dcs, ret);
+}
+
 static void domcreate_attach_pci(libxl__egc *egc, libxl__multidev *multidev,
                                  int ret)
 {
@@ -1394,7 +1429,7 @@ static void domcreate_attach_pci(libxl__egc *egc, libxl__multidev *multidev,
     libxl_domain_config *const d_config = dcs->guest_config;
 
     if (ret) {
-        LOG(ERROR, "unable to add vtpm devices");
+        LOG(ERROR, "unable to add usb devices");
         goto error_out;
     }
 
diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c
index a28f460..d97f382 100644
--- a/tools/libxl/xl_cmdimpl.c
+++ b/tools/libxl/xl_cmdimpl.c
@@ -985,7 +985,7 @@ static void parse_config_data(const char *config_source,
     const char *buf;
     long l;
     XLU_Config *config;
-    XLU_ConfigList *cpus, *vbds, *nics, *pcis, *cvfbs, *cpuids, *vtpms;
+    XLU_ConfigList *cpus, *vbds, *nics, *pcis, *usbs, *cvfbs, *cpuids, *vtpms;
     XLU_ConfigList *channels, *ioports, *irqs, *iomem, *viridian;
     int num_ioports, num_irqs, num_iomem, num_cpus, num_viridian;
     int pci_power_mgmt = 0;
@@ -1745,6 +1745,44 @@ skip_vfb:
             libxl_defbool_set(&b_info->u.pv.e820_host, true);
     }
 
+    if (!xlu_cfg_get_list (config, "usb", &usbs, 0, 0) ) {
+        d_config->num_usbs = 0;
+        d_config->usbs = NULL;
+        while ((buf = xlu_cfg_get_listitem (usbs, d_config->num_usbs)) != NULL) {
+            libxl_device_usb *usb;
+            char *buf2 = strdup(buf);
+            char *p, *p2;
+
+            d_config->usbs = (libxl_device_usb *) realloc(d_config->usbs,
+                                sizeof (libxl_device_usb) * (d_config->num_usbs+1));
+            usb = d_config->usbs + d_config->num_usbs;
+            libxl_device_usb_init(usb);
+
+            p = strtok(buf2, ",");
+            if(p) {
+                usb->port = -1;
+                usb->ctrl = -1;
+                do {
+                    while(*p == ' ')
+                        ++p;
+                    if ((p2 = strchr(p, '=')) == NULL)
+                     break;
+                    *p2 = '\0';
+                    if (!strcmp(p, "type")) {
+                        //Set type in libxl_device_usb
+                    } else if (!strcmp(p, "interface") ){
+                        usb->intf = strdup(p2 + 1);
+                    } else {
+                        fprintf(stderr, "Unknown string `%s' in usb spec\n", p);
+                        exit(1);
+                    }
+                } while ((p = strtok(NULL, ",")) != NULL);
+            }
+            free(buf2);
+            d_config->num_usbs++;
+        }
+    }
+
     switch (xlu_cfg_get_list(config, "cpuid", &cpuids, 0, 1)) {
     case 0:
         {
-- 
1.8.4.5

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* Re: [PATCH RFC V2 0/5] pvusb toolstack work
  2015-01-19  8:28 [PATCH RFC V2 0/5] pvusb toolstack work Chunyan Liu
                   ` (4 preceding siblings ...)
  2015-01-19  8:28 ` [PATCH RFC V2 5/5] domcreate: support pvusb in configuration file Chunyan Liu
@ 2015-01-28 15:51 ` Ian Campbell
  2015-01-28 16:07   ` Pasi Kärkkäinen
  2015-01-29  3:22   ` Chun Yan Liu
  5 siblings, 2 replies; 40+ messages in thread
From: Ian Campbell @ 2015-01-28 15:51 UTC (permalink / raw)
  To: Chunyan Liu; +Cc: lars.kurth, george.dunlap, xen-devel, ian.jackson, caobosimon

On Mon, 2015-01-19 at 16:28 +0800, Chunyan Liu wrote:
> This patch series is based on Simon's work. Since there is no progress
> after last August, I hope we can make this work proceed. Any comment will
> be very appreciated.
> 
> It adds pvusb toolstack implementation, with pvusb kernel side work,
> one could attach/detach a usb device to guest.

By any chance do you (or anyone else) have a link handy to the design
discussions for this stuff around the start of last year?

In particular I'm hoping for some reminder on what the
libxl_usbctrl_type / libxl_usb_type options mean.

Although this is PV USB only I think the intention was to leave a
suitable hole for HVM emulated USB support. Or am I mis-remembering?

[...]
>  tools/libxl/Makefile                 |    2 +-
>  tools/libxl/libxl.c                  |    8 +-
>  tools/libxl/libxl.h                  |   58 ++
>  tools/libxl/libxl_create.c           |   41 +-
>  tools/libxl/libxl_internal.h         |   11 +
>  tools/libxl/libxl_types.idl          |   58 +-
>  tools/libxl/libxl_types_internal.idl |    1 +
>  tools/libxl/libxl_usb.c              | 1277 ++++++++++++++++++++++++++++++++++
>  tools/libxl/libxlu_cfg_y.c           |  464 ++++++------
>  tools/libxl/libxlu_cfg_y.h           |   38 +-
>  tools/libxl/xl.h                     |    6 +
>  tools/libxl/xl_cmdimpl.c             |  296 +++++++-
>  tools/libxl/xl_cmdtable.c            |   30 +

This will need some docs changes too, at least to the xl and xl.cfg
manpages.

>  13 files changed, 2058 insertions(+), 232 deletions(-)
>  create mode 100644 tools/libxl/libxl_usb.c
> 

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH RFC V2 3/5] libxl: add pvusb API
  2015-01-19  8:28 ` [PATCH RFC V2 3/5] libxl: add pvusb API Chunyan Liu
@ 2015-01-28 15:54   ` Ian Campbell
  2015-01-29  3:24     ` Chun Yan Liu
  2015-02-10 10:08   ` Jürgen Groß
                     ` (4 subsequent siblings)
  5 siblings, 1 reply; 40+ messages in thread
From: Ian Campbell @ 2015-01-28 15:54 UTC (permalink / raw)
  To: Chunyan Liu; +Cc: lars.kurth, george.dunlap, xen-devel, ian.jackson, caobosimon

On Mon, 2015-01-19 at 16:28 +0800, Chunyan Liu wrote:
>  tools/libxl/libxlu_cfg_y.c   |  464 ++++++++-------
>  tools/libxl/libxlu_cfg_y.h   |   38 +-

I think these are spurious changes caused by you having different
versions of flex/bison installed, could you arrange to omit these
please.

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH RFC V2 0/5] pvusb toolstack work
  2015-01-28 15:51 ` [PATCH RFC V2 0/5] pvusb toolstack work Ian Campbell
@ 2015-01-28 16:07   ` Pasi Kärkkäinen
  2015-01-28 16:17     ` Ian Campbell
  2015-01-29  3:22   ` Chun Yan Liu
  1 sibling, 1 reply; 40+ messages in thread
From: Pasi Kärkkäinen @ 2015-01-28 16:07 UTC (permalink / raw)
  To: Ian Campbell
  Cc: lars.kurth, george.dunlap, Chunyan Liu, xen-devel, ian.jackson,
	caobosimon

On Wed, Jan 28, 2015 at 03:51:03PM +0000, Ian Campbell wrote:
> On Mon, 2015-01-19 at 16:28 +0800, Chunyan Liu wrote:
> > This patch series is based on Simon's work. Since there is no progress
> > after last August, I hope we can make this work proceed. Any comment will
> > be very appreciated.
> > 
> > It adds pvusb toolstack implementation, with pvusb kernel side work,
> > one could attach/detach a usb device to guest.
> 
> By any chance do you (or anyone else) have a link handy to the design
> discussions for this stuff around the start of last year?
> 
> In particular I'm hoping for some reminder on what the
> libxl_usbctrl_type / libxl_usb_type options mean.
> 

George probably knows/remembers the best.. 


> Although this is PV USB only I think the intention was to leave a
> suitable hole for HVM emulated USB support. Or am I mis-remembering?
> 

PVUSB should work with both PV and HVM guests, as long as the required PV drivers are in the domU kernel.


-- Pasi

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH RFC V2 0/5] pvusb toolstack work
  2015-01-28 16:07   ` Pasi Kärkkäinen
@ 2015-01-28 16:17     ` Ian Campbell
  0 siblings, 0 replies; 40+ messages in thread
From: Ian Campbell @ 2015-01-28 16:17 UTC (permalink / raw)
  To: Pasi Kärkkäinen
  Cc: lars.kurth, george.dunlap, Chunyan Liu, xen-devel, ian.jackson,
	caobosimon

On Wed, 2015-01-28 at 18:07 +0200, Pasi Kärkkäinen wrote:
> On Wed, Jan 28, 2015 at 03:51:03PM +0000, Ian Campbell wrote:

> > Although this is PV USB only I think the intention was to leave a
> > suitable hole for HVM emulated USB support. Or am I mis-remembering?
> > 
> 
> PVUSB should work with both PV and HVM guests, as long as the required PV drivers are in the domU kernel.

I know this. 

I was asking HVM *emulated* USB support...

Ian.


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

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH RFC V2 0/5] pvusb toolstack work
  2015-01-28 15:51 ` [PATCH RFC V2 0/5] pvusb toolstack work Ian Campbell
  2015-01-28 16:07   ` Pasi Kärkkäinen
@ 2015-01-29  3:22   ` Chun Yan Liu
  1 sibling, 0 replies; 40+ messages in thread
From: Chun Yan Liu @ 2015-01-29  3:22 UTC (permalink / raw)
  To: Ian Campbell
  Cc: lars.kurth, george.dunlap, xen-devel, ian.jackson, caobosimon



>>> On 1/28/2015 at 11:51 PM, in message <1422460263.5187.27.camel@citrix.com>, Ian
Campbell <Ian.Campbell@citrix.com> wrote: 
> On Mon, 2015-01-19 at 16:28 +0800, Chunyan Liu wrote: 
> > This patch series is based on Simon's work. Since there is no progress 
> > after last August, I hope we can make this work proceed. Any comment will 
> > be very appreciated. 
> >  
> > It adds pvusb toolstack implementation, with pvusb kernel side work, 
> > one could attach/detach a usb device to guest. 
>  
> By any chance do you (or anyone else) have a link handy to the design 
> discussions for this stuff around the start of last year? 

Design Discussion Thread:
http://www.redhat.com/archives/libvir-list/2014-June/msg00038.html

>  
> In particular I'm hoping for some reminder on what the 
> libxl_usbctrl_type / libxl_usb_type options mean. 

According to the design discussion, the intention of these two structures
was to unify PVUSB way and HVM QEMU emulated way.

libxl_usbctrl_type is to differentiate it is PVUSB or QEMU emulated.
George had a patch series to support add/remove usb in HVM by qemu
emulated way. In that patch series, it uses libxl_usb_protocol to
differeentiate PVUSB or QEMU emulated.
http://lists.xen.org/archives/html/xen-devel/2014-06/msg00086.html

libxl_usb_type is used in QEMU emulated way, since qemu usb-add support
many usb types, like: host, tablet, mouse, keyboard, net, serial, disk, etc.

For pvusb work only, this patch series sets libxl_usbctrl_type to 'PVUSB' always,
and libxl_usb_type is not used.

>  
> Although this is PV USB only I think the intention was to leave a 
> suitable hole for HVM emulated USB support. Or am I mis-remembering? 

Yes. It intended to leave hole for HVM QEMU emulated USB support.

- Chunyan

>  
> [...] 
> >  tools/libxl/Makefile                 |    2 +- 
> >  tools/libxl/libxl.c                  |    8 +- 
> >  tools/libxl/libxl.h                  |   58 ++ 
> >  tools/libxl/libxl_create.c           |   41 +- 
> >  tools/libxl/libxl_internal.h         |   11 + 
> >  tools/libxl/libxl_types.idl          |   58 +- 
> >  tools/libxl/libxl_types_internal.idl |    1 + 
> >  tools/libxl/libxl_usb.c              | 1277  
> ++++++++++++++++++++++++++++++++++ 
> >  tools/libxl/libxlu_cfg_y.c           |  464 ++++++------ 
> >  tools/libxl/libxlu_cfg_y.h           |   38 +- 
> >  tools/libxl/xl.h                     |    6 + 
> >  tools/libxl/xl_cmdimpl.c             |  296 +++++++- 
> >  tools/libxl/xl_cmdtable.c            |   30 + 
>  
> This will need some docs changes too, at least to the xl and xl.cfg 
> manpages. 
>  
> >  13 files changed, 2058 insertions(+), 232 deletions(-) 
> >  create mode 100644 tools/libxl/libxl_usb.c 
> >  
>  
>  
>  
>  

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH RFC V2 3/5] libxl: add pvusb API
  2015-01-28 15:54   ` Ian Campbell
@ 2015-01-29  3:24     ` Chun Yan Liu
  0 siblings, 0 replies; 40+ messages in thread
From: Chun Yan Liu @ 2015-01-29  3:24 UTC (permalink / raw)
  To: Ian Campbell
  Cc: lars.kurth, george.dunlap, xen-devel, ian.jackson, caobosimon



>>> On 1/28/2015 at 11:54 PM, in message <1422460493.5187.28.camel@citrix.com>, Ian
Campbell <Ian.Campbell@citrix.com> wrote: 
> On Mon, 2015-01-19 at 16:28 +0800, Chunyan Liu wrote: 
> >  tools/libxl/libxlu_cfg_y.c   |  464 ++++++++------- 
> >  tools/libxl/libxlu_cfg_y.h   |   38 +- 
>  
> I think these are spurious changes caused by you having different 
> versions of flex/bison installed, could you arrange to omit these 
> please. 

Sorry,  will delete.

>  
>  
>  
>  

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH RFC V2 4/5] xl: add pvusb commands
  2015-01-19  8:28 ` [PATCH RFC V2 4/5] xl: add pvusb commands Chunyan Liu
@ 2015-02-10  6:25   ` Jürgen Groß
  2015-03-03 11:43   ` Ian Campbell
  2015-03-06 17:25   ` George Dunlap
  2 siblings, 0 replies; 40+ messages in thread
From: Jürgen Groß @ 2015-02-10  6:25 UTC (permalink / raw)
  To: Chunyan Liu, xen-devel
  Cc: george.dunlap, lars.kurth, caobosimon, ian.campbell, ian.jackson

On 01/19/2015 09:28 AM, Chunyan Liu wrote:
> Add pvusb commands.
>
> To attach a usb device to guest through pvusb, one could follow
> following example:
>
>   #xl usb-ctrl-attach test_vm version=1 num_ports=8
>
>   #xl usb-list test_vm
>   will show the usb controllers and port usage under the domain.
>
>   #xl usb-assignable-list
>   will list all assignable usb devices now in host, with their
>   sysfs interface. (This is very useful since later we will use
>   sysfs interface to attach a usb devie to guest)
>
>   #xl usb-attach test_vm 2-1.1
>   will find the first usable controller:port, and attach usb
>   device with sysfs interface 2-1.1 (sys/bus/usb/devices/2-1.1)
>   to it. One could also specify which <controller> and which <port>
>
>   #xl usb-detach test_vm 2-1.1
>
>   #xl usb-ctrl-detach test_vm dev_id
>   will destroy the controller with dev_id as specified. Dev_id
>   can be traced in usb-list info

Sorry for late review.

Some comments inline.

>
> Signed-off-by: Chunyan Liu <cyliu@suse.com>
> Signed-off-by: Simon Cao <caobosimon@gmail.com>
> ---
>   tools/libxl/xl.h          |   6 ++
>   tools/libxl/xl_cmdimpl.c  | 256 ++++++++++++++++++++++++++++++++++++++++++++++
>   tools/libxl/xl_cmdtable.c |  30 ++++++
>   3 files changed, 292 insertions(+)
>
> diff --git a/tools/libxl/xl.h b/tools/libxl/xl.h
> index 5bc138c..f37a99f 100644
> --- a/tools/libxl/xl.h
> +++ b/tools/libxl/xl.h
> @@ -86,6 +86,12 @@ int main_blockdetach(int argc, char **argv);
>   int main_vtpmattach(int argc, char **argv);
>   int main_vtpmlist(int argc, char **argv);
>   int main_vtpmdetach(int argc, char **argv);
> +int main_usbassignable_list(int argc, char **argv);
> +int main_usbctrl_attach(int argc, char **argv);
> +int main_usbctrl_detach(int argc, char **argv);
> +int main_usbattach(int argc, char **argv);
> +int main_usbdetach(int argc, char **argv);
> +int main_usblist(int argc, char **argv);
>   int main_uptime(int argc, char **argv);
>   int main_claims(int argc, char **argv);
>   int main_tmem_list(int argc, char **argv);
> diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c
> index 0b02a6c..a28f460 100644
> --- a/tools/libxl/xl_cmdimpl.c
> +++ b/tools/libxl/xl_cmdimpl.c
> @@ -3000,6 +3000,262 @@ int main_cd_insert(int argc, char **argv)
>       return 0;
>   }
>
> +static void usbinfo_print(libxl_device_usb *usbs, int num) {
> +    int i;
> +    if ( usbs == NULL )
> +         return;
> +    libxl_usbinfo usbinfo;
> +    for (i = 0; i < num; i++) {
> +        /* TO BE Improved */
> +        if (usbs[i].port )
> +            printf("Port %d:", usbs[i].port);
> +        printf("Interface %8s ", usbs[i].intf);
> +        if (!libxl_device_usb_getinfo(ctx, usbs[i].intf, &usbinfo)) {
> +            printf("Bus %03d Dev %03d: %04d:%04d %s %s\n",
> +                    usbinfo.bus, usbinfo.devnum, usbinfo.idVendor,
> +                    usbinfo.idProduct, usbinfo.manuf, usbinfo.prod);
> +        }
> +        libxl_usbinfo_dispose(&usbinfo);
> +    }
> +}
> +
> +
> +static void usb_assignable_list(void)
> +{
> +    libxl_device_usb *usbs;
> +    int num;
> +
> +    usbs = libxl_device_usb_assignable_list(ctx, &num);
> +
> +    usbinfo_print(usbs, num);
> +
> +    free(usbs);
> +}
> +
> +int main_usbassignable_list(int argc, char **argv)
> +{
> +    int opt;
> +
> +    SWITCH_FOREACH_OPT(opt, "", NULL, "usb-assignable-list", 0) {
> +        /* No options */
> +    }
> +
> +    usb_assignable_list();
> +    return 0;
> +}
> +
> +int main_usbctrl_attach(int argc, char **argv)
> +{
> +    uint32_t domid;
> +    int opt;
> +    char *oparg;
> +    libxl_device_usbctrl usbctrl;
> +
> +    SWITCH_FOREACH_OPT(opt, "", NULL, "usb-controller-attach", 1) {

Should be "usb-ctrl-attach".

> +        /* No options */
> +    }
> +
> +    domid = find_domain(argv[optind++]);
> +
> +    libxl_device_usbctrl_init(&usbctrl);
> +
> +    while (argc >= optind) {

argc > optind?

> +        if (MATCH_OPTION("type",  argv[optind], oparg)) {
> +            if (!strcmp("pv", oparg)) {
> +                usbctrl.type = LIBXL_USBCTRL_TYPE_PV;
> +            } else if(!strcmp("ioemu", oparg)) {
> +                usbctrl.type = LIBXL_USBCTRL_TYPE_DEVICEMODEL;
> +            } else {
> +                fprintf(stderr, "Invalid parameter `type'.\n");
> +                exit(-1);
> +            }
> +        } else if (MATCH_OPTION("version", argv[optind], oparg)) {
> +            usbctrl.usb_version = atoi(oparg);
> +        } else if (MATCH_OPTION("num_ports", argv[optind], oparg)) {
> +            usbctrl.num_ports = atoi(oparg);
> +        }  else {
> +            fprintf(stderr, "unrecognized argument `%s'\n", argv[optind]);
> +            exit(-1);
> +        }
> +        optind++;
> +    }
> +
> +    if (dryrun_only) {
> +       char* json = libxl_device_usbctrl_to_json(ctx, &usbctrl);
> +       printf("usb controller: %s\n", json);
> +       free(json);
> +       libxl_device_usbctrl_dispose(&usbctrl);
> +       if (ferror(stdout) || fflush(stdout)) {
> +           perror("stdout");
> +           exit(-1);
> +       }
> +       return 0;
> +    }
> +
> +    if (libxl_device_usbctrl_add(ctx, domid, &usbctrl, 0)) {
> +        fprintf(stderr, "libxl_device_usbctrl_add failed.\n");
> +        exit(-1);
> +    }
> +    libxl_device_usbctrl_dispose(&usbctrl);
> +    return 0;
> +}
> +
> +int main_usbctrl_detach(int argc, char **argv)
> +{
> +    uint32_t domid;
> +    int devid;
> +    int opt;
> +    libxl_device_usbctrl usbctrl;
> +
> +    SWITCH_FOREACH_OPT(opt, "", NULL, "usb-controller-detach", 2) {

Should be "usb-ctrl-detach".

> +        /* No options */
> +    }
> +
> +    domid = find_domain(argv[optind]);
> +    devid = atoi(argv[optind+1]);
> +
> +    libxl_device_usbctrl_init(&usbctrl);
> +
> +    if (libxl_devid_to_device_usbctrl(ctx, domid, devid, &usbctrl)) {
> +        fprintf(stderr, "Unknown usb controller %d.\n", devid);
> +        exit(-1);
> +    }
> +
> +    if(libxl_device_usbctrl_remove(ctx, domid, &usbctrl, 0)) {
> +        fprintf(stderr, "libxl_device_usbctrl_add failed.\n");
> +        exit(-1);
> +    }
> +    libxl_device_usbctrl_dispose(&usbctrl);
> +    return 0;
> +
> +}
> +
> +int main_usbattach(int argc, char **argv)
> +{
> +    uint32_t domid;
> +    int opt;
> +    char *oparg;
> +    libxl_device_usb usb;
> +
> +    SWITCH_FOREACH_OPT(opt, "", NULL, "usb-attach", 2) {
> +        /* No options */
> +    }
> +
> +    domid = find_domain(argv[optind++]);
> +    libxl_device_usb_init(&usb);
> +    replace_string(&usb.intf, argv[optind++]);
> +    while (argc >= optind) {

argc > optind?

> +        if (MATCH_OPTION("controller", argv[optind], oparg)) {
> +            usb.ctrl = atoi(oparg);
> +        } else if (MATCH_OPTION("port", argv[optind], oparg)) {
> +            usb.port = atoi(oparg);
> +        } else {
> +            fprintf(stderr, "unrecognized argument `%s'\n", argv[optind]);
> +            exit(-1);
> +        }
> +        optind++;
> +    }
> +
> +    if (dryrun_only) {
> +        char *json = libxl_device_usb_to_json(ctx, &usb);
> +        printf("usb: %s\n", json);
> +        free(json);
> +        libxl_device_usb_dispose(&usb);
> +        if (ferror(stdout) || fflush(stdout)) {
> +            perror("stdout");
> +            exit(-1);
> +        }
> +        return 0;
> +    }
> +
> +    if (libxl_device_usb_add(ctx, domid, &usb, 0)) {
> +        fprintf(stderr, "libxl_device_usb_add failed.\n");
> +        exit(-1);
> +    }
> +
> +    libxl_device_usb_dispose(&usb);
> +    return 0;
> +}
> +
> +int main_usbdetach(int argc, char **argv)
> +{
> +    uint32_t domid;
> +    int opt;
> +    libxl_device_usb usb;
> +
> +    SWITCH_FOREACH_OPT(opt, "", NULL, "usb-detach", 2) {
> +        /* No options */
> +    }
> +
> +    domid = find_domain(argv[optind++]);
> +    libxl_device_usb_init(&usb);
> +    replace_string(&usb.intf, argv[optind++]);
> +
> +    if (argc > optind) {
> +        fprintf(stderr, "Invalid arguments.\n");
> +        exit(-1);
> +    }
> +
> +    if (libxl_intf_to_device_usb(ctx, domid, usb.intf, &usb) ) {
> +        fprintf(stderr, "libxl_intf_to_device_usb failed.\n");
> +        exit(-1);
> +    }
> +
> +    if (libxl_device_usb_remove(ctx, domid, &usb, 0) ) {
> +        fprintf(stderr, "libxl_device_usb_remove failed.\n");
> +        exit(-1);
> +    }
> +    libxl_device_usb_dispose(&usb);
> +    return 0;
> +}
> +
> +int main_usblist(int argc, char **argv)
> +{
> +    uint32_t domid;
> +    libxl_device_usbctrl *usbctrls;
> +    libxl_device_usb *usbs;
> +    libxl_usbctrlinfo usbctrlinfo;
> +    int numctrl, numusb, i, opt;
> +
> +    SWITCH_FOREACH_OPT(opt, "", NULL, "usb-list", 1) {
> +        /* No options */
> +    }
> +
> +    domid = find_domain(argv[optind++]);
> +
> +    if (argc > optind) {
> +        fprintf(stderr, "Invalid arguments.\n");
> +        exit(-1);
> +    }
> +
> +    usbctrls = libxl_device_usbctrl_list(ctx, domid, &numctrl);
> +    if (!usbctrls) {
> +        return 0;
> +    }
> +
> +    for (i = 0; i < numctrl; ++i) {
> +        printf("%-3s %-5s %-3s %-5s %-7s  %-30s\n",
> +                "Idx", "type", "BE", "state", "usb-ver", "BE-path");
> +
> +        if (!libxl_device_usbctrl_getinfo(ctx, domid,
> +                                &usbctrls[i], &usbctrlinfo)) {
> +            printf("%-3d %-5s %-3d %-5d %-7d %-30s\n",
> +                    i, usbctrlinfo.type, usbctrlinfo.backend_id,
> +                    usbctrlinfo.state, usbctrlinfo.version,
> +                    usbctrlinfo.backend );
> +
> +            usbs = libxl_device_usb_list(ctx, domid, usbctrlinfo.devid, &numusb);
> +            usbinfo_print(usbs, numusb);
> +
> +            libxl_usbctrlinfo_dispose(&usbctrlinfo);
> +        }
> +        libxl_device_usbctrl_dispose(&usbctrls[i]);
> +    }
> +
> +    free(usbctrls);
> +    return 0;
> +}
> +
>   int main_console(int argc, char **argv)
>   {
>       uint32_t domid;
> diff --git a/tools/libxl/xl_cmdtable.c b/tools/libxl/xl_cmdtable.c
> index 4b30d3d..b29bc2e 100644
> --- a/tools/libxl/xl_cmdtable.c
> +++ b/tools/libxl/xl_cmdtable.c
> @@ -541,6 +541,36 @@ struct cmd_spec cmd_table[] = {
>         "\"cache_occupancy\":         Show L3 cache occupancy\n",
>       },
>   #endif
> +    { "usb-ctrl-attach",
> +      &main_usbctrl_attach, 1, 1,
> +      "Create a virtual USB controller for a domain",
> +      "<Domain> [version=<version>] [num_ports=<number>]",
> +    },
> +    { "usb-ctrl-detach",
> +      &main_usbctrl_detach, 0, 1,
> +      "Destory the virtual USB controller specified by <DevId> for a domain",

s/Destory/Destroy/

> +      "<Domain> <DevId>",
> +    },
> +    { "usb-attach",
> +      &main_usbattach, 1, 2,
> +      "Attach a USB device to a domain",
> +      "<Domain> <BusId> [controller=<DevId> port=<port>]",
> +    },
> +    { "usb-detach",
> +      &main_usbdetach, 0, 1,
> +      "Detach a USB device from a domain",
> +      "<Domain> <BusId>",
> +    },
> +    { "usb-list",
> +      &main_usblist, 0, 0,
> +      "List information about USB devices for a domain",
> +      "<Domain>",
> +    },
> +    { "usb-assignable-list",
> +      &main_usbassignable_list, 0, 0,
> +      "List all the assignable USB devices",
> +    },
> +
>   };
>
>   int cmdtable_len = sizeof(cmd_table)/sizeof(struct cmd_spec);
>


Juergen

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH RFC V2 3/5] libxl: add pvusb API
  2015-01-19  8:28 ` [PATCH RFC V2 3/5] libxl: add pvusb API Chunyan Liu
  2015-01-28 15:54   ` Ian Campbell
@ 2015-02-10 10:08   ` Jürgen Groß
  2015-02-10 16:01   ` Jürgen Groß
                     ` (3 subsequent siblings)
  5 siblings, 0 replies; 40+ messages in thread
From: Jürgen Groß @ 2015-02-10 10:08 UTC (permalink / raw)
  To: Chunyan Liu, xen-devel
  Cc: george.dunlap, lars.kurth, caobosimon, ian.campbell, ian.jackson

On 01/19/2015 09:28 AM, Chunyan Liu wrote:
> Add pvusb APIs, including:
>   - attach/detach (create/destroy) virtual usb controller.
>   - attach/detach usb device
>   - list assignable usb devices in host
>   - some other helper functions
>
> Signed-off-by: Chunyan Liu <cyliu@suse.com>
> Signed-off-by: Simon Cao <caobosimon@gmail.com>
> ---
>   tools/libxl/Makefile         |    2 +-
>   tools/libxl/libxl.c          |    2 +
>   tools/libxl/libxl.h          |   58 ++
>   tools/libxl/libxl_internal.h |    6 +
>   tools/libxl/libxl_usb.c      | 1277 ++++++++++++++++++++++++++++++++++++++++++
>   tools/libxl/libxlu_cfg_y.c   |  464 ++++++++-------
>   tools/libxl/libxlu_cfg_y.h   |   38 +-
>   7 files changed, 1623 insertions(+), 224 deletions(-)
>   create mode 100644 tools/libxl/libxl_usb.c
>
> diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile
> index b417372..08cdb12 100644
> --- a/tools/libxl/Makefile
> +++ b/tools/libxl/Makefile
> @@ -95,7 +95,7 @@ LIBXL_OBJS = flexarray.o libxl.o libxl_create.o libxl_dm.o libxl_pci.o \
>   			libxl_internal.o libxl_utils.o libxl_uuid.o \
>   			libxl_json.o libxl_aoutils.o libxl_numa.o \
>   			libxl_save_callout.o _libxl_save_msgs_callout.o \
> -			libxl_qmp.o libxl_event.o libxl_fork.o $(LIBXL_OBJS-y)
> +			libxl_qmp.o libxl_event.o libxl_fork.o libxl_usb.o $(LIBXL_OBJS-y)
>   LIBXL_OBJS += libxl_genid.o
>   LIBXL_OBJS += _libxl_types.o libxl_flask.o _libxl_types_internal.o
>
> diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
> index 3cd13db..dd76ac3 100644
> --- a/tools/libxl/libxl.c
> +++ b/tools/libxl/libxl.c
> @@ -1594,6 +1594,8 @@ void libxl__destroy_domid(libxl__egc *egc, libxl__destroy_domid_state *dis)
>
>       if (libxl__device_pci_destroy_all(gc, domid) < 0)
>           LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "pci shutdown failed for domid %d", domid);
> +    if (libxl__device_usb_destroy_all(gc, domid) < 0)
> +         LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "usb shutdown failed for domid %d", domid);
>       rc = xc_domain_pause(ctx->xch, domid);
>       if (rc < 0) {
>           LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc, "xc_domain_pause failed for %d", domid);
> diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
> index 0a123f1..2e89244 100644
> --- a/tools/libxl/libxl.h
> +++ b/tools/libxl/libxl.h
> @@ -98,6 +98,12 @@
>   #define LIBXL_HAVE_DOMAIN_NODEAFFINITY 1
>
>   /*
> + * LIBXL_HAVE_DEVICE_USB indicates the functions for doing hot-plug of
> + * USB devices.
> + */
> +#define LIBXL_HAVE_DEVICE_USB 1
> +
> +/*
>    * LIBXL_HAVE_BUILDINFO_HVM_VENDOR_DEVICE indicates that the
>    * libxl_vendor_device field is present in the hvm sections of
>    * libxl_domain_build_info. This field tells libxl which
> @@ -1168,6 +1174,56 @@ int libxl_cdrom_insert(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *disk,
>                          const libxl_asyncop_how *ao_how)
>                          LIBXL_EXTERNAL_CALLERS_ONLY;
>
> +/* USB Controllers*/
> +int libxl_device_usbctrl_add(libxl_ctx *ctx, uint32_t domid,
> +                         libxl_device_usbctrl *usbctrl,
> +                         const libxl_asyncop_how *ao_how)
> +                         LIBXL_EXTERNAL_CALLERS_ONLY;
> +
> +int libxl_device_usbctrl_remove(libxl_ctx *ctx, uint32_t domid,
> +                         libxl_device_usbctrl *usbctrl,
> +                         const libxl_asyncop_how *ao_how)
> +                         LIBXL_EXTERNAL_CALLERS_ONLY;
> +
> +int libxl_device_usbctrl_destroy(libxl_ctx *ctx, uint32_t domid,
> +                         libxl_device_usbctrl *usbctrl,
> +                         const libxl_asyncop_how *ao_how)
> +                         LIBXL_EXTERNAL_CALLERS_ONLY;
> +
> +libxl_device_usbctrl *libxl_device_usbctrl_list(libxl_ctx *ctx,
> +                            uint32_t domid, int *num);
> +
> +int libxl_devid_to_device_usbctrl(libxl_ctx *ctx, uint32_t domid,
> +                            int devid, libxl_device_usbctrl *usbctrl)
> +                            LIBXL_EXTERNAL_CALLERS_ONLY;
> +
> +int libxl_device_usbctrl_getinfo(libxl_ctx *ctx, uint32_t domid,
> +                                libxl_device_usbctrl *usbctrl,
> +                                libxl_usbctrlinfo *usbctrlinfo)
> +                                LIBXL_EXTERNAL_CALLERS_ONLY;
> +
> +/* USB Devices */
> +int libxl_device_usb_add(libxl_ctx *ctx, uint32_t domid, libxl_device_usb *usb,
> +                         const libxl_asyncop_how *ao_how)
> +                         LIBXL_EXTERNAL_CALLERS_ONLY;
> +
> +int libxl_device_usb_remove(libxl_ctx *ctx, uint32_t domid, libxl_device_usb *usb,
> +                            const libxl_asyncop_how *ao_how)
> +                            LIBXL_EXTERNAL_CALLERS_ONLY;
> +
> +int libxl_device_usb_destroy(libxl_ctx *ctx, uint32_t domid, libxl_device_usb *usb,
> +                            const libxl_asyncop_how *ao_how)
> +                            LIBXL_EXTERNAL_CALLERS_ONLY;
> +
> +libxl_device_usb *libxl_device_usb_list(libxl_ctx *ctx, uint32_t domid,
> +                                        int usbctrl, int *num);
> +
> +int libxl_intf_to_device_usb(libxl_ctx *ctx, uint32_t domid,
> +                            char *intf, libxl_device_usb *usb)
> +                            LIBXL_EXTERNAL_CALLERS_ONLY;
> +
> +int libxl_device_usb_getinfo(libxl_ctx *ctx, char *intf, libxl_usbinfo *usbinfo)
> +                             LIBXL_EXTERNAL_CALLERS_ONLY;
>   /* Network Interfaces */
>   int libxl_device_nic_add(libxl_ctx *ctx, uint32_t domid, libxl_device_nic *nic,
>                            const libxl_asyncop_how *ao_how)
> @@ -1294,6 +1350,8 @@ int libxl_device_pci_assignable_add(libxl_ctx *ctx, libxl_device_pci *pcidev, in
>   int libxl_device_pci_assignable_remove(libxl_ctx *ctx, libxl_device_pci *pcidev, int rebind);
>   libxl_device_pci *libxl_device_pci_assignable_list(libxl_ctx *ctx, int *num);
>
> +libxl_device_usb *libxl_device_usb_assignable_list(libxl_ctx *ctx, int *num);
> +
>   /* CPUID handling */
>   int libxl_cpuid_parse_config(libxl_cpuid_policy_list *cpuid, const char* str);
>   int libxl_cpuid_parse_config_xend(libxl_cpuid_policy_list *cpuid,
> diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
> index bcf43fb..dba1326 100644
> --- a/tools/libxl/libxl_internal.h
> +++ b/tools/libxl/libxl_internal.h
> @@ -2395,6 +2395,11 @@ _hidden void libxl__device_vtpm_add(libxl__egc *egc, uint32_t domid,
>                                      libxl_device_vtpm *vtpm,
>                                      libxl__ao_device *aodev);
>
> +/* from libxl_usb */
> +_hidden int libxl__device_usb_add(libxl__gc *gc, uint32_t domid,
> +                            libxl_device_usb *usb);
> +_hidden int libxl__device_usb_destroy_all(libxl__gc *gc, uint32_t domid);
> +
>   /* Internal function to connect a vkb device */
>   _hidden int libxl__device_vkb_add(libxl__gc *gc, uint32_t domid,
>                                     libxl_device_vkb *vkb);
> @@ -3574,6 +3579,7 @@ static inline void libxl__update_config_vtpm(libxl__gc *gc,
>   #define COMPARE_PCI(a, b) ((a)->func == (b)->func &&    \
>                              (a)->bus == (b)->bus &&      \
>                              (a)->dev == (b)->dev)
> +#define COMPARE_USB(a, b) (!strcmp((a)->intf, (b)->intf))
>
>   /* DEVICE_ADD
>    *
> diff --git a/tools/libxl/libxl_usb.c b/tools/libxl/libxl_usb.c
> new file mode 100644
> index 0000000..830a846
> --- /dev/null
> +++ b/tools/libxl/libxl_usb.c
> @@ -0,0 +1,1277 @@
> +/*
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU Lesser General Public License as published
> + * by the Free Software Foundation; version 2.1 only. with the special
> + * exception on linking described in file LICENSE.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU Lesser General Public License for more details.
> + */
> +
> +#include "libxl_osdeps.h" /* must come before any other headers */
> +
> +#include "libxl_internal.h"
> +
> +#define SYSFS_USB_DEVS_PATH "/sys/bus/usb/devices"
> +#define SYSFS_USBBACK_DRIVER "/sys/bus/usb/drivers/usbback"
> +#define USBBACK_INFO_PATH "/libxl/usbback"
> +
> +#define USBHUB_CLASS_CODE "09"
> +
> +static int libxl__device_usbctrl_setdefault(libxl__gc *gc, uint32_t domid,
> +                                            libxl_device_usbctrl *usbctrl)
> +{
> +    int rc;
> +
> +    if (!usbctrl->usb_version)
> +        usbctrl->usb_version = 2;
> +
> +    if (!usbctrl->num_ports)
> +        usbctrl->num_ports = 8;
> +
> +    if(!usbctrl->backend_domid)
> +        usbctrl->backend_domid = 0;

Just use a comment?

> +
> +    if (!usbctrl->type)
> +        usbctrl->type = LIBXL_USBCTRL_TYPE_PV;
> +
> +    rc = libxl__resolve_domid(gc, usbctrl->backend_domname,
> +                              &usbctrl->backend_domid);
> +
> +    return rc;
> +}
> +
> +static int libxl__device_from_usbctrl(libxl__gc *gc, uint32_t domid,
> +                                      libxl_device_usbctrl *usbctrl,
> +                                      libxl__device *device)

Make function type void?

> +{
> +    device->backend_devid   = usbctrl->devid;
> +    device->backend_domid   = usbctrl->backend_domid;
> +    device->backend_kind    = LIBXL__DEVICE_KIND_VUSB;
> +    device->devid           = usbctrl->devid;
> +    device->domid           = domid;
> +    device->kind            = LIBXL__DEVICE_KIND_VUSB;
> +
> +    return 0;
> +}
> +
> +static int libxl__usbport_add_xenstore(libxl__gc *gc,
> +                                       xs_transaction_t tran,
> +                                       uint32_t domid,
> +                                       libxl_device_usbctrl *usbctrl)
> +{
> +    char *path;
> +    int i;
> +
> +    path = GCSPRINTF("%s/backend/vusb/%d/%d/port",
> +                     libxl__xs_get_dompath(gc, 0), domid, usbctrl->devid);
> +
> +    libxl__xs_mkdir(gc, tran, path, NULL, 0);
> +
> +    for (i = 1; i <= usbctrl->num_ports; i++) {
> +        if (libxl__xs_write_checked(gc, tran, GCSPRINTF("%s/%d", path, i), ""))
> +            return ERROR_FAIL;
> +    }
> +
> +    return 0;
> +}
> +
> +static int libxl__usbctrl_add_xenstore(libxl__gc *gc, uint32_t domid,
> +                                       libxl_device_usbctrl *usbctrl)
> +{
> +    libxl_ctx *ctx = libxl__gc_owner(gc);
> +    flexarray_t *front;
> +    flexarray_t *back;
> +    libxl__device *device;
> +    xs_transaction_t tran;
> +    int rc = 0;
> +
> +    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(back, "frontend-id");
> +    flexarray_append(back, libxl__sprintf(gc, "%d", domid));
> +    flexarray_append(back, "online");
> +    flexarray_append(back, "1");
> +    flexarray_append(back, "state");
> +    flexarray_append(back, libxl__sprintf(gc, "%d", 1));
> +    flexarray_append(back, "usb-ver");
> +    flexarray_append(back, libxl__sprintf(gc, "%d", usbctrl->usb_version));
> +    flexarray_append(back, "num-ports");
> +    flexarray_append(back, libxl__sprintf(gc, "%d", usbctrl->num_ports));
> +    flexarray_append(back, "type");
> +    switch(usbctrl->type) {
> +    case LIBXL_USBCTRL_TYPE_PV:{
> +        flexarray_append(back, "PVUSB");
> +        break;
> +    }
> +    case LIBXL_USBCTRL_TYPE_DEVICEMODEL: {
> +        flexarray_append(back, "IOEMU");
> +        break;
> +    }
> +    default:
> +        /* not supported */
> +        rc = ERROR_FAIL;
> +        goto out;
> +    }
> +
> +    flexarray_append(front, "backend-id");
> +    flexarray_append(front, libxl__sprintf(gc, "%d", usbctrl->backend_domid));
> +    flexarray_append(front, "state");
> +    flexarray_append(front, libxl__sprintf(gc, "%d", 1));
> +
> +retry_transaction:
> +    tran = xs_transaction_start(ctx->xsh);
> +
> +    libxl__device_generic_add(gc, tran, device,
> +                              libxl__xs_kvs_of_flexarray(gc, back, back->count),
> +                              libxl__xs_kvs_of_flexarray(gc, front, front->count),
> +                              NULL);
> +    libxl__usbport_add_xenstore(gc, tran, domid, usbctrl);

No check of rc?

> +
> +    if (!xs_transaction_end(ctx->xsh, tran, 0)) {
> +        if (errno == EAGAIN)
> +            goto retry_transaction;
> +        else {
> +            rc = ERROR_FAIL;
> +            goto out;
> +        }
> +    }
> +
> +out:
> +    return rc;
> +}
> +
> +static int libxl__device_usbctrl_add(libxl__gc *gc, uint32_t domid,
> +                                     libxl_device_usbctrl *usbctrl)
> +{
> +    int rc = 0;
> +
> +    rc = libxl__device_usbctrl_setdefault(gc, domid, usbctrl);
> +    if(rc) goto out;

Coding style.

> +
> +    if (usbctrl->devid == -1) {
> +        if ((usbctrl->devid = libxl__device_nextid(gc, domid, "vusb")) < 0) {

Combine above 2 ifs in one?

> +            rc = ERROR_FAIL;
> +            goto out;
> +        }
> +    }
> +
> +    if (libxl__usbctrl_add_xenstore(gc, domid, usbctrl) < 0){
> +        rc = ERROR_FAIL;
> +        goto out;
> +    }
> +
> +out:
> +    return rc;
> +}
> +
> +int libxl_device_usbctrl_add(libxl_ctx *ctx, uint32_t domid,
> +                             libxl_device_usbctrl *usbctrl,
> +                             const libxl_asyncop_how *ao_how)
> +{
> +    AO_CREATE(ctx, domid, ao_how);
> +    int rc;
> +
> +    rc = libxl__device_usbctrl_add(gc, domid, usbctrl);
> +    libxl__ao_complete(egc, ao, rc);
> +    return AO_INPROGRESS;
> +}
> +
> +libxl_device_usbctrl *
> +libxl_device_usbctrl_list(libxl_ctx *ctx, uint32_t domid, int *num)
> +{
> +    GC_INIT(ctx);
> +
> +    libxl_device_usbctrl *usbctrls = NULL;
> +    char *fe_path = NULL;
> +    char **dir = NULL;
> +    unsigned int ndirs = 0;
> +
> +    *num = 0;
> +
> +    fe_path = libxl__sprintf(gc, "%s/device/vusb",
> +                             libxl__xs_get_dompath(gc, domid));
> +    dir = libxl__xs_directory(gc, XBT_NULL, fe_path, &ndirs);
> +
> +    if (dir && ndirs) {
> +        usbctrls = malloc(sizeof(*usbctrls) * ndirs);
> +        libxl_device_usbctrl* usbctrl;
> +        libxl_device_usbctrl* end = usbctrls + ndirs;
> +        for(usbctrl = usbctrls; usbctrl < end; usbctrl++, dir++, (*num)++) {

Coding style.

Why (*num)++? *num is set at end of loop.

> +            char *tmp;
> +            const char *be_path = libxl__xs_read(gc, XBT_NULL,
> +                                    GCSPRINTF("%s/%s/backend", fe_path, *dir));
> +
> +            libxl_device_usbctrl_init(usbctrl);
> +
> +            usbctrl->devid = atoi(*dir);
> +
> +            tmp = libxl__xs_read(gc, XBT_NULL,
> +                                 GCSPRINTF("%s/%s/backend-id", fe_path, *dir));
> +            if (!tmp) goto outerr;
> +            usbctrl->backend_domid = atoi(tmp);
> +
> +            tmp = libxl__xs_read(gc, XBT_NULL,
> +                                 GCSPRINTF("%s/usb-ver", be_path));
> +            if (!tmp) goto outerr;
> +            usbctrl->usb_version = atoi(tmp);
> +
> +            tmp = libxl__xs_read(gc, XBT_NULL,
> +                                 GCSPRINTF("%s/num-ports", be_path));
> +            if (!tmp) goto outerr;
> +            usbctrl->num_ports = atoi(tmp);
> +       }
> +    }
> +    *num = ndirs;
> +
> +    return usbctrls;
> +
> +outerr:
> +    LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "Unable to list USB Controllers");
> +    for (int i = 0; i < *num; i++) {
> +        libxl_device_usbctrl_dispose(usbctrls + i);
> +    }
> +    free(usbctrls);
> +    *num = 0;
> +    return NULL;
> +}
> +
> +static int libxl__device_usb_list(libxl__gc *gc, uint32_t domid, int usbctrl,
> +                                  libxl_device_usb **usbs, int *num);
> +
> +static int libxl__device_usb_remove_common(libxl__gc *gc, uint32_t domid,
> +                                libxl_device_usb *usb, int force);
> +
> +static int
> +libxl__device_usbctrl_remove_common(libxl_ctx *ctx, uint32_t domid,
> +                                    libxl_device_usbctrl *usbctrl,
> +                                    const libxl_asyncop_how *ao_how,
> +                                    int force)
> +{
> +    AO_CREATE(ctx, domid, ao_how);
> +    libxl__device *device;
> +    libxl__ao_device *aodev;
> +    libxl_device_usb *usbs = NULL;
> +    int numusb = 0;
> +    int i, rc;
> +
> +    GCNEW(device);
> +    rc = libxl__device_from_usbctrl(gc, domid, usbctrl, device);
> +    if(rc) goto out;

Coding style, but rc check can be probably removed.

> +
> +    /* Remove usb devives first */
> +    rc  = libxl__device_usb_list(gc, domid, usbctrl->devid, &usbs, &numusb);

Coding style.

> +    if (rc) goto out;
> +    for (i = 0; i < numusb; i++) {
> +        if (libxl__device_usb_remove_common(gc, domid, &usbs[i], 0)) {
> +            fprintf(stderr, "libxl_device_usb_remove failed.\n");
> +            return -1;
> +        }
> +    }
> +    /* remove usbctrl */
> +    GCNEW(aodev);
> +    libxl__prepare_ao_device(ao, aodev);
> +    aodev->action = LIBXL__DEVICE_ACTION_REMOVE;
> +    aodev->dev = device;
> +    aodev->callback = device_addrm_aocomplete;
> +    aodev->force = force;
> +    libxl__initiate_device_remove(egc, aodev);
> +
> +out:
> +    if(rc) return AO_ABORT(rc);

Coding style.

> +    return AO_INPROGRESS;
> +}
> +
> +int libxl_device_usbctrl_remove(libxl_ctx *ctx, uint32_t domid,
> +                                libxl_device_usbctrl *usbctrl,
> +                                const libxl_asyncop_how *ao_how)
> +{
> +    return libxl__device_usbctrl_remove_common(ctx, domid, usbctrl, ao_how, 0);
> +}
> +
> +int libxl_device_usbctrl_destroy(libxl_ctx *ctx, uint32_t domid,
> +                                 libxl_device_usbctrl *usbctrl,
> +                                 const libxl_asyncop_how *ao_how)
> +{
> +    return libxl__device_usbctrl_remove_common(ctx, domid, usbctrl, ao_how, 1);
> +}
> +
> +int libxl_device_usbctrl_getinfo(libxl_ctx *ctx, uint32_t domid,
> +                                libxl_device_usbctrl *usbctrl,
> +                                libxl_usbctrlinfo *usbctrlinfo)
> +{
> +    GC_INIT(ctx);
> +    char *dompath, *usbctrlpath;
> +    char *val;
> +    int rc = 0;
> +
> +    dompath = libxl__xs_get_dompath(gc, domid);
> +    usbctrlinfo->devid = usbctrl->devid;
> +    usbctrlinfo->num_ports = usbctrl->num_ports;
> +    usbctrlinfo->version = usbctrl->usb_version;
> +
> +    usbctrlpath = libxl__sprintf(gc, "%s/device/vusb/%d", dompath, usbctrlinfo->devid);
> +    usbctrlinfo->backend = libxl__xs_read(gc, XBT_NULL,
> +                                libxl__sprintf(gc, "%s/backend", usbctrlpath));
> +    if (!usbctrlinfo->backend) {
> +        rc = ERROR_FAIL;
> +        goto out;
> +    }
> +
> +    val = libxl__xs_read(gc, XBT_NULL,
> +                         GCSPRINTF("%s/backend-id", usbctrlpath));
> +    usbctrlinfo->backend_id = val ? strtoul(val, NULL, 10) : -1;
> +
> +    val = libxl__xs_read(gc, XBT_NULL,
> +                         GCSPRINTF("%s/state", usbctrlpath));
> +    usbctrlinfo->state = val ? strtoul(val, NULL, 10) : -1;
> +
> +    val = libxl__xs_read(gc, XBT_NULL,
> +                         GCSPRINTF("%s/event-channel", usbctrlpath));
> +    usbctrlinfo->evtch = val ? strtoul(val, NULL, 10) : -1;
> +
> +    val = libxl__xs_read(gc, XBT_NULL,
> +                         GCSPRINTF("%s/urb-ring-ref", usbctrlpath));
> +    usbctrlinfo->ref_urb = val ? strtoul(val, NULL, 10) : -1;
> +
> +    val = libxl__xs_read(gc, XBT_NULL,
> +                         GCSPRINTF("%s/conn-ring-ref", usbctrlpath));
> +    usbctrlinfo->ref_conn= val ? strtoul(val, NULL, 10) : -1;
> +
> +    usbctrlinfo->type = libxl__xs_read(gc, XBT_NULL,
> +                                GCSPRINTF("%s/type", usbctrlinfo->backend));
> +
> +    usbctrlinfo->frontend = libxl__xs_read(gc, XBT_NULL,
> +                                GCSPRINTF("%s/frontend", usbctrlinfo->backend));
> +
> +    val = libxl__xs_read(gc, XBT_NULL,
> +                         GCSPRINTF("%s/frontend-id", usbctrlinfo->backend));
> +    usbctrlinfo->frontend_id = val ? strtoul(val, NULL, 10) : -1;
> +
> +out:
> +    GC_FREE;
> +    return rc;
> +}
> +
> +int libxl_devid_to_device_usbctrl(libxl_ctx *ctx, uint32_t domid,
> +                                  int devid, libxl_device_usbctrl *usbctrl)
> +{
> +    GC_INIT(ctx);
> +    char* fe_path = NULL, *be_path = NULL, *tmp;
> +    int rc = 0;
> +
> +    libxl_device_usbctrl_init(usbctrl);
> +    usbctrl->devid = devid;
> +
> +    fe_path = libxl__sprintf(gc, "%s/device/vusb",
> +                             libxl__xs_get_dompath(gc, domid));
> +    be_path = libxl__xs_read(gc, XBT_NULL,
> +                             GCSPRINTF("%s/%d/backend", fe_path, devid));
> +
> +    tmp = libxl__xs_read(gc, XBT_NULL,
> +                         GCSPRINTF("%s/%d/backend-id", fe_path, devid));
> +    if (!tmp) {
> +        rc = ERROR_FAIL;
> +        goto out;
> +    }
> +    usbctrl->backend_domid = atoi(tmp);
> +
> +    tmp = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/usb-ver", be_path));
> +    usbctrl->usb_version = atoi(tmp);
> +
> +    tmp = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/num-ports", be_path));
> +    usbctrl->num_ports = atoi(tmp);
> +
> +out:
> +    GC_FREE;
> +    return rc;
> +}
> +
> +/* usb device functions */
> +
> +/* Following functions are to get assignable usb devices */
> +static int
> +libxl__device_usb_assigned_list(libxl__gc *gc,
> +                                libxl_device_usb **list, int *num)
> +{
> +    char **domlist;
> +    unsigned int nd = 0, i, j;
> +    char *be_path;
> +    libxl_device_usb *usb;
> +
> +    *list = NULL;
> +    *num = 0;
> +
> +    domlist = libxl__xs_directory(gc, XBT_NULL, "/local/domain", &nd);
> +    be_path = libxl__sprintf(gc,"/local/domain/0/backend/vusb");
> +    for (i = 0; i < nd; i++) {
> +        char *path, *num_ports, **ctrl_list;
> +        unsigned int nc = 0;
> +        path = libxl__sprintf(gc, "%s/%s", be_path, domlist[i]);
> +        ctrl_list = libxl__xs_directory(gc, XBT_NULL, path , &nc);
> +
> +        for (j = 0; j < nc; j++) {
> +            path = libxl__sprintf(gc, "%s/%s/%s/num-ports", be_path,
> +                                  domlist[i], ctrl_list[j]);
> +            num_ports = libxl__xs_read(gc, XBT_NULL, path);
> +            if ( num_ports ) {
> +                int nport = atoi(num_ports), k;
> +                char *devpath, *intf;
> +
> +                for (k = 1; k <= nport; k++) {
> +                    devpath = libxl__sprintf(gc, "%s/%s/%s/port/%u", be_path,
> +                                             domlist[i], ctrl_list[j], k);
> +                    intf = libxl__xs_read(gc, XBT_NULL, devpath);
> +                    /* If there are USB device attached, add it to list */
> +                    if (intf && strcmp(intf, "") ) {
> +                        *list = realloc(*list,
> +                                  sizeof(libxl_device_usb) * ((*num) + 1));
> +                        if (*list == NULL)
> +                            return ERROR_NOMEM;
> +                        usb = *list + *num;
> +                        usb->ctrl = atoi(ctrl_list[j]);
> +                        usb->port = k;
> +                        usb->intf = strdup(intf);
> +                        (*num)++;
> +                    }
> +                }
> +            }
> +        }
> +    }
> +    libxl__ptr_add(gc, *list);
> +
> +    return 0;
> +}
> +
> +static bool is_usb_in_array(libxl_device_usb *usbs, int num, char *intf)
> +{
> +    int i;
> +
> +    for (i = 0; i < num; i++) {
> +        if (!strcmp(usbs[i].intf, intf) )
> +            return true;
> +    }
> +
> +    return false;
> +}
> +
> +static int get_usb_bDeviceClass(libxl__gc *gc, char *intf, char *buf)
> +{
> +    char *path;
> +    FILE *fd;

Naming a FILE pointer fd isn't very common. I always think "int" when
I see a file related variable named "fd". Perhaps "fp"?

+3333333333333 (might look strange, but my cat wanted this comment to
go in).

> +    int rc;
> +
> +    path = libxl__sprintf(gc, SYSFS_USB_DEVS_PATH"/%s/bDeviceClass", intf);
> +
> +    /* Check if this path exist, if not return -1 */
> +    if (access(path, R_OK) )
> +        return -1;
> +
> +    fd = popen(GCSPRINTF("cat %s", path), "r");

Why can't you just read from sysfs? Using a pipe here seems overkill.

> +    rc = fscanf(fd, "%s", buf);

Is buf always large enough?

> +    pclose(fd);
> +
> +    return (rc > 0) ? 0 : -1;
> +}
> +
> +static bool is_usb_assignable(libxl__gc *gc, char *intf)
> +{
> +    char buf[5];
> +
> +    if (get_usb_bDeviceClass(gc, intf, buf) < 0)
> +        return false;
> +
> +    if (strcmp(buf, USBHUB_CLASS_CODE))
> +        return false;
> +
> +    return true;
> +}
> +
> +libxl_device_usb *
> +libxl_device_usb_assignable_list(libxl_ctx *ctx, int *num)
> +{
> +    GC_INIT(ctx);
> +    libxl_device_usb *usbs = NULL;
> +    libxl_device_usb *assigned;
> +    int num_assigned;
> +    struct dirent *de;
> +    DIR *dir;
> +
> +    *num = 0;
> +
> +    if (libxl__device_usb_assigned_list(gc, &assigned, &num_assigned) < 0)
> +        goto out;
> +
> +    if (!(dir = opendir(SYSFS_USB_DEVS_PATH)))
> +        goto out;
> +
> +    while((de = readdir(dir))) {
> +        if (!de->d_name)
> +            continue;

Check for entry type?

Exclude ".", ".."?

> +
> +        if(is_usb_assignable(gc, de->d_name))

!is_usb_assignable?

Coding style. There are lots of other style errors more, especially
regarding if statements.

> +            continue;
> +
> +        if (is_usb_in_array(assigned, num_assigned, de->d_name))
> +            continue;
> +
> +        usbs = realloc(usbs, sizeof(*usbs)*((*num) + 1));
> +        usbs[*num].intf = strdup(de->d_name);
> +        (*num)++;
> +    }
> +
> +    closedir(dir);
> +
> +out:
> +    GC_FREE;
> +    return usbs;
> +}
> +
> +/* get usb devices under certain usb controller */
> +static int libxl__device_usb_list(libxl__gc *gc, uint32_t domid, int usbctrl,
> +                                  libxl_device_usb **usbs, int *num)
> +{
> +    char *be_path, *num_devs;
> +    int n, i;
> +    libxl_device_usb *usb = NULL;
> +
> +    usbs = NULL;
> +    *num = 0;
> +
> +    be_path = libxl__sprintf(gc, "%s/backend/vusb/%d/%d",
> +                             libxl__xs_get_dompath(gc, 0), domid, usbctrl);
> +    num_devs = libxl__xs_read(gc, XBT_NULL,
> +                              libxl__sprintf(gc, "%s/num-ports", be_path));
> +    if (!num_devs)
> +        return 0;
> +
> +    n = atoi(num_devs);
> +    usb = calloc(n, sizeof(libxl_device_usb));
> +    usbs = &usb;
> +
> +    for (i = 0; i < n; i++) {
> +        char *intf;
> +        intf = libxl__xs_read(gc, XBT_NULL,
> +                              libxl__sprintf(gc,"%s/port/%d", be_path, i + 1));
> +        if (intf && strcmp(intf, "") ) {
> +            usbs[i]->ctrl = usbctrl;
> +            usbs[i]->port = i + 1;
> +            usbs[i]->intf = strdup(intf);
> +            (*num)++;
> +        }
> +    }
> +
> +    return 0;
> +}
> +
> +libxl_device_usb *libxl_device_usb_list(libxl_ctx *ctx, uint32_t domid,
> +                                        int usbctrl, int *num)
> +{
> +    GC_INIT(ctx);
> +    libxl_device_usb *usbs = NULL;
> +
> +    libxl__device_usb_list(gc, domid, usbctrl, &usbs, num);
> +
> +    GC_FREE;
> +    return usbs;
> +}
> +
> +/* get all usb devices of the domain */
> +static libxl_device_usb *
> +libxl_device_usb_list_all(libxl__gc *gc, uint32_t domid, int *num)
> +{
> +    char **usbctrls;
> +    unsigned int nd, i, j;
> +    char *be_path;
> +    int rc;
> +    libxl_device_usb *usbs = NULL;
> +
> +    *num = 0;
> +
> +    be_path = GCSPRINTF("/local/domain/0/backend/vusb/%d", domid);
> +    usbctrls = libxl__xs_directory(gc, XBT_NULL, be_path, &nd);
> +
> +    for (i = 0; i < nd; i++) {
> +        int nc = 0;
> +        libxl_device_usb *tmp = NULL;
> +        rc = libxl__device_usb_list(gc, domid, atoi(usbctrls[i]), &tmp, &nc);
> +        if (!nc) continue;
> +
> +        usbs = realloc(usbs, sizeof(libxl_device_usb)*((*num) + nc));
> +        for(j = 0; j < nc; j++) {
> +            usbs[*num].ctrl = tmp[j].ctrl;
> +            usbs[*num].port = tmp[j].port;
> +            usbs[*num].intf = strdup(tmp[j].intf);
> +            (*num)++;
> +        }
> +        free(tmp);
> +    }
> +    return usbs;
> +}
> +
> +/* set default value */
> +
> +/* find first unused controller:port and give that to usb device */
> +static int
> +libxl__device_usb_set_default_usbctrl(libxl__gc *gc, uint32_t domid,
> +                                      libxl_device_usb *usb)
> +{
> +    libxl_ctx *ctx = CTX;
> +    libxl_device_usbctrl *usbctrls;
> +    libxl_device_usb *usbs = NULL;
> +    int numctrl, numusb, i, j, rc = -1;
> +    char *be_path, *tmp;
> +
> +    usbctrls = libxl_device_usbctrl_list(ctx, domid, &numctrl);
> +    if ( !numctrl)
> +        goto out;
> +
> +    for (i = 0; i < numctrl; i++) {
> +        rc = libxl__device_usb_list(gc, domid, usbctrls[i].devid,
> +                                    &usbs, &numusb);
> +        if (rc) continue;
> +
> +        if (!usbctrls[i].num_ports || numusb == usbctrls[i].num_ports)
> +            continue;
> +
> +        for (j = 1; i <= numusb; j++) {
> +            be_path = libxl__sprintf(gc, "%s/backend/vusb/%d/%d/port/%d",
> +                                     libxl__xs_get_dompath(gc, 0), domid,
> +                                     usbctrls[i].devid, j);
> +            tmp = libxl__xs_read(gc, XBT_NULL, be_path);
> +            if (tmp && !strcmp( tmp, "")) {
> +                usb->ctrl = usbctrls[i].devid;
> +                usb->port = j;
> +                break;
> +            }
> +        }
> +    }
> +
> +    rc = 0;
> +
> +out:
> +    if (usbctrls)
> +        free(usbctrls);
> +    if (usbs)
> +        free(usbs);
> +    return rc;
> +}
> +
> +static int libxl__device_usb_setdefault(libxl__gc *gc, uint32_t domid,
> +                                        libxl_device_usb *usb)
> +{
> +    char *be_path, *tmp;
> +
> +    if (usb->ctrl == -1) {
> +        int ret = libxl__device_usb_set_default_usbctrl(gc, domid, usb);
> +        /* If no existing ctrl to host this usb device, setup a new one */
> +        if (ret) {
> +            libxl_device_usbctrl usbctrl;
> +            libxl_device_usbctrl_init(&usbctrl);
> +            libxl__device_usbctrl_add(gc, domid, &usbctrl);
> +            usb->ctrl = usbctrl.devid;
> +            usb->port = 1;
> +            libxl_device_usbctrl_dispose(&usbctrl);
> +        }
> +    }
> +
> +    be_path = libxl__sprintf(gc, "%s/backend/vusb/%d/path/%d",
> +                    libxl__xs_get_dompath(gc, 0), usb->ctrl, usb->port);
> +    tmp = libxl__xs_read(gc, XBT_NULL, be_path);
> +    if (!tmp || strcmp(tmp, "") ){
> +        LOG(ERROR, "The controller port isn't available.");
> +        return ERROR_INVAL;
> +    }
> +
> +    return 0;
> +}
> +
> +/* xenstore usb data */
> +static int libxl__device_usb_add_xenstore(libxl__gc *gc, uint32_t domid,
> +                                          libxl_device_usb *usb)
> +{
> +    libxl_ctx *ctx = CTX;
> +    char *be_path;
> +    int rc;
> +    libxl_domain_config d_config;
> +    libxl_device_usb usb_saved;
> +    libxl__domain_userdata_lock *lock = NULL;
> +
> +    libxl_domain_config_init(&d_config);
> +    libxl_device_usb_init(&usb_saved);
> +    libxl_device_usb_copy(CTX, &usb_saved, usb);
> +
> +    be_path = libxl__sprintf(gc, "%s/backend/vusb/%d/%d",
> +                        libxl__xs_get_dompath(gc, 0), domid, usb->ctrl);
> +    if (libxl__wait_for_backend(gc, be_path, "4") < 0) {
> +        rc = ERROR_FAIL;
> +        goto out;
> +    }
> +
> +    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(usb, usbs, domid, &usb_saved, COMPARE_USB, &d_config);
> +
> +    rc = libxl__set_domain_configuration(gc, domid, &d_config);
> +    if (rc) goto out;
> +
> +    be_path = libxl__sprintf(gc, "%s/port/%d", be_path, usb->port);
> +    LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, "Adding new usb device to xenstore");
> +    if (libxl__xs_write_checked(gc, XBT_NULL, be_path, usb->intf)) {
> +        rc = ERROR_FAIL;
> +        goto out;
> +    }
> +
> +    rc = 0;
> +
> +out:
> +    if (lock) libxl__unlock_domain_userdata(lock);
> +    libxl_device_usb_dispose(&usb_saved);
> +    libxl_domain_config_dispose(&d_config);
> +    return rc;
> +
> +}
> +
> +static int libxl__device_usb_remove_xenstore(libxl__gc *gc, uint32_t domid,
> +                                             libxl_device_usb *usb)
> +{
> +    libxl_ctx *ctx = CTX;
> +    char *be_path;
> +
> +    be_path = libxl__sprintf(gc, "%s/backend/vusb/%d/%d",
> +                        libxl__xs_get_dompath(gc, 0), domid, usb->ctrl);
> +    if (libxl__wait_for_backend(gc, be_path, "4") < 0)
> +        return ERROR_FAIL;
> +
> +    be_path = libxl__sprintf(gc, "%s/port/%d", be_path, usb->port);
> +    LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, "Removing USB device from xenstore");
> +    if (libxl__xs_write_checked(gc,XBT_NULL, be_path, ""))
> +        return ERROR_FAIL;
> +
> +    return 0;
> +}
> +
> +/* bind/unbind usb device interface */
> +static int unbind_usb_intf(libxl__gc *gc, char *intf, char *drvpath)
> +{
> +    char *path;
> +    int fd, rc = 0;
> +
> +    drvpath = GCSPRINTF(SYSFS_USB_DEVS_PATH"/%s/driver", intf);
> +
> +    /* if not bound to a driver, return directly */
> +    if (!drvpath)
> +        return 0;
> +
> +    /* else, unbind from driver */
> +    path = GCSPRINTF("%s/unbind", drvpath);
> +    fd = open(path, O_WRONLY);
> +    if (fd < 0) {
> +        rc = ERROR_FAIL;
> +        goto out;
> +    }
> +    if (write(fd, intf, strlen(intf)) < 0) {
> +        rc = ERROR_FAIL;
> +        goto out;
> +    }
> +    close(fd);
> +
> +out:
> +    return rc;
> +}
> +
> +static int bind_usb_intf(libxl__gc *gc, char *intf, char *drvpath)
> +{
> +    char *path;
> +    int fd, rc = 0;
> +
> +    path = GCSPRINTF("%s/bind", drvpath);
> +    fd = open(path, O_WRONLY);
> +    if (fd < 0) {
> +        rc = ERROR_FAIL;
> +        goto out;
> +    }
> +    if (write(fd, intf, strlen(intf)) < 0) {
> +        rc = ERROR_FAIL;
> +        goto out;
> +    }
> +    close(fd);
> +
> +out:
> +    return rc;
> +}
> +
> +static int usb_get_all_interfaces(libxl__gc *gc, libxl_device_usb *usb,
> +                                  char **intfs, int *num)
> +{
> +    DIR *dir;
> +    struct dirent *entry;
> +    char *buf;
> +    int rc = 0;
> +
> +    intfs = NULL;
> +    *num = 0;
> +
> +    buf = GCSPRINTF("%s:", usb->intf);
> +
> +    if (!(dir = opendir(SYSFS_USB_DEVS_PATH))) {
> +        rc = ERROR_FAIL;
> +        goto out;
> +    }
> +
> +    while ((entry = readdir(dir)) != NULL) {
> +        if (!strncmp(entry->d_name, buf, strlen(buf))){
> +            intfs = realloc(intfs, sizeof(char *) * (*num + 1));
> +            if (!intfs) {
> +                rc = ERROR_FAIL;
> +                goto out;
> +            }
> +            intfs[*num] = strdup(entry->d_name);
> +            (*num)++;
> +        }
> +    }
> +
> +    closedir(dir);
> +
> +out:
> +    return rc;
> +}
> +
> +/* unbind usb device from usbback driver, if there are many interfaces
> + * under the usb device, then check each interface, unbind from usbback
> + * driver and rebind to original driver
> + */
> +static int unbind_usb_device_from_usbback(libxl__gc *gc, libxl_device_usb *usb)
> +{
> +    char **intfs = NULL;
> +    char *path;
> +    int num = 0, i;
> +    int rc = 0;
> +
> +    if (usb_get_all_interfaces(gc, usb, intfs, &num) < 0)
> +        return ERROR_FAIL;
> +
> +    for (i = 0; i < num; i++){
> +        char *intf = intfs[i];
> +        char *drvpath = NULL;
> +        char *tmp = NULL;
> +
> +        drvpath = GCSPRINTF(SYSFS_USB_DEVS_PATH"/%s/driver", intf);
> +        if (!drvpath || strcmp(drvpath, SYSFS_USBBACK_DRIVER))
> +            continue;
> +
> +        /* unbind interface from usbback driver */
> +        if (unbind_usb_intf(gc, intf, NULL) < 0) {
> +            rc = ERROR_FAIL;
> +            goto out;
> +        }
> +
> +        /* bind interface to its originial driver */
> +        tmp = libxl__xs_read(gc, XBT_NULL,
> +                  GCSPRINTF(USBBACK_INFO_PATH"/%s/%s/driver_path",
> +                  usb->intf, intf));
> +        if (tmp) {
> +            if (bind_usb_intf(gc, intf, GCSPRINTF("%s/bind", tmp)) < 0) {
> +                free(tmp);
> +                rc = ERROR_FAIL;
> +                goto out;
> +            }
> +            free(tmp);
> +        }
> +    }
> +
> +    /* finally, remove xs driver path */
> +    path = GCSPRINTF(USBBACK_INFO_PATH"/%s", usb->intf);
> +    if (libxl__xs_rm_checked(gc, XBT_NULL, path) < 0)
> +        rc = ERROR_FAIL;
> +
> +out:
> +    if (intfs) {
> +        for (i = 0; i < num; i++)
> +            free(intfs[i]);
> +        free(intfs);
> +    }
> +    return rc;
> +}
> +
> +/* bind usb device to "usbback" driver, if there are many interfaces
> + * under the usb device, check each interface, unbind from original
> + * driver and bind to usbback driver.
> + */
> +static int bind_usb_device_to_usbback(libxl__gc *gc, libxl_device_usb *usb)
> +{
> +    char **intfs = NULL;
> +    int num = 0, i;
> +    int rc = 0;
> +
> +    if (usb_get_all_interfaces(gc, usb, intfs, &num) < 0)
> +        return ERROR_FAIL;
> +
> +    for (i = 0; i < num; i++){
> +        char *intf = intfs[i];
> +        char *path = NULL;
> +        char *drvpath = NULL;
> +
> +        /* unbind interface from original driver */
> +        if (unbind_usb_intf(gc, intf, drvpath) < 0) {
> +            rc = ERROR_FAIL;
> +            goto out_rebind;
> +        }
> +
> +        if (drvpath) {
> +            /* write driver path to xenstore for later rebinding */
> +            path = GCSPRINTF(USBBACK_INFO_PATH"/%s/%s/driver_path",
> +                             usb->intf, intf);
> +            if (libxl__xs_write_checked(gc, XBT_NULL, path, drvpath) < 0) {
> +                rc = ERROR_FAIL;
> +                goto out_rebind;
> +            }
> +        }
> +
> +        /* bind interface to usbback */
> +        if (bind_usb_intf(gc, intf, SYSFS_USBBACK_DRIVER) < 0){
> +            rc = ERROR_FAIL;
> +            goto out_rebind;
> +        }
> +    }
> +
> +    goto out;
> +
> +out_rebind:
> +    /* some interfaces might be bound to usbback, unbind it then and
> +     * rebind to its original driver
> +     */
> +    unbind_usb_device_from_usbback(gc, usb);
> +out:
> +    if (intfs) {
> +        for (i = 0; i < num; i++)
> +            free(intfs[i]);
> +        free(intfs);
> +    }
> +
> +    return rc;
> +}
> +
> +static int do_usb_add(libxl__gc *gc, uint32_t domid, libxl_device_usb *usb)
> +{
> +    int rc = 0;
> +
> +    rc = libxl__device_usb_add_xenstore(gc, domid, usb);
> +    if (rc) goto out;
> +
> +    rc = bind_usb_device_to_usbback(gc, usb);
> +    if (rc)
> +        libxl__device_usb_remove_xenstore(gc, domid, usb);
> +
> +out:
> +    return rc;
> +}
> +
> +int libxl__device_usb_add(libxl__gc *gc, uint32_t domid, libxl_device_usb *usb)
> +{
> +    libxl_ctx *ctx = CTX;
> +    libxl_device_usb *usbs;
> +    int rc, num;
> +
> +    rc = libxl__device_usb_setdefault(gc, domid, usb);
> +    if (rc) goto out;
> +
> +    rc = libxl__device_usb_assigned_list(gc, &usbs, &num);
> +    if (rc) {
> +        LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "Fail to get assigned usb list");
> +        goto out;
> +    }
> +
> +    if (is_usb_in_array(usbs, num, usb->intf)) {
> +        LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
> +                   "USB device is already attached to a domain");
> +        rc = ERROR_FAIL;
> +        goto out;
> +    }
> +
> +    rc = do_usb_add(gc, domid, usb);
> +
> +out:
> +    return rc;
> +}
> +
> +int libxl_device_usb_add(libxl_ctx *ctx, uint32_t domid,
> +                         libxl_device_usb *usb,
> +                         const libxl_asyncop_how *ao_how)
> +{
> +    AO_CREATE(ctx, domid, ao_how);
> +    int rc;
> +
> +    rc = libxl__device_usb_add(gc, domid, usb);
> +    libxl__ao_complete(egc, ao, rc);
> +    return AO_INPROGRESS;
> +}
> +
> +static int do_usb_remove(libxl__gc *gc, uint32_t domid,
> +                         libxl_device_usb *usb, int force)
> +{
> +
> +    libxl_ctx *ctx = CTX;
> +    libxl_device_usb *usbs = NULL;
> +    int rc = -1, num;
> +
> +    usbs = libxl_device_usb_list_all(gc, domid, &num);
> +    if (!usbs) {
> +        LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
> +                   "No USB device attached to this domain");
> +        goto out;
> +    }
> +
> +    if (!is_usb_in_array(usbs, num, usb->intf)) {
> +        LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
> +                   "USB device is not attached to this domain");
> +        goto out;
> +    }
> +
> +    if (libxl__device_usb_remove_xenstore(gc, domid, usb))
> +        goto out;
> +
> +    if (unbind_usb_device_from_usbback(gc, usb))
> +        goto out;
> +
> +    rc = 0;
> +
> +out:
> +    return rc;
> +}
> +
> +static int libxl__device_usb_remove_common(libxl__gc *gc, uint32_t domid,
> +                                           libxl_device_usb *usb, int force)
> +{
> +    return do_usb_remove(gc, domid, usb, force);
> +}
> +
> +int libxl_device_usb_remove(libxl_ctx *ctx, uint32_t domid,
> +                            libxl_device_usb *usb,
> +                            const libxl_asyncop_how *ao_how)
> +
> +{
> +    AO_CREATE(ctx, domid, ao_how);
> +    int rc;
> +
> +    rc = libxl__device_usb_remove_common(gc, domid, usb, 0);
> +
> +    libxl__ao_complete(egc, ao, rc);
> +    return AO_INPROGRESS;
> +}
> +
> +int libxl_device_usb_destroy(libxl_ctx *ctx, uint32_t domid,
> +                             libxl_device_usb *usb,
> +                             const libxl_asyncop_how *ao_how)
> +{
> +    AO_CREATE(ctx, domid, ao_how);
> +    int rc;
> +
> +    rc = libxl__device_usb_remove_common(gc, domid, usb, 1);
> +
> +    libxl__ao_complete(egc, ao, rc);
> +    return AO_INPROGRESS;
> +}
> +
> +int libxl__device_usb_destroy_all(libxl__gc *gc, uint32_t domid)
> +{
> +    libxl_ctx *ctx = CTX;
> +    libxl_device_usbctrl *usbctrls;
> +    int num, i, rc = 0;
> +
> +    usbctrls = libxl_device_usbctrl_list(ctx, domid, &num);
> +    if (!usbctrls)
> +        return 0;
> +
> +    for (i = 0; i < num; i++) {
> +        /* Force remove on shutdown since, on HVM, qemu will not always
> +         * respond to SCI interrupt because the guest kernel has shut
> +         * down the devices by the time we even get here!
> +         */
> +        if (libxl__device_usbctrl_remove_common(ctx, domid,
> +                                          usbctrls + i, 0, 1) < 0) {
> +            rc = ERROR_FAIL;
> +            goto out;
> +        }
> +    }
> +
> +out:
> +    if (usbctrls)

Pointless test.

> +        free(usbctrls);
> +    return rc;
> +}
> +
> +/*Get usb device information */
> +static int get_usb_devnum (libxl__gc *gc, const char *intf, char *buf)
> +{
> +    char *path;
> +    int rc = 0;
> +    FILE *fd;

Variable naming again.

> +
> +    path = libxl__sprintf(gc, "cat "SYSFS_USB_DEVS_PATH"/%s/devnum", intf);
> +    fd = popen(path, "r");
> +    if (fgets(buf, 512, fd) == NULL || ferror(fd))
> +        rc = -1;
> +    pclose(fd);
> +
> +    return rc;
> +}
> +
> +static int get_usb_busnum(libxl__gc *gc, const char *intf, char *buf)
> +{
> +    char *path;
> +    int rc = 0;
> +    FILE *fd;

And again.

> +
> +    path = libxl__sprintf(gc, "cat "SYSFS_USB_DEVS_PATH"/%s/busnum", intf);
> +    fd = popen(path, "r");
> +    if (fgets(buf, 512, fd) == NULL || ferror(fd))
> +        rc = -1;
> +    pclose(fd);
> +
> +    return rc;
> +}
> +
> +static int get_usb_idVendor(libxl__gc *gc, const char *intf, char *buf)
> +{
> +    char *path;
> +    int rc = 0;
> +    FILE *fd;

Again.

> +
> +    path = libxl__sprintf(gc, "cat "SYSFS_USB_DEVS_PATH"/%s/idVendor", intf);
> +    fd = popen(path, "r");
> +    if (fgets(buf, 512, fd) == NULL || ferror(fd))
> +        rc = -1;
> +    pclose(fd);
> +
> +    return rc;
> +}
> +
> +static int get_usb_idProduct(libxl__gc *gc, const char *intf, char *buf)
> +{
> +    char *path;
> +    int rc = 0;
> +    FILE *fd;

Again.

> +
> +    path = libxl__sprintf(gc, "cat "SYSFS_USB_DEVS_PATH"/%s/idProduct", intf);
> +    fd = popen(path, "r");
> +    if (fgets(buf, 512, fd) == NULL || ferror(fd))
> +        rc = -1;
> +    pclose(fd);
> +
> +    return rc;
> +}
> +
> +static int get_usb_manufacturer(libxl__gc *gc, const char *intf, char *buf)
> +{
> +    char *path;
> +    int rc = 0;
> +    FILE *fd;

Again.

> +
> +    path = libxl__sprintf(gc, "cat "SYSFS_USB_DEVS_PATH"/%s/manufacturer", intf);
> +    fd = popen(path, "r");
> +    if (fgets(buf, 512, fd) == NULL || ferror(fd))
> +        rc = -1;
> +    pclose(fd);
> +
> +    return rc;
> +}
> +
> +static int get_usb_product(libxl__gc *gc, const char *intf, char *buf)
> +{
> +    char *path;
> +    int rc = 0;
> +    FILE *fd;

Again.

> +
> +    path = libxl__sprintf(gc, "cat "SYSFS_USB_DEVS_PATH"/%s/product", intf);
> +    fd = popen(path, "r");
> +    if (fgets(buf, 512, fd) == NULL || ferror(fd))
> +        rc = -1;
> +    pclose(fd);
> +
> +    return rc;
> +}

Wouldn't it make sense to have just one generic function taking the leaf
name as additional argument?

Like:

static int get_usb_leaf(libxl__gc *gc, const char *intf, char *buf,
                         char *leaf)
{
     char *path;
     int rc = 0;
     FILE *fp;

     path = libxl__sprintf(gc, "cat "SYSFS_USB_DEVS_PATH"/%s/%s", intf,
                           leaf);
     fp = popen(path, "r"); /* a pipe shouldn't be needed here */
     if (fgets(buf, 512, fp) == NULL || ferror(fp))
         rc = -1;
     pclose(fp);

     return rc;
}

static int get_usb_product(libxl__gc *gc, const char *intf, char *buf)
{
     return get_usb_leaf(gc, intf, buf, "product");
}

> +
> +int libxl_device_usb_getinfo(libxl_ctx *ctx, char *intf, libxl_usbinfo *usbinfo)
> +{
> +    GC_INIT(ctx);
> +    char buf[512];
> +
> +    if (!get_usb_devnum(gc, intf, buf) )
> +        usbinfo->devnum = atoi(buf);
> +
> +    if ( !get_usb_busnum(gc, intf, buf))
> +        usbinfo->bus = atoi(buf);
> +
> +    if (!get_usb_idVendor(gc, intf, buf) )
> +        usbinfo->idVendor = atoi(buf);
> +
> +    if (!get_usb_idProduct(gc, intf, buf) )
> +        usbinfo->idProduct  = atoi(buf);
> +
> +    if (!get_usb_manufacturer(gc, intf, buf) )
> +        usbinfo->manuf = strdup(buf);
> +
> +    if (!get_usb_product(gc, intf, buf) )
> +        usbinfo->prod = strdup(buf);
> +
> +    GC_FREE;
> +    return 0;
> +}
> +
> +int libxl_intf_to_device_usb(libxl_ctx *ctx, uint32_t domid,
> +                             char *intf, libxl_device_usb *usb)
> +{
> +    GC_INIT(ctx);
> +    libxl_device_usb *usbs = NULL;
> +    int num, i, rc;
> +    bool find = false;
> +
> +    usbs = libxl_device_usb_list_all(gc, domid, &num);
> +
> +    for (i = 0; i < num; i++) {
> +        if (!strcmp(intf, usbs[i].intf) ) {
> +            usb->ctrl = usbs[i].ctrl;
> +            usb->port = usbs[i].port;
> +            usb->intf = strdup(usbs[i].intf);
> +            find = 1;
> +            break;
> +        }
> +    }
> +
> +    /* doesn't find the usb device in domain's usb device list*/
> +    if (!find) {
> +        rc = ERROR_FAIL;
> +        goto out;
> +    }
> +
> +    rc = 0;
> +
> +out:
> +    GC_FREE;
> +    if (usbs)
> +        free(usbs);
> +    return rc;
> +}
> +
> +/*
> + * Local variables:
> + * mode: C
> + * c-basic-offset: 4
> + * indent-tabs-mode: nil
> + * End:
> + */


Juergen

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH RFC V2 3/5] libxl: add pvusb API
  2015-01-19  8:28 ` [PATCH RFC V2 3/5] libxl: add pvusb API Chunyan Liu
  2015-01-28 15:54   ` Ian Campbell
  2015-02-10 10:08   ` Jürgen Groß
@ 2015-02-10 16:01   ` Jürgen Groß
  2015-03-03 11:38   ` Ian Campbell
                     ` (2 subsequent siblings)
  5 siblings, 0 replies; 40+ messages in thread
From: Jürgen Groß @ 2015-02-10 16:01 UTC (permalink / raw)
  To: Chunyan Liu, xen-devel
  Cc: george.dunlap, lars.kurth, caobosimon, ian.campbell, ian.jackson

Just found other issues:

On 01/19/2015 09:28 AM, Chunyan Liu wrote:
> Add pvusb APIs, including:
>   - attach/detach (create/destroy) virtual usb controller.
>   - attach/detach usb device
>   - list assignable usb devices in host
>   - some other helper functions
>
> Signed-off-by: Chunyan Liu <cyliu@suse.com>
> Signed-off-by: Simon Cao <caobosimon@gmail.com>
> ---
>   tools/libxl/Makefile         |    2 +-
>   tools/libxl/libxl.c          |    2 +
>   tools/libxl/libxl.h          |   58 ++
>   tools/libxl/libxl_internal.h |    6 +
>   tools/libxl/libxl_usb.c      | 1277 ++++++++++++++++++++++++++++++++++++++++++
>   tools/libxl/libxlu_cfg_y.c   |  464 ++++++++-------
>   tools/libxl/libxlu_cfg_y.h   |   38 +-
>   7 files changed, 1623 insertions(+), 224 deletions(-)
>   create mode 100644 tools/libxl/libxl_usb.c
>
...
> +/*Get usb device information */
> +static int get_usb_devnum (libxl__gc *gc, const char *intf, char *buf)
> +{
> +    char *path;
> +    int rc = 0;
> +    FILE *fd;
> +
> +    path = libxl__sprintf(gc, "cat "SYSFS_USB_DEVS_PATH"/%s/devnum", intf);
> +    fd = popen(path, "r");
> +    if (fgets(buf, 512, fd) == NULL || ferror(fd))
> +        rc = -1;
> +    pclose(fd);
> +
> +    return rc;
> +}
> +
> +static int get_usb_busnum(libxl__gc *gc, const char *intf, char *buf)
> +{
> +    char *path;
> +    int rc = 0;
> +    FILE *fd;
> +
> +    path = libxl__sprintf(gc, "cat "SYSFS_USB_DEVS_PATH"/%s/busnum", intf);
> +    fd = popen(path, "r");
> +    if (fgets(buf, 512, fd) == NULL || ferror(fd))
> +        rc = -1;
> +    pclose(fd);
> +
> +    return rc;
> +}
> +
> +static int get_usb_idVendor(libxl__gc *gc, const char *intf, char *buf)
> +{
> +    char *path;
> +    int rc = 0;
> +    FILE *fd;
> +
> +    path = libxl__sprintf(gc, "cat "SYSFS_USB_DEVS_PATH"/%s/idVendor", intf);
> +    fd = popen(path, "r");
> +    if (fgets(buf, 512, fd) == NULL || ferror(fd))
> +        rc = -1;
> +    pclose(fd);
> +
> +    return rc;
> +}
> +
> +static int get_usb_idProduct(libxl__gc *gc, const char *intf, char *buf)
> +{
> +    char *path;
> +    int rc = 0;
> +    FILE *fd;
> +
> +    path = libxl__sprintf(gc, "cat "SYSFS_USB_DEVS_PATH"/%s/idProduct", intf);
> +    fd = popen(path, "r");
> +    if (fgets(buf, 512, fd) == NULL || ferror(fd))
> +        rc = -1;
> +    pclose(fd);
> +
> +    return rc;
> +}
> +
> +static int get_usb_manufacturer(libxl__gc *gc, const char *intf, char *buf)
> +{
> +    char *path;
> +    int rc = 0;
> +    FILE *fd;
> +
> +    path = libxl__sprintf(gc, "cat "SYSFS_USB_DEVS_PATH"/%s/manufacturer", intf);

File does not exist in newer kernels (checked 3.16 and 3.19).

> +    fd = popen(path, "r");
> +    if (fgets(buf, 512, fd) == NULL || ferror(fd))
> +        rc = -1;

Another reason not to use popen(): file doesn't exist, but rc = 0.
And buf contains garbage.

> +    pclose(fd);
> +
> +    return rc;
> +}
> +
> +static int get_usb_product(libxl__gc *gc, const char *intf, char *buf)
> +{
> +    char *path;
> +    int rc = 0;
> +    FILE *fd;
> +
> +    path = libxl__sprintf(gc, "cat "SYSFS_USB_DEVS_PATH"/%s/product", intf);

File does not exist in newer kernels (checked 3.16 and 3.19).

> +    fd = popen(path, "r");
> +    if (fgets(buf, 512, fd) == NULL || ferror(fd))
> +        rc = -1;
> +    pclose(fd);
> +
> +    return rc;
> +}
> +
> +int libxl_device_usb_getinfo(libxl_ctx *ctx, char *intf, libxl_usbinfo *usbinfo)
> +{
> +    GC_INIT(ctx);
> +    char buf[512];
> +
> +    if (!get_usb_devnum(gc, intf, buf) )
> +        usbinfo->devnum = atoi(buf);
> +
> +    if ( !get_usb_busnum(gc, intf, buf))
> +        usbinfo->bus = atoi(buf);
> +
> +    if (!get_usb_idVendor(gc, intf, buf) )
> +        usbinfo->idVendor = atoi(buf);

atoi is wrong. idVendor in sysfs is a hex-string.

> +
> +    if (!get_usb_idProduct(gc, intf, buf) )
> +        usbinfo->idProduct  = atoi(buf);

again hex-string.

> +
> +    if (!get_usb_manufacturer(gc, intf, buf) )
> +        usbinfo->manuf = strdup(buf);
> +
> +    if (!get_usb_product(gc, intf, buf) )
> +        usbinfo->prod = strdup(buf);
> +
> +    GC_FREE;
> +    return 0;
> +}

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH RFC V2 1/5] libxl: add pvusb definitions
  2015-01-19  8:28 ` [PATCH RFC V2 1/5] libxl: add pvusb definitions Chunyan Liu
@ 2015-03-03 11:10   ` Ian Campbell
  2015-03-03 16:45     ` George Dunlap
  2015-03-04  7:26     ` Chun Yan Liu
  2015-03-03 17:15   ` George Dunlap
  1 sibling, 2 replies; 40+ messages in thread
From: Ian Campbell @ 2015-03-03 11:10 UTC (permalink / raw)
  To: Chunyan Liu; +Cc: lars.kurth, george.dunlap, xen-devel, ian.jackson, caobosimon

On Mon, 2015-01-19 at 16:28 +0800, Chunyan Liu wrote:

Sorry for the long delay in replying.

> To attach a usb device, a virtual usb controller should be created first.
> This patch defines usbctrl and usbdevice related structs.

Per <54CA17DF0200006600095E3D@relay2.provo.novell.com> please could you
mention here that the HVM guest related parts (i.e.
LIBXL_USBCTRL_TYPE_DEVICEMODEL) and libxl_usb_type are placeholders for
emulated HVM support.

In fact I wonder if it should just be omitted, we will need a LIBXL_HAVE
for HVM USB support anyway once it is implemented so we can add the enum
then.

Or will we -- do we think returning an error for such an HVM guest with
USB devices configured now is acceptable and for it to silently start
working at some point in the future is OK?

> 
> Signed-off-by: Chunyan Liu <cyliu@suse.com>
> Signed-off-by: Simon Cao <caobosimon@gmail.com>
> ---
>  tools/libxl/libxl_types.idl          | 58 +++++++++++++++++++++++++++++++++++-
>  tools/libxl/libxl_types_internal.idl |  1 +
>  2 files changed, 58 insertions(+), 1 deletion(-)
> 
> diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl
> index 1214d2e..0639434 100644
> --- a/tools/libxl/libxl_types.idl
> +++ b/tools/libxl/libxl_types.idl
> @@ -521,6 +531,27 @@ libxl_device_pci = Struct("device_pci", [
>      ("seize", bool),
>      ])
>  
> +libxl_device_usbctrl = Struct("device_usbctrl", [
> +    ("name", string),
> +    ("type", libxl_usbctrl_type),
> +    ("backend_domid", libxl_domid),
> +    ("backend_domname", string),
> +    ("devid", libxl_devid),
> +    ("usb_version", uint8),
> +    ("num_ports", uint8),

I think int would be fine for both of these last two (and is a bit
kinder to language bindings).

> +    ])
> +
> +libxl_device_usb = Struct("device_usb", [
> +    ("ctrl", integer),

Is this an index into something? If so what?

There seems to be no usbctrl array added to the domain_config struct, so
I'm unsure how this is used.

> +    ("port", integer),

Port on the hub?
> +    ("intf", string),

What is this one? (This may just be my lack of usb knowledge)

> +    ("u", KeyedUnion(None, libxl_usb_type, "type",
> +        [("hostdev", Struct(None, [
> +            ("hostbus",   integer),
> +            ("hostaddr",  integer) ]))
> +        ]))
> +    ])
> +
> @@ -547,6 +578,7 @@ libxl_domain_config = Struct("domain_config", [
>      ("disks", Array(libxl_device_disk, "num_disks")),
>      ("nics", Array(libxl_device_nic, "num_nics")),
>      ("pcidevs", Array(libxl_device_pci, "num_pcidevs")),
> +    ("usbs", Array(libxl_device_usb, "num_usbs")),

So, I'm unsure how this interacts with the controllers, which it doesn't
seem to be possible to specify at domain build time.

You pointed me to
http://www.redhat.com/archives/libvir-list/2014-June/msg00038.html but
having had a look through I can't see it.

For v3 please could you give an overview/summary of how it fits together
in the 0/N patch.

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH RFC V2 2/5] libxl: export some functions for pvusb use
  2015-01-19  8:28 ` [PATCH RFC V2 2/5] libxl: export some functions for pvusb use Chunyan Liu
@ 2015-03-03 11:10   ` Ian Campbell
  0 siblings, 0 replies; 40+ messages in thread
From: Ian Campbell @ 2015-03-03 11:10 UTC (permalink / raw)
  To: Chunyan Liu; +Cc: lars.kurth, george.dunlap, xen-devel, ian.jackson, caobosimon

On Mon, 2015-01-19 at 16:28 +0800, Chunyan Liu wrote:
> Signed-off-by: Chunyan Liu <cyliu@suse.com>
> Signed-off-by: Simon Cao <caobosimon@gmail.com>


Acked-by: Ian Campbell <ian.campbell@citrix.com>

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH RFC V2 3/5] libxl: add pvusb API
  2015-01-19  8:28 ` [PATCH RFC V2 3/5] libxl: add pvusb API Chunyan Liu
                     ` (2 preceding siblings ...)
  2015-02-10 16:01   ` Jürgen Groß
@ 2015-03-03 11:38   ` Ian Campbell
  2015-03-04  7:47     ` Chun Yan Liu
  2015-03-06 16:50   ` George Dunlap
  2015-03-17 14:03   ` Juergen Gross
  5 siblings, 1 reply; 40+ messages in thread
From: Ian Campbell @ 2015-03-03 11:38 UTC (permalink / raw)
  To: Chunyan Liu; +Cc: lars.kurth, george.dunlap, xen-devel, ian.jackson, caobosimon

On Mon, 2015-01-19 at 16:28 +0800, Chunyan Liu wrote:
> Add pvusb APIs, including:
>  - attach/detach (create/destroy) virtual usb controller.
>  - attach/detach usb device
>  - list assignable usb devices in host
>  - some other helper functions
> 
> Signed-off-by: Chunyan Liu <cyliu@suse.com>
> Signed-off-by: Simon Cao <caobosimon@gmail.com>
> ---
>  tools/libxl/Makefile         |    2 +-
>  tools/libxl/libxl.c          |    2 +
>  tools/libxl/libxl.h          |   58 ++
>  tools/libxl/libxl_internal.h |    6 +
>  tools/libxl/libxl_usb.c      | 1277 ++++++++++++++++++++++++++++++++++++++++++
>  tools/libxl/libxlu_cfg_y.c   |  464 ++++++++-------
>  tools/libxl/libxlu_cfg_y.h   |   38 +-
>  7 files changed, 1623 insertions(+), 224 deletions(-)
>  create mode 100644 tools/libxl/libxl_usb.c
> 
> diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile
> index b417372..08cdb12 100644
> --- a/tools/libxl/Makefile
> +++ b/tools/libxl/Makefile
> @@ -95,7 +95,7 @@ LIBXL_OBJS = flexarray.o libxl.o libxl_create.o libxl_dm.o libxl_pci.o \
>  			libxl_internal.o libxl_utils.o libxl_uuid.o \
>  			libxl_json.o libxl_aoutils.o libxl_numa.o \
>  			libxl_save_callout.o _libxl_save_msgs_callout.o \
> -			libxl_qmp.o libxl_event.o libxl_fork.o $(LIBXL_OBJS-y)
> +			libxl_qmp.o libxl_event.o libxl_fork.o libxl_usb.o $(LIBXL_OBJS-y)

The contents of that file looks Linux specific, so I think you might
have to arrange for it to only be built there and also to provide a
libxl_nousb.c with stubs returning appropriate errors to be used on
other platforms.

Or it may be possible (even better) to refactor the linux specific bits
of libxl_usb.c into libxl_linux.c and leave the common stuff behind.

I thought libxl_pci.c would be a good example of this, but it doesn't
seem to have any conditional stuff, yet I expected it to be Linux
specific. I've no idea how that works :-(. Maybe usb can get away with
it too.

> +int libxl_intf_to_device_usb(libxl_ctx *ctx, uint32_t domid,
> +                            char *intf, libxl_device_usb *usb)
> +                            LIBXL_EXTERNAL_CALLERS_ONLY;

I wasn't sure what an "intf" was on patch #1. hopefully your answer
there will help me understand what this is for!

> diff --git a/tools/libxl/libxl_usb.c b/tools/libxl/libxl_usb.c
> new file mode 100644
> index 0000000..830a846
> --- /dev/null
> +++ b/tools/libxl/libxl_usb.c

Apart from my not yet understanding the interface semantics and the
potential for Linux-specificness mentioned above the actual code here
looks reasonably OK to me. I have smaller and larger comments below
though.

> +static int libxl__device_usbctrl_setdefault(libxl__gc *gc, uint32_t domid,
> +                                            libxl_device_usbctrl *usbctrl)
> +{
[...]
> +    if(!usbctrl->backend_domid)

Missing space before (.


> +static int libxl__usbctrl_add_xenstore(libxl__gc *gc, uint32_t domid,
> +                                       libxl_device_usbctrl *usbctrl)
> +{
> +    libxl_ctx *ctx = libxl__gc_owner(gc);
> +    flexarray_t *front;
> +    flexarray_t *back;
> +    libxl__device *device;
> +    xs_transaction_t tran;
> +    int rc = 0;
> +
> +    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(back, "frontend-id");
> +    flexarray_append(back, libxl__sprintf(gc, "%d", domid));

GCSPRINTF would be good for all of these (and in lots of other places
too).

flexarray_append_pair is also nice for adding key+value at the same time
since it makes it easier to see what goes together.

> +retry_transaction:
> +    tran = xs_transaction_start(ctx->xsh);

Please follow the design pattern in e.g. libxl__device_vtpm_add or
device_disk_add and use libxl__xs_transaction_start/commit/abort here
inside a for (;;).

> +static int libxl__device_usbctrl_add(libxl__gc *gc, uint32_t domid,
> +                                     libxl_device_usbctrl *usbctrl)
> +{
> [...]
> +    if (libxl__usbctrl_add_xenstore(gc, domid, usbctrl) < 0){

Space before { please.

> +static int
> +libxl__device_usbctrl_remove_common(libxl_ctx *ctx, uint32_t domid,
> +                                    libxl_device_usbctrl *usbctrl,
> +                                    const libxl_asyncop_how *ao_how,
> +                                    int force)
> +{
> [...]
> +    for (i = 0; i < numusb; i++) {
> +        if (libxl__device_usb_remove_common(gc, domid, &usbs[i], 0)) {
> +            fprintf(stderr, "libxl_device_usb_remove failed.\n");

Use LOG*( please, not fprintf (this is true everywhere in libxl in case
I missed any other).

> +/* usb device functions */
> +
> +/* Following functions are to get assignable usb devices */
> +static int
> +libxl__device_usb_assigned_list(libxl__gc *gc,
> +                                libxl_device_usb **list, int *num)
> +{
> +    char **domlist;
> +    unsigned int nd = 0, i, j;
> +    char *be_path;
> +    libxl_device_usb *usb;
> +
> +    *list = NULL;
> +    *num = 0;
> +
> +    domlist = libxl__xs_directory(gc, XBT_NULL, "/local/domain", &nd);
> +    be_path = libxl__sprintf(gc,"/local/domain/0/backend/vusb");

GCSPRINTF.

Also I notice a hardcoded 0, shouldn't that be backend_domid somehow?
I've seen a few /0/ hardcoded here and there in this patch, which if not
backend_domid perhaps ought to at least be LIBXL_TOOLSTACK_DOMID.

If not then is it necessary to dup the string, can't it just be a const
string literal?

> +static bool is_usb_assignable(libxl__gc *gc, char *intf)
> +{
> +    char buf[5];
> +
> +    if (get_usb_bDeviceClass(gc, intf, buf) < 0)
> +        return false;
> +
> +    if (strcmp(buf, USBHUB_CLASS_CODE))
> +        return false;


OOI are hubs inherently unassignable, or is that a short coming of the
current driver code?

> +/* get all usb devices of the domain */
> +static libxl_device_usb *
> +libxl_device_usb_list_all(libxl__gc *gc, uint32_t domid, int *num)

Should be in libxl__ namespace, or since it is static you could omit the
namespacing completely if you prefer.

> +/* xenstore usb data */
> +static int libxl__device_usb_add_xenstore(libxl__gc *gc, uint32_t domid,
> +                                          libxl_device_usb *usb)
> +{
> +    libxl_ctx *ctx = CTX;

FYI although it's not required, you can just use CTX in the code if you
prefer.

> [...]
> +    be_path = libxl__sprintf(gc, "%s/port/%d", be_path, usb->port);
> +    LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, "Adding new usb device to xenstore");

The LOG*( macros will help shorten this line.

> +    path = libxl__sprintf(gc, "cat "SYSFS_USB_DEVS_PATH"/%s/manufacturer", intf);

Whoah, what now?

What you want here is to open the fd and use read on it. We may even
have existing helpers for doing so. Certainly using popen on a string
starting with cat isn't what is wanted (at least not without a big and
convincing comment explaining why this should be needed).

I see a bunch of this in this area.

> +int libxl_device_usb_getinfo(libxl_ctx *ctx, char *intf, libxl_usbinfo *usbinfo)
> +{
> +    GC_INIT(ctx);
> +    char buf[512];
> +
> +    if (!get_usb_devnum(gc, intf, buf) )

In consistent spacing.

> +        usbinfo->devnum = atoi(buf);
> +
> +    if ( !get_usb_busnum(gc, intf, buf))
> +        usbinfo->bus = atoi(buf);
> +
> +    if (!get_usb_idVendor(gc, intf, buf) )
> +        usbinfo->idVendor = atoi(buf);
> +
> +    if (!get_usb_idProduct(gc, intf, buf) )
> +        usbinfo->idProduct  = atoi(buf);
> +
> +    if (!get_usb_manufacturer(gc, intf, buf) )
> +        usbinfo->manuf = strdup(buf);

libxl_strdup with NOGC to get correct error handling please.

> +
> +    if (!get_usb_product(gc, intf, buf) )
> +        usbinfo->prod = strdup(buf);
> +
> +    GC_FREE;
> +    return 0;
> +}
> +

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH RFC V2 4/5] xl: add pvusb commands
  2015-01-19  8:28 ` [PATCH RFC V2 4/5] xl: add pvusb commands Chunyan Liu
  2015-02-10  6:25   ` Jürgen Groß
@ 2015-03-03 11:43   ` Ian Campbell
  2015-03-04  7:48     ` Chun Yan Liu
  2015-03-06 17:25   ` George Dunlap
  2 siblings, 1 reply; 40+ messages in thread
From: Ian Campbell @ 2015-03-03 11:43 UTC (permalink / raw)
  To: Chunyan Liu; +Cc: lars.kurth, george.dunlap, xen-devel, ian.jackson, caobosimon

On Mon, 2015-01-19 at 16:28 +0800, Chunyan Liu wrote:
> Add pvusb commands.
> 
> To attach a usb device to guest through pvusb, one could follow
> following example:
> 
>  #xl usb-ctrl-attach test_vm version=1 num_ports=8
> 
>  #xl usb-list test_vm
>  will show the usb controllers and port usage under the domain.
> 
>  #xl usb-assignable-list
>  will list all assignable usb devices now in host, with their
>  sysfs interface. (This is very useful since later we will use
>  sysfs interface to attach a usb devie to guest)
> 
>  #xl usb-attach test_vm 2-1.1
>  will find the first usable controller:port, and attach usb
>  device with sysfs interface 2-1.1 (sys/bus/usb/devices/2-1.1)
>  to it. One could also specify which <controller> and which <port>
> 
>  #xl usb-detach test_vm 2-1.1
> 
>  #xl usb-ctrl-detach test_vm dev_id
>  will destroy the controller with dev_id as specified. Dev_id
>  can be traced in usb-list info
> 
> Signed-off-by: Chunyan Liu <cyliu@suse.com>
> Signed-off-by: Simon Cao <caobosimon@gmail.com>
> ---
>  tools/libxl/xl.h          |   6 ++
>  tools/libxl/xl_cmdimpl.c  | 256 ++++++++++++++++++++++++++++++++++++++++++++++
>  tools/libxl/xl_cmdtable.c |  30 ++++++

This patch should also touch docs/man/xl*.pod I think.

> +int main_usbassignable_list(int argc, char **argv)
> +{
> +    int opt;
> +
> +    SWITCH_FOREACH_OPT(opt, "", NULL, "usb-assignable-list", 0) {
> +        /* No options */
> +    }
> +
> +    usb_assignable_list();

Unless there are other callers or a good reason to factor it out (e.g.
complexity) you can just do the operation inline here if you like.

The rest of it seems pretty straightforward and looked ok to me.

Ian.

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH RFC V2 5/5] domcreate: support pvusb in configuration file
  2015-01-19  8:28 ` [PATCH RFC V2 5/5] domcreate: support pvusb in configuration file Chunyan Liu
@ 2015-03-03 11:44   ` Ian Campbell
  0 siblings, 0 replies; 40+ messages in thread
From: Ian Campbell @ 2015-03-03 11:44 UTC (permalink / raw)
  To: Chunyan Liu; +Cc: lars.kurth, george.dunlap, xen-devel, ian.jackson, caobosimon

On Mon, 2015-01-19 at 16:28 +0800, Chunyan Liu wrote:
> Add code to support pvusb from domain create. One could specify
> usb in domain's configuration file and create domain, then usb
> device would be attached to guest automatically.
> 
> One could specify usb device in config file like this:
> usb=['2-1.1']
> 
> Signed-off-by: Chunyan Liu <cyliu@suse.com>
> Signed-off-by: Simon Cao <caobosimon@gmail.com>
> ---
>  tools/libxl/libxl_create.c | 41 ++++++++++++++++++++++++++++++++++++++---
>  tools/libxl/xl_cmdimpl.c   | 40 +++++++++++++++++++++++++++++++++++++++-

This should be touching the docs too.

> +static void domcreate_attach_usbs(libxl__egc *egc, libxl__multidev *multidev,
> +                                int ret)
> +{
> [...]
> +    for (i = 0; i < d_config->num_usbs; i++) {
> +        ret = libxl__device_usb_add(gc, domid, &d_config->usbs[i]);
> +        if (ret < 0) {
> +            LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
> +                       "libxl__device_usb_add failed: %d", ret);

Use the LOG*( macros please.

Otherwise the code looks fine, only the lack of docs stops me acking.

Ian.

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH RFC V2 1/5] libxl: add pvusb definitions
  2015-03-03 11:10   ` Ian Campbell
@ 2015-03-03 16:45     ` George Dunlap
  2015-03-04  7:26     ` Chun Yan Liu
  1 sibling, 0 replies; 40+ messages in thread
From: George Dunlap @ 2015-03-03 16:45 UTC (permalink / raw)
  To: Ian Campbell, Chunyan Liu; +Cc: ian.jackson, lars.kurth, caobosimon, xen-devel

On 03/03/2015 11:10 AM, Ian Campbell wrote:
> On Mon, 2015-01-19 at 16:28 +0800, Chunyan Liu wrote:
> 
> Sorry for the long delay in replying.
> 
>> To attach a usb device, a virtual usb controller should be created first.
>> This patch defines usbctrl and usbdevice related structs.
> 
> Per <54CA17DF0200006600095E3D@relay2.provo.novell.com> please could you
> mention here that the HVM guest related parts (i.e.
> LIBXL_USBCTRL_TYPE_DEVICEMODEL) and libxl_usb_type are placeholders for
> emulated HVM support.
> 
> In fact I wonder if it should just be omitted, we will need a LIBXL_HAVE
> for HVM USB support anyway once it is implemented so we can add the enum
> then.
> 
> Or will we -- do we think returning an error for such an HVM guest with
> USB devices configured now is acceptable and for it to silently start
> working at some point in the future is OK?

I think that was my idea back when I was writing the HVM hotplug patches.

> 
>>
>> Signed-off-by: Chunyan Liu <cyliu@suse.com>
>> Signed-off-by: Simon Cao <caobosimon@gmail.com>
>> ---
>>  tools/libxl/libxl_types.idl          | 58 +++++++++++++++++++++++++++++++++++-
>>  tools/libxl/libxl_types_internal.idl |  1 +
>>  2 files changed, 58 insertions(+), 1 deletion(-)
>>
>> diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl
>> index 1214d2e..0639434 100644
>> --- a/tools/libxl/libxl_types.idl
>> +++ b/tools/libxl/libxl_types.idl
>> @@ -521,6 +531,27 @@ libxl_device_pci = Struct("device_pci", [
>>      ("seize", bool),
>>      ])
>>  
>> +libxl_device_usbctrl = Struct("device_usbctrl", [
>> +    ("name", string),
>> +    ("type", libxl_usbctrl_type),
>> +    ("backend_domid", libxl_domid),
>> +    ("backend_domname", string),
>> +    ("devid", libxl_devid),
>> +    ("usb_version", uint8),
>> +    ("num_ports", uint8),
> 
> I think int would be fine for both of these last two (and is a bit
> kinder to language bindings).
> 
>> +    ])
>> +
>> +libxl_device_usb = Struct("device_usb", [
>> +    ("ctrl", integer),
> 
> Is this an index into something? If so what?
> 
> There seems to be no usbctrl array added to the domain_config struct, so
> I'm unsure how this is used.

It looks like this is meant to specify which USB controller you're
plugging your device into; and if you set it to -1, then it will
automatically try to plug it into the best one (and also automatically
create one for you if one doesn't exist).

This should probably be a libxl_devid I'm guessing, then?

 -George

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH RFC V2 1/5] libxl: add pvusb definitions
  2015-01-19  8:28 ` [PATCH RFC V2 1/5] libxl: add pvusb definitions Chunyan Liu
  2015-03-03 11:10   ` Ian Campbell
@ 2015-03-03 17:15   ` George Dunlap
  2015-03-04  8:28     ` Chun Yan Liu
  1 sibling, 1 reply; 40+ messages in thread
From: George Dunlap @ 2015-03-03 17:15 UTC (permalink / raw)
  To: Chunyan Liu, xen-devel; +Cc: ian.jackson, caobosimon, ian.campbell, lars.kurth

On 01/19/2015 08:28 AM, Chunyan Liu wrote:
> To attach a usb device, a virtual usb controller should be created first.
> This patch defines usbctrl and usbdevice related structs.
> 
> Signed-off-by: Chunyan Liu <cyliu@suse.com>
> Signed-off-by: Simon Cao <caobosimon@gmail.com>

Chunyan, thanks for picking up this work!

A couple of things.  First, I think that having the IDL stuff separate
from the patches where they are used actually makes it *harder* to
review, because you can't easily go to the code where it's used and see
what's actually happening.

I think that the IDL stuff used in patch 3 should be in patch 3; and the
domain creation IDL stuff should be included in patch 5.

> ---
>  tools/libxl/libxl_types.idl          | 58 +++++++++++++++++++++++++++++++++++-
>  tools/libxl/libxl_types_internal.idl |  1 +
>  2 files changed, 58 insertions(+), 1 deletion(-)
> 
> diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl
> index 1214d2e..0639434 100644
> --- a/tools/libxl/libxl_types.idl
> +++ b/tools/libxl/libxl_types.idl
> @@ -111,6 +111,16 @@ libxl_nic_type = Enumeration("nic_type", [
>      (2, "VIF"),
>      ])
>  
> +libxl_usbctrl_type = Enumeration("usbctrl_type",[
> +    (0, "AUTO"),
> +    (1, "PV"),
> +    (2, "DEVICEMODEL"),
> +    ])
> +
> +libxl_usb_type = Enumeration("device_usb_type", [
> +    (1, "HOSTDEV"),
> +    ])
> +
>  libxl_action_on_shutdown = Enumeration("action_on_shutdown", [
>      (1, "DESTROY"),
>  
> @@ -394,7 +404,7 @@ libxl_domain_build_info = Struct("domain_build_info",[
>      ("ioports",          Array(libxl_ioport_range, "num_ioports")),
>      ("irqs",             Array(uint32, "num_irqs")),
>      ("iomem",            Array(libxl_iomem_range, "num_iomem")),
> -    ("claim_mode",	     libxl_defbool),
> +    ("claim_mode",       libxl_defbool),

Spurious whitespace change -- please kill this.

>      ("event_channels",   uint32),
>      ("kernel",           string),
>      ("cmdline",          string),
> @@ -521,6 +531,27 @@ libxl_device_pci = Struct("device_pci", [
>      ("seize", bool),
>      ])
>  
> +libxl_device_usbctrl = Struct("device_usbctrl", [
> +    ("name", string),
> +    ("type", libxl_usbctrl_type),
> +    ("backend_domid", libxl_domid),
> +    ("backend_domname", string),
> +    ("devid", libxl_devid),
> +    ("usb_version", uint8),
> +    ("num_ports", uint8),
> +    ])
> +
> +libxl_device_usb = Struct("device_usb", [
> +    ("ctrl", integer),
> +    ("port", integer),
> +    ("intf", string),
> +    ("u", KeyedUnion(None, libxl_usb_type, "type",
> +        [("hostdev", Struct(None, [
> +            ("hostbus",   integer),
> +            ("hostaddr",  integer) ]))
> +        ]))
> +    ])

So "intf" here is wrong.  To begin with, it's information specific to
the "hostdev" type; so it would go under the "type" keyed union under
"hostdev".

Secondly, this requires people to figure out that their media reader has
an intf of "1-2.1.1:1.0".  I don't think that's a good idea, for two
reasons: one, it just seems like a really hard interface to use.  I
couldn't find any straightforward tools to map USB devices onto intf;
tools like "lsusb" instead give you a bus:addr combination.  Secondly,
it's inconsistent with qemu -- which means we'd either have to have two
different ways of specifying the device, or we'd need to translate from
"intf" back into bus:addr

I think the right thing to do here is to take "intf" out of this struct,
and to translate "bus:addr" into intf internally.

It looks like the values qemu and lsusb use can be found in "busnum" and
"devnum" in the sysfs files.  You've already got code to scan those
devices; you just need to add a bit of code to find which of those
corresponds to a given "hostbus:hostaddr" combination.

> +
>  libxl_device_vtpm = Struct("device_vtpm", [
>      ("backend_domid",    libxl_domid),
>      ("backend_domname",  string),
> @@ -547,6 +578,7 @@ libxl_domain_config = Struct("domain_config", [
>      ("disks", Array(libxl_device_disk, "num_disks")),
>      ("nics", Array(libxl_device_nic, "num_nics")),
>      ("pcidevs", Array(libxl_device_pci, "num_pcidevs")),
> +    ("usbs", Array(libxl_device_usb, "num_usbs")),

Any reason you don't make it possible to specify usb controllers as well?

Thanks again for picking this up.  I'll give feedback on the other
patches tomorrow.

 -George

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH RFC V2 1/5] libxl: add pvusb definitions
  2015-03-03 11:10   ` Ian Campbell
  2015-03-03 16:45     ` George Dunlap
@ 2015-03-04  7:26     ` Chun Yan Liu
  2015-03-04 10:00       ` Ian Campbell
  1 sibling, 1 reply; 40+ messages in thread
From: Chun Yan Liu @ 2015-03-04  7:26 UTC (permalink / raw)
  To: Ian Campbell
  Cc: lars.kurth, george.dunlap, xen-devel, ian.jackson, caobosimon



>>> On 3/3/2015 at 07:10 PM, in message <1425381019.24959.87.camel@citrix.com>, Ian
Campbell <ian.campbell@citrix.com> wrote: 
> On Mon, 2015-01-19 at 16:28 +0800, Chunyan Liu wrote: 
>  
> Sorry for the long delay in replying. 
>  
> > To attach a usb device, a virtual usb controller should be created first. 
> > This patch defines usbctrl and usbdevice related structs. 
>  
> Per <54CA17DF0200006600095E3D@relay2.provo.novell.com> please could you 
> mention here that the HVM guest related parts (i.e. 
> LIBXL_USBCTRL_TYPE_DEVICEMODEL) and libxl_usb_type are placeholders for 
> emulated HVM support. 

Yes, I agree it's better placed in libxl_usb_type rather than ctrl_type.

>  
> In fact I wonder if it should just be omitted, we will need a LIBXL_HAVE 
> for HVM USB support anyway once it is implemented so we can add the enum 
> then. 

It won't harm to omit it for current pvusb work. Acceptable to me to
add enum later when adding HVM qemu emulated usb device implementation.

>  
> Or will we -- do we think returning an error for such an HVM guest with 
> USB devices configured now is acceptable and for it to silently start 
> working at some point in the future is OK? 
>  
> >  
> > Signed-off-by: Chunyan Liu <cyliu@suse.com> 
> > Signed-off-by: Simon Cao <caobosimon@gmail.com> 
> > --- 
> >  tools/libxl/libxl_types.idl          | 58  
> +++++++++++++++++++++++++++++++++++- 
> >  tools/libxl/libxl_types_internal.idl |  1 + 
> >  2 files changed, 58 insertions(+), 1 deletion(-) 
> >  
> > diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl 
> > index 1214d2e..0639434 100644 
> > --- a/tools/libxl/libxl_types.idl 
> > +++ b/tools/libxl/libxl_types.idl 
> > @@ -521,6 +531,27 @@ libxl_device_pci = Struct("device_pci", [ 
> >      ("seize", bool), 
> >      ]) 
> >   
> > +libxl_device_usbctrl = Struct("device_usbctrl", [ 
> > +    ("name", string), 
> > +    ("type", libxl_usbctrl_type), 
> > +    ("backend_domid", libxl_domid), 
> > +    ("backend_domname", string), 
> > +    ("devid", libxl_devid), 
> > +    ("usb_version", uint8), 
> > +    ("num_ports", uint8), 
>  
> I think int would be fine for both of these last two (and is a bit 
> kinder to language bindings). 

OK. Will update.

>  
> > +    ]) 
> > + 
> > +libxl_device_usb = Struct("device_usb", [ 
> > +    ("ctrl", integer), 
>  
> Is this an index into something? If so what? 

To usb controller index.
A usb device should be connected to a usb port of a usb controller.
e.g.: there is 2 usb controllers in system, each with 8 ports, then:
1st usb controller index will be 0, port will be 1~8.
2nd usb controller index will be 1, port will be 1~8.
To attach a usb device through pvusb way, it should be pointed to
connect to which controller and which port.

>  
> There seems to be no usbctrl array added to the domain_config struct, so 
> I'm unsure how this is used. 
>  
> > +    ("port", integer), 
>  
> Port on the hub? 
> > +    ("intf", string), 
>  
> What is this one? (This may just be my lack of usb knowledge)

It means sysfs interface for the usb device under /sys/bus/usb/devices/,
like: 2-1.6.

>  
> > +    ("u", KeyedUnion(None, libxl_usb_type, "type", 
> > +        [("hostdev", Struct(None, [ 
> > +            ("hostbus",   integer), 
> > +            ("hostaddr",  integer) ])) 
> > +        ])) 
> > +    ]) 

This part is for HVM qemu emulated usb device too. Currently not used.

> > + 
> > @@ -547,6 +578,7 @@ libxl_domain_config = Struct("domain_config", [ 
> >      ("disks", Array(libxl_device_disk, "num_disks")), 
> >      ("nics", Array(libxl_device_nic, "num_nics")), 
> >      ("pcidevs", Array(libxl_device_pci, "num_pcidevs")), 
> > +    ("usbs", Array(libxl_device_usb, "num_usbs")), 
>  
> So, I'm unsure how this interacts with the controllers, which it doesn't 
> seem to be possible to specify at domain build time.

In domain config, user only needs to specify usb=['2-1.6'], by default, it will
create a default usb contoller, and probe the 1st available controller:port for
the usb device to attach. So, it can work to specify usbs here only.

Reason didn't include controller in libxl_domain_config: for HVM qemu emulated
usb device, all work is done in qemu (create usb controller and attach usb device),
no controller exists in libxl in that case.
 
>  
> You pointed me to 
> http://www.redhat.com/archives/libvir-list/2014-June/msg00038.html but 
> having had a look through I can't see it. 
>  
> For v3 please could you give an overview/summary of ow it fits together 
> in the 0/N patch. 

Sure. Thanks!

-Chunyan

>  
>  
>  

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH RFC V2 3/5] libxl: add pvusb API
  2015-03-03 11:38   ` Ian Campbell
@ 2015-03-04  7:47     ` Chun Yan Liu
  0 siblings, 0 replies; 40+ messages in thread
From: Chun Yan Liu @ 2015-03-04  7:47 UTC (permalink / raw)
  To: Ian Campbell, Juergen Gross
  Cc: lars.kurth, george.dunlap, xen-devel, ian.jackson, caobosimon



>>> On 3/3/2015 at 07:38 PM, in message <1425382696.24959.112.camel@citrix.com>,
Ian Campbell <ian.campbell@citrix.com> wrote: 
> On Mon, 2015-01-19 at 16:28 +0800, Chunyan Liu wrote: 
> > Add pvusb APIs, including: 
> >  - attach/detach (create/destroy) virtual usb controller. 
> >  - attach/detach usb device 
> >  - list assignable usb devices in host 
> >  - some other helper functions 
> >  
> > Signed-off-by: Chunyan Liu <cyliu@suse.com> 
> > Signed-off-by: Simon Cao <caobosimon@gmail.com> 
> > --- 
> >  tools/libxl/Makefile         |    2 +- 
> >  tools/libxl/libxl.c          |    2 + 
> >  tools/libxl/libxl.h          |   58 ++ 
> >  tools/libxl/libxl_internal.h |    6 + 
> >  tools/libxl/libxl_usb.c      | 1277  
> ++++++++++++++++++++++++++++++++++++++++++ 
> >  tools/libxl/libxlu_cfg_y.c   |  464 ++++++++------- 
> >  tools/libxl/libxlu_cfg_y.h   |   38 +- 
> >  7 files changed, 1623 insertions(+), 224 deletions(-) 
> >  create mode 100644 tools/libxl/libxl_usb.c 
> >  
> > diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile 
> > index b417372..08cdb12 100644 
> > --- a/tools/libxl/Makefile 
> > +++ b/tools/libxl/Makefile 
> > @@ -95,7 +95,7 @@ LIBXL_OBJS = flexarray.o libxl.o libxl_create.o  
> libxl_dm.o libxl_pci.o \ 
> >  			libxl_internal.o libxl_utils.o libxl_uuid.o \ 
> >  			libxl_json.o libxl_aoutils.o libxl_numa.o \ 
> >  			libxl_save_callout.o _libxl_save_msgs_callout.o \ 
> > -			libxl_qmp.o libxl_event.o libxl_fork.o $(LIBXL_OBJS-y) 
> > +			libxl_qmp.o libxl_event.o libxl_fork.o libxl_usb.o $(LIBXL_OBJS-y) 
>  
> The contents of that file looks Linux specific, so I think you might 
> have to arrange for it to only be built there and also to provide a 
> libxl_nousb.c with stubs returning appropriate errors to be used on 
> other platforms. 
>  
> Or it may be possible (even better) to refactor the linux specific bits 
> of libxl_usb.c into libxl_linux.c and leave the common stuff behind. 
>  
> I thought libxl_pci.c would be a good example of this, but it doesn't 
> seem to have any conditional stuff, yet I expected it to be Linux 
> specific. I've no idea how that works :-(. Maybe usb can get away with 
> it too. 
>  
> > +int libxl_intf_to_device_usb(libxl_ctx *ctx, uint32_t domid, 
> > +                            char *intf, libxl_device_usb *usb) 
> > +                            LIBXL_EXTERNAL_CALLERS_ONLY; 
>  
> I wasn't sure what an "intf" was on patch #1. hopefully your answer 
> there will help me understand what this is for! 

As in patch#1, it means syfs interface for the usb device, like: 2-1.6.
This function will be used when detaching a usb device, use indicates
2-1.6, it will return the corresponding libxl_device_usb structure.

>  
> > diff --git a/tools/libxl/libxl_usb.c b/tools/libxl/libxl_usb.c 
> > new file mode 100644 
> > index 0000000..830a846 
> > --- /dev/null 
> > +++ b/tools/libxl/libxl_usb.c 
>  
> Apart from my not yet understanding the interface semantics and the 
> potential for Linux-specificness mentioned above the actual code here 
> looks reasonably OK to me. I have smaller and larger comments below 
> though. 
>  
> > +static int libxl__device_usbctrl_setdefault(libxl__gc *gc, uint32_t domid, 
> > +                                            libxl_device_usbctrl *usbctrl) 
> > +{ 
> [...] 
> > +    if(!usbctrl->backend_domid) 
>  
> Missing space before (. 
>  
>  
> > +static int libxl__usbctrl_add_xenstore(libxl__gc *gc, uint32_t domid, 
> > +                                       libxl_device_usbctrl *usbctrl) 
> > +{ 
> > +    libxl_ctx *ctx = libxl__gc_owner(gc); 
> > +    flexarray_t *front; 
> > +    flexarray_t *back; 
> > +    libxl__device *device; 
> > +    xs_transaction_t tran; 
> > +    int rc = 0; 
> > + 
> > +    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(back, "frontend-id"); 
> > +    flexarray_append(back, libxl__sprintf(gc, "%d", domid)); 
>  
> GCSPRINTF would be good for all of these (and in lots of other places 
> too).
>  
> flexarray_append_pair is also nice for adding key+value at the same time 
> since it makes it easier to see what goes together. 

Got it. Will update all in next version.

>  
> > +retry_transaction: 
> > +    tran = xs_transaction_start(ctx->xsh); 
>  
> Please follow the design pattern in e.g. libxl__device_vtpm_add or 
> device_disk_add and use libxl__xs_transaction_start/commit/abort here 
> inside a for (;;). 

OK. Got it.

>  
> > +static int libxl__device_usbctrl_add(libxl__gc *gc, uint32_t domid, 
> > +                                     libxl_device_usbctrl *usbctrl) 
> > +{ 
> > [...] 
> > +    if (libxl__usbctrl_add_xenstore(gc, domid, usbctrl) < 0){ 
>  
> Space before { please. 
>  
> > +static int 
> > +libxl__device_usbctrl_remove_common(libxl_ctx *ctx, uint32_t domid, 
> > +                                    libxl_device_usbctrl *usbctrl, 
> > +                                    const libxl_asyncop_how *ao_how, 
> > +                                    int force) 
> > +{ 
> > [...] 
> > +    for (i = 0; i < numusb; i++) { 
> > +        if (libxl__device_usb_remove_common(gc, domid, &usbs[i], 0)) { 
> > +            fprintf(stderr, "libxl_device_usb_remove failed.\n"); 
>  
> Use LOG*( please, not fprintf (this is true everywhere in libxl in case 
> I missed any other). 
>  
> > +/* usb device functions */ 
> > + 
> > +/* Following functions are to get assignable usb devices */ 
> > +static int 
> > +libxl__device_usb_assigned_list(libxl__gc *gc, 
> > +                                libxl_device_usb **list, int *num) 
> > +{ 
> > +    char **domlist; 
> > +    unsigned int nd = 0, i, j; 
> > +    char *be_path; 
> > +    libxl_device_usb *usb; 
> > + 
> > +    *list = NULL; 
> > +    *num = 0; 
> > + 
> > +    domlist = libxl__xs_directory(gc, XBT_NULL, "/local/domain", &nd); 
> > +    be_path = libxl__sprintf(gc,"/local/domain/0/backend/vusb"); 
>  
> GCSPRINTF. 
>  
> Also I notice a hardcoded 0, shouldn't that be backend_domid somehow? 

Yes, it is. Will update. Thanks for pointing out.

> I've seen a few /0/ hardcoded here and there in this patch, which if not 
> backend_domid perhaps ought to at least be LIBXL_TOOLSTACK_DOMID. 
>  
> If not then is it necessary to dup the string, can't it just be a const 
> string literal? 
>  
> > +static bool is_usb_assignable(libxl__gc *gc, char *intf) 
> > +{ 
> > +    char buf[5]; 
> > + 
> > +    if (get_usb_bDeviceClass(gc, intf, buf) < 0) 
> > +        return false; 
> > + 
> > +    if (strcmp(buf, USBHUB_CLASS_CODE)) 
> > +        return false; 
>  
>  
> OOI are hubs inherently unassignable, or is that a short coming of the 
> current driver code? 

It's right. I'm very sorry here and other few places out of my mistake,
some changes not included in this patch when sending. I noticed that
when sending these patches to Juergen for his kernel patches testing.
Will send the correct ones in next version.

>  
> > +/* get all usb devices of the domain */ 
> > +static libxl_device_usb * 
> > +libxl_device_usb_list_all(libxl__gc *gc, uint32_t domid, int *num) 
>  
> Should be in libxl__ namespace, or since it is static you could omit the 
> namespacing completely if you prefer. 
>  
> > +/* xenstore usb data */ 
> > +static int libxl__device_usb_add_xenstore(libxl__gc *gc, uint32_t domid, 
> > +                                          libxl_device_usb *usb) 
> > +{ 
> > +    libxl_ctx *ctx = CTX; 
>  
> FYI although it's not required, you can just use CTX in the code if you 
> prefer. 
>  
> > [...] 
> > +    be_path = libxl__sprintf(gc, "%s/port/%d", be_path, usb->port); 
> > +    LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, "Adding new usb device to  
> xenstore"); 
>  
> The LOG*( macros will help shorten this line. 
>  
> > +    path = libxl__sprintf(gc, "cat "SYSFS_USB_DEVS_PATH"/%s/manufacturer",  
> intf); 
>  
> Whoah, what now? 
>  
> What you want here is to open the fd and use read on it. We may even
 
Yes. I also think it's odd and so already updated this kinds of places locally
for Juergen's testing. Will be posted in next version. Thanks.
 
> have existing helpers for doing so. Certainly using popen on a string 
> starting with cat isn't what is wanted (at least not without a big and 
> convincing comment explaining why this should be needed). 
>  
> I see a bunch of this in this area. 
>  
> > +int libxl_device_usb_getinfo(libxl_ctx *ctx, char *intf, libxl_usbinfo  
> *usbinfo) 
> > +{ 
> > +    GC_INIT(ctx); 
> > +    char buf[512]; 
> > + 
> > +    if (!get_usb_devnum(gc, intf, buf) ) 
>  
> In consistent spacing. 
>  
> > +        usbinfo->devnum = atoi(buf); 
> > + 
> > +    if ( !get_usb_busnum(gc, intf, buf)) 
> > +        usbinfo->bus = atoi(buf); 
> > + 
> > +    if (!get_usb_idVendor(gc, intf, buf) ) 
> > +        usbinfo->idVendor = atoi(buf); 
> > + 
> > +    if (!get_usb_idProduct(gc, intf, buf) ) 
> > +        usbinfo->idProduct  = atoi(buf); 
> > + 
> > +    if (!get_usb_manufacturer(gc, intf, buf) ) 
> > +        usbinfo->manuf = strdup(buf); 
>  
> libxl_strdup with NOGC to get correct error handling please.

Got it. Will update.

- Chunyan
 
>  
> > + 
> > +    if (!get_usb_product(gc, intf, buf) ) 
> > +        usbinfo->prod = strdup(buf); 
> > + 
> > +    GC_FREE; 
> > +    return 0; 
> > +} 
> > + 
>  
>  
>  

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH RFC V2 4/5] xl: add pvusb commands
  2015-03-03 11:43   ` Ian Campbell
@ 2015-03-04  7:48     ` Chun Yan Liu
  0 siblings, 0 replies; 40+ messages in thread
From: Chun Yan Liu @ 2015-03-04  7:48 UTC (permalink / raw)
  To: Ian Campbell
  Cc: lars.kurth, george.dunlap, xen-devel, ian.jackson, caobosimon



>>> On 3/3/2015 at 07:43 PM, in message <1425382984.24959.115.camel@citrix.com>,
Ian Campbell <ian.campbell@citrix.com> wrote: 
> On Mon, 2015-01-19 at 16:28 +0800, Chunyan Liu wrote: 
> > Add pvusb commands. 
> >  
> > To attach a usb device to guest through pvusb, one could follow 
> > following example: 
> >  
> >  #xl usb-ctrl-attach test_vm version=1 num_ports=8 
> >  
> >  #xl usb-list test_vm 
> >  will show the usb controllers and port usage under the domain. 
> >  
> >  #xl usb-assignable-list 
> >  will list all assignable usb devices now in host, with their 
> >  sysfs interface. (This is very useful since later we will use 
> >  sysfs interface to attach a usb devie to guest) 
> >  
> >  #xl usb-attach test_vm 2-1.1 
> >  will find the first usable controller:port, and attach usb 
> >  device with sysfs interface 2-1.1 (sys/bus/usb/devices/2-1.1) 
> >  to it. One could also specify which <controller> and which <port> 
> >  
> >  #xl usb-detach test_vm 2-1.1 
> >  
> >  #xl usb-ctrl-detach test_vm dev_id 
> >  will destroy the controller with dev_id as specified. Dev_id 
> >  can be traced in usb-list info 
> >  
> > Signed-off-by: Chunyan Liu <cyliu@suse.com> 
> > Signed-off-by: Simon Cao <caobosimon@gmail.com> 
> > --- 
> >  tools/libxl/xl.h          |   6 ++ 
> >  tools/libxl/xl_cmdimpl.c  | 256  
> ++++++++++++++++++++++++++++++++++++++++++++++ 
> >  tools/libxl/xl_cmdtable.c |  30 ++++++ 
>  
> This patch should also touch docs/man/xl*.pod I think. 

Right. Will update it.

>  
> > +int main_usbassignable_list(int argc, char **argv) 
> > +{ 
> > +    int opt; 
> > + 
> > +    SWITCH_FOREACH_OPT(opt, "", NULL, "usb-assignable-list", 0) { 
> > +        /* No options */ 
> > +    } 
> > + 
> > +    usb_assignable_list(); 
>  
> Unless there are other callers or a good reason to factor it out (e.g. 
> complexity) you can just do the operation inline here if you like. 

Got it.

>  
> The rest of it seems pretty straightforward and looked ok to me. 
>  
> Ian. 
>  
>  
>  

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH RFC V2 1/5] libxl: add pvusb definitions
  2015-03-03 17:15   ` George Dunlap
@ 2015-03-04  8:28     ` Chun Yan Liu
  2015-03-04 14:41       ` George Dunlap
  0 siblings, 1 reply; 40+ messages in thread
From: Chun Yan Liu @ 2015-03-04  8:28 UTC (permalink / raw)
  To: George Dunlap, xen-devel
  Cc: ian.jackson, caobosimon, ian.campbell, lars.kurth



>>> On 3/4/2015 at 01:15 AM, in message <54F5EC4E.6020607@eu.citrix.com>, George
Dunlap <george.dunlap@eu.citrix.com> wrote: 
> On 01/19/2015 08:28 AM, Chunyan Liu wrote: 
> > To attach a usb device, a virtual usb controller should be created first. 
> > This patch defines usbctrl and usbdevice related structs. 
> >  
> > Signed-off-by: Chunyan Liu <cyliu@suse.com> 
> > Signed-off-by: Simon Cao <caobosimon@gmail.com> 
>  
> Chunyan, thanks for picking up this work! 
>  
> A couple of things.  First, I think that having the IDL stuff separate 
> from the patches where they are used actually makes it *harder* to 
> review, because you can't easily go to the code where it's used and see 
> what's actually happening. 
>  
> I think that the IDL stuff used in patch 3 should be in patch 3; and the 
> domain creation IDL stuff should be included in patch 5. 

Tha's OK. I'll update.

>  
> > --- 
> >  tools/libxl/libxl_types.idl          | 58  
> +++++++++++++++++++++++++++++++++++- 
> >  tools/libxl/libxl_types_internal.idl |  1 + 
> >  2 files changed, 58 insertions(+), 1 deletion(-) 
> >  
> > diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl 
> > index 1214d2e..0639434 100644 
> > --- a/tools/libxl/libxl_types.idl 
> > +++ b/tools/libxl/libxl_types.idl 
> > @@ -111,6 +111,16 @@ libxl_nic_type = Enumeration("nic_type", [ 
> >      (2, "VIF"), 
> >      ]) 
> >   
> > +libxl_usbctrl_type = Enumeration("usbctrl_type",[ 
> > +    (0, "AUTO"), 
> > +    (1, "PV"), 
> > +    (2, "DEVICEMODEL"), 
> > +    ]) 
> > + 
> > +libxl_usb_type = Enumeration("device_usb_type", [ 
> > +    (1, "HOSTDEV"), 
> > +    ]) 
> > + 
> >  libxl_action_on_shutdown = Enumeration("action_on_shutdown", [ 
> >      (1, "DESTROY"), 
> >   
> > @@ -394,7 +404,7 @@ libxl_domain_build_info = Struct("domain_build_info",[ 
> >      ("ioports",          Array(libxl_ioport_range, "num_ioports")), 
> >      ("irqs",             Array(uint32, "num_irqs")), 
> >      ("iomem",            Array(libxl_iomem_range, "num_iomem")), 
> > -    ("claim_mode",	     libxl_defbool), 
> > +    ("claim_mode",       libxl_defbool), 
>  
> Spurious whitespace change -- please kill this. 
>  
> >      ("event_channels",   uint32), 
> >      ("kernel",           string), 
> >      ("cmdline",          string), 
> > @@ -521,6 +531,27 @@ libxl_device_pci = Struct("device_pci", [ 
> >      ("seize", bool), 
> >      ]) 
> >   
> > +libxl_device_usbctrl = Struct("device_usbctrl", [ 
> > +    ("name", string), 
> > +    ("type", libxl_usbctrl_type), 
> > +    ("backend_domid", libxl_domid), 
> > +    ("backend_domname", string), 
> > +    ("devid", libxl_devid), 
> > +    ("usb_version", uint8), 
> > +    ("num_ports", uint8), 
> > +    ]) 
> > + 
> > +libxl_device_usb = Struct("device_usb", [ 
> > +    ("ctrl", integer), 
> > +    ("port", integer), 
> > +    ("intf", string), 
> > +    ("u", KeyedUnion(None, libxl_usb_type, "type", 
> > +        [("hostdev", Struct(None, [ 
> > +            ("hostbus",   integer), 
> > +            ("hostaddr",  integer) ])) 
> > +        ])) 
> > +    ]) 
>  
> So "intf" here is wrong.  To begin with, it's information specific to 
> the "hostdev" type; so it would go under the "type" keyed union under 
> "hostdev". 
>  
> Secondly, this requires people to figure out that their media reader has 
> an intf of "1-2.1.1:1.0".  I don't think that's a good idea, for two 
> reasons: one, it just seems like a really hard interface to use.  I 
> couldn't find any straightforward tools to map USB devices onto intf; 

Right. One can only use usb-assignable-list for a fast look. That
follows the old xend toolstack way.

> tools like "lsusb" instead give you a bus:addr combination.  Secondly, 
> it's inconsistent with qemu -- which means we'd either have to have two 
> different ways of specifying the device, or we'd need to translate from 
> "intf" back into bus:addr

You are right. Using bus:addr could unify qemu and pvusb. I also thought
about that. Only concern is it's different from old xend toolstack usage.
If that doesn't affect, we can update to use bus:addr, no problem.
 
>  
> I think the right thing to do here is to take "intf" out of this struct, 
> and to translate "bus:addr" into intf internally. 
>  
> It looks like the values qemu and lsusb use can be found in "busnum" and 
> "devnum" in the sysfs files.  You've already got code to scan those 
> devices; you just need to add a bit of code to find which of those 
> corresponds to a given "hostbus:hostaddr" combination. 
>  
> > + 
> >  libxl_device_vtpm = Struct("device_vtpm", [ 
> >      ("backend_domid",    libxl_domid), 
> >      ("backend_domname",  string), 
> > @@ -547,6 +578,7 @@ libxl_domain_config = Struct("domain_config", [ 
> >      ("disks", Array(libxl_device_disk, "num_disks")), 
> >      ("nics", Array(libxl_device_nic, "num_nics")), 
> >      ("pcidevs", Array(libxl_device_pci, "num_pcidevs")), 
> > +    ("usbs", Array(libxl_device_usb, "num_usbs")), 
>  
> Any reason you don't make it possible to specify usb controllers as well?

For qemu emulated HVM usb device, usb controller is created by qemu, no
way to specify it (?) Also I wonder if specifying usb controller is necessary,
seems it won't affect without usb controller here. Correct me if I'm wrong.
If it's necessary, we can add it.

Thanks,
Chunyan
 
>  
> Thanks again for picking this up.  I'll give feedback on the other 
> patches tomorrow. 
>  
>  -George 
>  
>  
>  

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH RFC V2 1/5] libxl: add pvusb definitions
  2015-03-04  7:26     ` Chun Yan Liu
@ 2015-03-04 10:00       ` Ian Campbell
  2015-03-04 12:26         ` George Dunlap
  0 siblings, 1 reply; 40+ messages in thread
From: Ian Campbell @ 2015-03-04 10:00 UTC (permalink / raw)
  To: Chun Yan Liu
  Cc: lars.kurth, george.dunlap, xen-devel, ian.jackson, caobosimon

On Wed, 2015-03-04 at 00:26 -0700, Chun Yan Liu wrote:
> 
> >>> On 3/3/2015 at 07:10 PM, in message <1425381019.24959.87.camel@citrix.com>, Ian
> Campbell <ian.campbell@citrix.com> wrote: 
> > On Mon, 2015-01-19 at 16:28 +0800, Chunyan Liu wrote: 
> >  
> > Sorry for the long delay in replying. 
> >  
> > > To attach a usb device, a virtual usb controller should be created first. 
> > > This patch defines usbctrl and usbdevice related structs. 
> >  
> > Per <54CA17DF0200006600095E3D@relay2.provo.novell.com> please could you 
> > mention here that the HVM guest related parts (i.e. 
> > LIBXL_USBCTRL_TYPE_DEVICEMODEL) and libxl_usb_type are placeholders for 
> > emulated HVM support. 
> 
> Yes, I agree it's better placed in libxl_usb_type rather than ctrl_type.
> 
> >  
> > In fact I wonder if it should just be omitted, we will need a LIBXL_HAVE 
> > for HVM USB support anyway once it is implemented so we can add the enum 
> > then. 
> 
> It won't harm to omit it for current pvusb work. Acceptable to me to
> add enum later when adding HVM qemu emulated usb device implementation.

I suppose users of libxl would like to be able to expose to their users
whether or not HVM USB passthrough will work (i.e. to hide UI options).
So I think we will want the #define eventually so they can know at
compile time if HVM USB will work.

We could add a negative one now (LIBXC_NO_HVM_USB_PASSTHROUGH) and
remove it later, but that's icky I think.

So I think omit the HVM stuff for now, it's less confusing overall that
way.

George, is that OK with you?

> >  
> > > +    ]) 
> > > + 
> > > +libxl_device_usb = Struct("device_usb", [ 
> > > +    ("ctrl", integer), 
> >  
> > Is this an index into something? If so what? 
> 
> To usb controller index.
> A usb device should be connected to a usb port of a usb controller.
> e.g.: there is 2 usb controllers in system, each with 8 ports, then:
> 1st usb controller index will be 0, port will be 1~8.
> 2nd usb controller index will be 1, port will be 1~8.
> To attach a usb device through pvusb way, it should be pointed to
> connect to which controller and which port.

I guess what I'm missing is how do I create this controller? I saw
nothing in the guest cfg which would allow me to create one.

Is there some way to say "I don't care, find a controller and use it"?

> >  
> > There seems to be no usbctrl array added to the domain_config struct, so 
> > I'm unsure how this is used. 
> >  
> > > +    ("port", integer), 
> >  
> > Port on the hub? 
> > > +    ("intf", string), 
> >  
> > What is this one? (This may just be my lack of usb knowledge)
> 
> It means sysfs interface for the usb device under /sys/bus/usb/devices/,
> like: 2-1.6.

Thanks. I think given Georges feedback we will be dropping this?
> ntly not used.
> 
> > > + 
> > > @@ -547,6 +578,7 @@ libxl_domain_config = Struct("domain_config", [ 
> > >      ("disks", Array(libxl_device_disk, "num_disks")), 
> > >      ("nics", Array(libxl_device_nic, "num_nics")), 
> > >      ("pcidevs", Array(libxl_device_pci, "num_pcidevs")), 
> > > +    ("usbs", Array(libxl_device_usb, "num_usbs")), 
> >  
> > So, I'm unsure how this interacts with the controllers, which it doesn't 
> > seem to be possible to specify at domain build time.
> 
> In domain config, user only needs to specify usb=['2-1.6'], by default, it will
> create a default usb contoller, and probe the 1st available controller:port for
> the usb device to attach. So, it can work to specify usbs here only.
> 
> Reason didn't include controller in libxl_domain_config: for HVM qemu emulated
> usb device, all work is done in qemu (create usb controller and attach usb device),
> no controller exists in libxl in that case.

OK, so it's an HVM only thing. I think that makes sense, but then how
does the libxl_device_usb.ctrl field make sense or how do I use it?

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH RFC V2 1/5] libxl: add pvusb definitions
  2015-03-04 10:00       ` Ian Campbell
@ 2015-03-04 12:26         ` George Dunlap
  2015-03-04 12:33           ` Ian Campbell
  0 siblings, 1 reply; 40+ messages in thread
From: George Dunlap @ 2015-03-04 12:26 UTC (permalink / raw)
  To: Ian Campbell, Chun Yan Liu; +Cc: ian.jackson, caobosimon, xen-devel, lars.kurth

On 03/04/2015 10:00 AM, Ian Campbell wrote:
> On Wed, 2015-03-04 at 00:26 -0700, Chun Yan Liu wrote:
>>
>>>>> On 3/3/2015 at 07:10 PM, in message <1425381019.24959.87.camel@citrix.com>, Ian
>> Campbell <ian.campbell@citrix.com> wrote: 
>>> On Mon, 2015-01-19 at 16:28 +0800, Chunyan Liu wrote: 
>>>  
>>> Sorry for the long delay in replying. 
>>>  
>>>> To attach a usb device, a virtual usb controller should be created first. 
>>>> This patch defines usbctrl and usbdevice related structs. 
>>>  
>>> Per <54CA17DF0200006600095E3D@relay2.provo.novell.com> please could you 
>>> mention here that the HVM guest related parts (i.e. 
>>> LIBXL_USBCTRL_TYPE_DEVICEMODEL) and libxl_usb_type are placeholders for 
>>> emulated HVM support. 
>>
>> Yes, I agree it's better placed in libxl_usb_type rather than ctrl_type.
>>
>>>  
>>> In fact I wonder if it should just be omitted, we will need a LIBXL_HAVE 
>>> for HVM USB support anyway once it is implemented so we can add the enum 
>>> then. 
>>
>> It won't harm to omit it for current pvusb work. Acceptable to me to
>> add enum later when adding HVM qemu emulated usb device implementation.
> 
> I suppose users of libxl would like to be able to expose to their users
> whether or not HVM USB passthrough will work (i.e. to hide UI options).
> So I think we will want the #define eventually so they can know at
> compile time if HVM USB will work.
> 
> We could add a negative one now (LIBXC_NO_HVM_USB_PASSTHROUGH) and
> remove it later, but that's icky I think.
> 
> So I think omit the HVM stuff for now, it's less confusing overall that
> way.
> 
> George, is that OK with you?

Yes; particularly as I'm hoping that having the PVUSB stuff in will make
it easier for me to add my HVM usb hot-plug stuff before the feature
freeze. :-)

>> To usb controller index.
>> A usb device should be connected to a usb port of a usb controller.
>> e.g.: there is 2 usb controllers in system, each with 8 ports, then:
>> 1st usb controller index will be 0, port will be 1~8.
>> 2nd usb controller index will be 1, port will be 1~8.
>> To attach a usb device through pvusb way, it should be pointed to
>> connect to which controller and which port.
> 
> I guess what I'm missing is how do I create this controller? I saw
> nothing in the guest cfg which would allow me to create one.
> 
> Is there some way to say "I don't care, find a controller and use it"?

This isn't documented, but if you set "ctrl" to -1, the code as written
will automatically:
 * find an empty port on a controller, if there is one
 * create a controller if there isn't one.

I meant to mention this in my mail yesterday though -- I think probably
there should be a defined constant in the IDL (LIBXL_USBCTRL_AUTO or
something) you should use for that, rather than just remembering a magic
value.

>>>> + 
>>>> @@ -547,6 +578,7 @@ libxl_domain_config = Struct("domain_config", [ 
>>>>      ("disks", Array(libxl_device_disk, "num_disks")), 
>>>>      ("nics", Array(libxl_device_nic, "num_nics")), 
>>>>      ("pcidevs", Array(libxl_device_pci, "num_pcidevs")), 
>>>> +    ("usbs", Array(libxl_device_usb, "num_usbs")), 
>>>  
>>> So, I'm unsure how this interacts with the controllers, which it doesn't 
>>> seem to be possible to specify at domain build time.
>>
>> In domain config, user only needs to specify usb=['2-1.6'], by default, it will
>> create a default usb contoller, and probe the 1st available controller:port for
>> the usb device to attach. So, it can work to specify usbs here only.
>>
>> Reason didn't include controller in libxl_domain_config: for HVM qemu emulated
>> usb device, all work is done in qemu (create usb controller and attach usb device),
>> no controller exists in libxl in that case.
> 
> OK, so it's an HVM only thing. I think that makes sense, but then how
> does the libxl_device_usb.ctrl field make sense or how do I use it?

Well for one, you can use libxl_device_usbctrl_add() to make a new one
on a running VM; then you can use libxl_device_usb_add() to attach it.
(These are exposed in xl as usb-ctrl-attach and usb-attach.)

 -George

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH RFC V2 1/5] libxl: add pvusb definitions
  2015-03-04 12:26         ` George Dunlap
@ 2015-03-04 12:33           ` Ian Campbell
  2015-03-05  5:04             ` Chun Yan Liu
  0 siblings, 1 reply; 40+ messages in thread
From: Ian Campbell @ 2015-03-04 12:33 UTC (permalink / raw)
  To: George Dunlap
  Cc: lars.kurth, Chun Yan Liu, xen-devel, ian.jackson, caobosimon

On Wed, 2015-03-04 at 12:26 +0000, George Dunlap wrote:
> On 03/04/2015 10:00 AM, Ian Campbell wrote:
> > On Wed, 2015-03-04 at 00:26 -0700, Chun Yan Liu wrote:
> >>
> >>>>> On 3/3/2015 at 07:10 PM, in message <1425381019.24959.87.camel@citrix.com>, Ian
> >> Campbell <ian.campbell@citrix.com> wrote: 
> >>> On Mon, 2015-01-19 at 16:28 +0800, Chunyan Liu wrote: 
> >>>  
> >>> Sorry for the long delay in replying. 
> >>>  
> >>>> To attach a usb device, a virtual usb controller should be created first. 
> >>>> This patch defines usbctrl and usbdevice related structs. 
> >>>  
> >>> Per <54CA17DF0200006600095E3D@relay2.provo.novell.com> please could you 
> >>> mention here that the HVM guest related parts (i.e. 
> >>> LIBXL_USBCTRL_TYPE_DEVICEMODEL) and libxl_usb_type are placeholders for 
> >>> emulated HVM support. 
> >>
> >> Yes, I agree it's better placed in libxl_usb_type rather than ctrl_type.
> >>
> >>>  
> >>> In fact I wonder if it should just be omitted, we will need a LIBXL_HAVE 
> >>> for HVM USB support anyway once it is implemented so we can add the enum 
> >>> then. 
> >>
> >> It won't harm to omit it for current pvusb work. Acceptable to me to
> >> add enum later when adding HVM qemu emulated usb device implementation.
> > 
> > I suppose users of libxl would like to be able to expose to their users
> > whether or not HVM USB passthrough will work (i.e. to hide UI options).
> > So I think we will want the #define eventually so they can know at
> > compile time if HVM USB will work.
> > 
> > We could add a negative one now (LIBXC_NO_HVM_USB_PASSTHROUGH) and
> > remove it later, but that's icky I think.
> > 
> > So I think omit the HVM stuff for now, it's less confusing overall that
> > way.
> > 
> > George, is that OK with you?
> 
> Yes; particularly as I'm hoping that having the PVUSB stuff in will make
> it easier for me to add my HVM usb hot-plug stuff before the feature
> freeze. :-)

Great.

> 
> >> To usb controller index.
> >> A usb device should be connected to a usb port of a usb controller.
> >> e.g.: there is 2 usb controllers in system, each with 8 ports, then:
> >> 1st usb controller index will be 0, port will be 1~8.
> >> 2nd usb controller index will be 1, port will be 1~8.
> >> To attach a usb device through pvusb way, it should be pointed to
> >> connect to which controller and which port.
> > 
> > I guess what I'm missing is how do I create this controller? I saw
> > nothing in the guest cfg which would allow me to create one.
> > 
> > Is there some way to say "I don't care, find a controller and use it"?
> 
> This isn't documented, but if you set "ctrl" to -1, the code as written
> will automatically:
>  * find an empty port on a controller, if there is one
>  * create a controller if there isn't one.
> 
> I meant to mention this in my mail yesterday though -- I think probably
> there should be a defined constant in the IDL (LIBXL_USBCTRL_AUTO or
> something) you should use for that, rather than just remembering a magic
> value.

Yes, and it should be the init_val in the idl I think so that the
default is to do something useful after _init is called.

Can we arrange for the default/auto value to be 0, or is that too
confusing because it is expected that controllers will be zero based?

> >>>> + 
> >>>> @@ -547,6 +578,7 @@ libxl_domain_config = Struct("domain_config", [ 
> >>>>      ("disks", Array(libxl_device_disk, "num_disks")), 
> >>>>      ("nics", Array(libxl_device_nic, "num_nics")), 
> >>>>      ("pcidevs", Array(libxl_device_pci, "num_pcidevs")), 
> >>>> +    ("usbs", Array(libxl_device_usb, "num_usbs")), 
> >>>  
> >>> So, I'm unsure how this interacts with the controllers, which it doesn't 
> >>> seem to be possible to specify at domain build time.
> >>
> >> In domain config, user only needs to specify usb=['2-1.6'], by default, it will
> >> create a default usb contoller, and probe the 1st available controller:port for
> >> the usb device to attach. So, it can work to specify usbs here only.
> >>
> >> Reason didn't include controller in libxl_domain_config: for HVM qemu emulated
> >> usb device, all work is done in qemu (create usb controller and attach usb device),
> >> no controller exists in libxl in that case.
> > 
> > OK, so it's an HVM only thing. I think that makes sense, but then how
> > does the libxl_device_usb.ctrl field make sense or how do I use it?
> 
> Well for one, you can use libxl_device_usbctrl_add() to make a new one
> on a running VM; then you can use libxl_device_usb_add() to attach it.
> (These are exposed in xl as usb-ctrl-attach and usb-attach.)

I was thinking in the context of the domain_config struct above, so
runtime xl commands other than create aren't usable.

Ian.

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH RFC V2 1/5] libxl: add pvusb definitions
  2015-03-04  8:28     ` Chun Yan Liu
@ 2015-03-04 14:41       ` George Dunlap
  2015-03-05  6:07         ` Chun Yan Liu
  0 siblings, 1 reply; 40+ messages in thread
From: George Dunlap @ 2015-03-04 14:41 UTC (permalink / raw)
  To: Chun Yan Liu, xen-devel; +Cc: ian.jackson, caobosimon, ian.campbell, lars.kurth

On 03/04/2015 08:28 AM, Chun Yan Liu wrote:
> 
> 
>>>> On 3/4/2015 at 01:15 AM, in message <54F5EC4E.6020607@eu.citrix.com>, George
> Dunlap <george.dunlap@eu.citrix.com> wrote: 
>> On 01/19/2015 08:28 AM, Chunyan Liu wrote: 
>>> To attach a usb device, a virtual usb controller should be created first. 
>>> This patch defines usbctrl and usbdevice related structs. 
>>>  
>>> Signed-off-by: Chunyan Liu <cyliu@suse.com> 
>>> Signed-off-by: Simon Cao <caobosimon@gmail.com> 
>>  
>> Chunyan, thanks for picking up this work! 
>>  
>> A couple of things.  First, I think that having the IDL stuff separate 
>> from the patches where they are used actually makes it *harder* to 
>> review, because you can't easily go to the code where it's used and see 
>> what's actually happening. 
>>  
>> I think that the IDL stuff used in patch 3 should be in patch 3; and the 
>> domain creation IDL stuff should be included in patch 5. 
> 
> Tha's OK. I'll update.

Great, thanks.

>>> +libxl_device_usbctrl = Struct("device_usbctrl", [ 
>>> +    ("name", string), 
>>> +    ("type", libxl_usbctrl_type), 
>>> +    ("backend_domid", libxl_domid), 
>>> +    ("backend_domname", string), 
>>> +    ("devid", libxl_devid), 
>>> +    ("usb_version", uint8), 
>>> +    ("num_ports", uint8), 
>>> +    ]) 
>>> + 
>>> +libxl_device_usb = Struct("device_usb", [ 
>>> +    ("ctrl", integer), 
>>> +    ("port", integer), 
>>> +    ("intf", string), 
>>> +    ("u", KeyedUnion(None, libxl_usb_type, "type", 
>>> +        [("hostdev", Struct(None, [ 
>>> +            ("hostbus",   integer), 
>>> +            ("hostaddr",  integer) ])) 
>>> +        ])) 
>>> +    ]) 
>>  
>> So "intf" here is wrong.  To begin with, it's information specific to 
>> the "hostdev" type; so it would go under the "type" keyed union under 
>> "hostdev". 
>>  
>> Secondly, this requires people to figure out that their media reader has 
>> an intf of "1-2.1.1:1.0".  I don't think that's a good idea, for two 
>> reasons: one, it just seems like a really hard interface to use.  I 
>> couldn't find any straightforward tools to map USB devices onto intf; 
> 
> Right. One can only use usb-assignable-list for a fast look. That
> follows the old xend toolstack way.
> 
>> tools like "lsusb" instead give you a bus:addr combination.  Secondly, 
>> it's inconsistent with qemu -- which means we'd either have to have two 
>> different ways of specifying the device, or we'd need to translate from 
>> "intf" back into bus:addr
> 
> You are right. Using bus:addr could unify qemu and pvusb. I also thought
> about that. Only concern is it's different from old xend toolstack usage.
> If that doesn't affect, we can update to use bus:addr, no problem.

Right, I see.

I think overall that the bus:addr is a better interface; it's also
what's exposed by lsusb, qemu, and libvirt, AFAICT.  So I definitely
think that at the libxl level that's what we should be using.

We're already defining a new config file format, right?  So domain
configs that used pvusb with xend won't work with this patch series
anyway, correct?

If we're not going to make something 100% compatible, I don't see any
particular value in making it 25% compatible. :-)

>> I think the right thing to do here is to take "intf" out of this struct, 
>> and to translate "bus:addr" into intf internally. 
>>  
>> It looks like the values qemu and lsusb use can be found in "busnum" and 
>> "devnum" in the sysfs files.  You've already got code to scan those 
>> devices; you just need to add a bit of code to find which of those 
>> corresponds to a given "hostbus:hostaddr" combination. 
>>  
>>> + 
>>>  libxl_device_vtpm = Struct("device_vtpm", [ 
>>>      ("backend_domid",    libxl_domid), 
>>>      ("backend_domname",  string), 
>>> @@ -547,6 +578,7 @@ libxl_domain_config = Struct("domain_config", [ 
>>>      ("disks", Array(libxl_device_disk, "num_disks")), 
>>>      ("nics", Array(libxl_device_nic, "num_nics")), 
>>>      ("pcidevs", Array(libxl_device_pci, "num_pcidevs")), 
>>> +    ("usbs", Array(libxl_device_usb, "num_usbs")), 
>>  
>> Any reason you don't make it possible to specify usb controllers as well?
> 
> For qemu emulated HVM usb device, usb controller is created by qemu, no
> way to specify it (?) Also I wonder if specifying usb controller is necessary,
> seems it won't affect without usb controller here. Correct me if I'm wrong.
> If it's necessary, we can add it.

On the contrary, there is a way to specify it. :-)  See
"usbversion=[n]".  At the moment we specify the usb device on the qemu
command-line; but I'm pretty sure that we can use qmp to hot-plug a USB
controller just like we can use it to hot-plug a USB device.

qemu will automatically hot-plug a USB controller as necessary, similar
to your "automatically create a pvusb controller" functionality for
pvusb add.  But there may be circumstances where we want to specify a
controller (for instance, if you want to be able to control what kind of
controller it is).

My long-term vision is to have the USB stuff unified.  Instead of
passing in USB devices on the qemu command-line, as we do now, we'd plug
them in after starting qemu but before letting the VM run (similar to
the way we do things with PCI pass-through).

In any case, I agree with your design decision that you shouldn't *have*
to specify a controller.  However, I think you should be able to specify
a controller if you wish.

Adding that functionality to libxl should be pretty straightforward.
Coming up with a sensible way to specify it in the xl config file would
be a bit more work, and I would be open to the argument that it
shouldn't be a requirement for this series to go in.

 -George

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH RFC V2 1/5] libxl: add pvusb definitions
  2015-03-04 12:33           ` Ian Campbell
@ 2015-03-05  5:04             ` Chun Yan Liu
  0 siblings, 0 replies; 40+ messages in thread
From: Chun Yan Liu @ 2015-03-05  5:04 UTC (permalink / raw)
  To: Ian Campbell, George Dunlap
  Cc: ian.jackson, caobosimon, xen-devel, lars.kurth



>>> On 3/4/2015 at 08:33 PM, in message <1425472438.25940.147.camel@citrix.com>,
Ian Campbell <ian.campbell@citrix.com> wrote: 
> On Wed, 2015-03-04 at 12:26 +0000, George Dunlap wrote: 
> > On 03/04/2015 10:00 AM, Ian Campbell wrote: 
> > > On Wed, 2015-03-04 at 00:26 -0700, Chun Yan Liu wrote: 
> > >> 
> > >>>>> On 3/3/2015 at 07:10 PM, in message <1425381019.24959.87.camel@citrix.com>,  
> Ian 
> > >> Campbell <ian.campbell@citrix.com> wrote:  
> > >>> On Mon, 2015-01-19 at 16:28 +0800, Chunyan Liu wrote:  
> > >>>   
> > >>> Sorry for the long delay in replying.  
> > >>>   
> > >>>> To attach a usb device, a virtual usb controller should be created first.  
> > >>>> This patch defines usbctrl and usbdevice related structs.  
> > >>>   
> > >>> Per <54CA17DF0200006600095E3D@relay2.provo.novell.com> please could you  
> > >>> mention here that the HVM guest related parts (i.e.  
> > >>> LIBXL_USBCTRL_TYPE_DEVICEMODEL) and libxl_usb_type are placeholders for  
> > >>> emulated HVM support.  
> > >> 
> > >> Yes, I agree it's better placed in libxl_usb_type rather than ctrl_type. 
> > >> 
> > >>>   
> > >>> In fact I wonder if it should just be omitted, we will need a LIBXL_HAVE  
> > >>> for HVM USB support anyway once it is implemented so we can add the enum  
> > >>> then.  
> > >> 
> > >> It won't harm to omit it for current pvusb work. Acceptable to me to 
> > >> add enum later when adding HVM qemu emulated usb device implementation. 
> > >  
> > > I suppose users of libxl would like to be able to expose to their users 
> > > whether or not HVM USB passthrough will work (i.e. to hide UI options). 
> > > So I think we will want the #define eventually so they can know at 
> > > compile time if HVM USB will work. 
> > >  
> > > We could add a negative one now (LIBXC_NO_HVM_USB_PASSTHROUGH) and 
> > > remove it later, but that's icky I think. 
> > >  
> > > So I think omit the HVM stuff for now, it's less confusing overall that 
> > > way. 
> > >  
> > > George, is that OK with you? 
> >  
> > Yes; particularly as I'm hoping that having the PVUSB stuff in will make 
> > it easier for me to add my HVM usb hot-plug stuff before the feature 
> > freeze. :-) 
>  
> Great. 
>  
> >  
> > >> To usb controller index. 
> > >> A usb device should be connected to a usb port of a usb controller. 
> > >> e.g.: there is 2 usb controllers in system, each with 8 ports, then: 
> > >> 1st usb controller index will be 0, port will be 1~8. 
> > >> 2nd usb controller index will be 1, port will be 1~8. 
> > >> To attach a usb device through pvusb way, it should be pointed to 
> > >> connect to which controller and which port. 
> > >  
> > > I guess what I'm missing is how do I create this controller? I saw 
> > > nothing in the guest cfg which would allow me to create one. 
> > >  
> > > Is there some way to say "I don't care, find a controller and use it"? 
> >  
> > This isn't documented, but if you set "ctrl" to -1, the code as written 
> > will automatically: 
> >  * find an empty port on a controller, if there is one 
> >  * create a controller if there isn't one. 
> >  
> > I meant to mention this in my mail yesterday though -- I think probably 
> > there should be a defined constant in the IDL (LIBXL_USBCTRL_AUTO or 
> > something) you should use for that, rather than just remembering a magic 
> > value. 
>  
> Yes, and it should be the init_val in the idl I think so that the 
> default is to do something useful after _init is called. 

Got it. Will update.

>  
> Can we arrange for the default/auto value to be 0, or is that too 
> confusing because it is expected that controllers will be zero based? 

Yeah, controller index is zero based, so it might be confusing if setting
default/auto to be 0.

- Chunyan

>  
> > >>>> +  
> > >>>> @@ -547,6 +578,7 @@ libxl_domain_config = Struct("domain_config", [  
> > >>>>      ("disks", Array(libxl_device_disk, "num_disks")),  
> > >>>>      ("nics", Array(libxl_device_nic, "num_nics")),  
> > >>>>      ("pcidevs", Array(libxl_device_pci, "num_pcidevs")),  
> > >>>> +    ("usbs", Array(libxl_device_usb, "num_usbs")),  
> > >>>   
> > >>> So, I'm unsure how this interacts with the controllers, which it doesn't  
> > >>> seem to be possible to specify at domain build time. 
> > >> 
> > >> In domain config, user only needs to specify usb=['2-1.6'], by default, it  
> will 
> > >> create a default usb contoller, and probe the 1st available  
> controller:port for 
> > >> the usb device to attach. So, it can work to specify usbs here only. 
> > >> 
> > >> Reason didn't include controller in libxl_domain_config: for HVM qemu  
> emulated 
> > >> usb device, all work is done in qemu (create usb controller and attach usb  
> device), 
> > >> no controller exists in libxl in that case. 
> > >  
> > > OK, so it's an HVM only thing. I think that makes sense, but then how 
> > > does the libxl_device_usb.ctrl field make sense or how do I use it? 
> >  
> > Well for one, you can use libxl_device_usbctrl_add() to make a new one 
> > on a running VM; then you can use libxl_device_usb_add() to attach it. 
> > (These are exposed in xl as usb-ctrl-attach and usb-attach.) 
>  
> I was thinking in the context of the domain_config struct above, so 
> runtime xl commands other than create aren't usable. 
>  
> Ian. 
>  
>  
>  

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH RFC V2 1/5] libxl: add pvusb definitions
  2015-03-04 14:41       ` George Dunlap
@ 2015-03-05  6:07         ` Chun Yan Liu
  0 siblings, 0 replies; 40+ messages in thread
From: Chun Yan Liu @ 2015-03-05  6:07 UTC (permalink / raw)
  To: George Dunlap, xen-devel
  Cc: ian.jackson, caobosimon, ian.campbell, lars.kurth



>>> On 3/4/2015 at 10:41 PM, in message <54F71992.5080306@eu.citrix.com>, George
Dunlap <george.dunlap@eu.citrix.com> wrote: 
> On 03/04/2015 08:28 AM, Chun Yan Liu wrote: 
> >  
> >  
> >>>> On 3/4/2015 at 01:15 AM, in message <54F5EC4E.6020607@eu.citrix.com>, George 
> > Dunlap <george.dunlap@eu.citrix.com> wrote:  
> >> On 01/19/2015 08:28 AM, Chunyan Liu wrote:  
> >>> To attach a usb device, a virtual usb controller should be created first.  
> >>> This patch defines usbctrl and usbdevice related structs.  
> >>>   
> >>> Signed-off-by: Chunyan Liu <cyliu@suse.com>  
> >>> Signed-off-by: Simon Cao <caobosimon@gmail.com>  
> >>   
> >> Chunyan, thanks for picking up this work!  
> >>   
> >> A couple of things.  First, I think that having the IDL stuff separate  
> >> from the patches where they are used actually makes it *harder* to  
> >> review, because you can't easily go to the code where it's used and see  
> >> what's actually happening.  
> >>   
> >> I think that the IDL stuff used in patch 3 should be in patch 3; and the  
> >> domain creation IDL stuff should be included in patch 5.  
> >  
> > Tha's OK. I'll update. 
>  
> Great, thanks. 
>  
> >>> +libxl_device_usbctrl = Struct("device_usbctrl", [  
> >>> +    ("name", string),  
> >>> +    ("type", libxl_usbctrl_type),  
> >>> +    ("backend_domid", libxl_domid),  
> >>> +    ("backend_domname", string),  
> >>> +    ("devid", libxl_devid),  
> >>> +    ("usb_version", uint8),  
> >>> +    ("num_ports", uint8),  
> >>> +    ])  
> >>> +  
> >>> +libxl_device_usb = Struct("device_usb", [  
> >>> +    ("ctrl", integer),  
> >>> +    ("port", integer),  
> >>> +    ("intf", string),  
> >>> +    ("u", KeyedUnion(None, libxl_usb_type, "type",  
> >>> +        [("hostdev", Struct(None, [  
> >>> +            ("hostbus",   integer),  
> >>> +            ("hostaddr",  integer) ]))  
> >>> +        ]))  
> >>> +    ])  
> >>   
> >> So "intf" here is wrong.  To begin with, it's information specific to  
> >> the "hostdev" type; so it would go under the "type" keyed union under  
> >> "hostdev".  
> >>   
> >> Secondly, this requires people to figure out that their media reader has  
> >> an intf of "1-2.1.1:1.0".  I don't think that's a good idea, for two  
> >> reasons: one, it just seems like a really hard interface to use.  I  
> >> couldn't find any straightforward tools to map USB devices onto intf;  
> >  
> > Right. One can only use usb-assignable-list for a fast look. That 
> > follows the old xend toolstack way. 
> >  
> >> tools like "lsusb" instead give you a bus:addr combination.  Secondly,  
> >> it's inconsistent with qemu -- which means we'd either have to have two  
> >> different ways of specifying the device, or we'd need to translate from  
> >> "intf" back into bus:addr 
> >  
> > You are right. Using bus:addr could unify qemu and pvusb. I also thought 
> > about that. Only concern is it's different from old xend toolstack usage. 
> > If that doesn't affect, we can update to use bus:addr, no problem. 
>  
> Right, I see. 
>  
> I think overall that the bus:addr is a better interface; it's also 
> what's exposed by lsusb, qemu, and libvirt, AFAICT.  So I definitely 
> think that at the libxl level that's what we should be using. 

Thanks. Got it. Will update.

>  
> We're already defining a new config file format, right?  So domain 
> configs that used pvusb with xend won't work with this patch series 
> anyway, correct? 
>  
> If we're not going to make something 100% compatible, I don't see any 
> particular value in making it 25% compatible. :-) 
>  
> >> I think the right thing to do here is to take "intf" out of this struct,  
> >> and to translate "bus:addr" into intf internally.  
> >>   
> >> It looks like the values qemu and lsusb use can be found in "busnum" and  
> >> "devnum" in the sysfs files.  You've already got code to scan those  
> >> devices; you just need to add a bit of code to find which of those  
> >> corresponds to a given "hostbus:hostaddr" combination.  
> >>   
> >>> +  
> >>>  libxl_device_vtpm = Struct("device_vtpm", [  
> >>>      ("backend_domid",    libxl_domid),  
> >>>      ("backend_domname",  string),  
> >>> @@ -547,6 +578,7 @@ libxl_domain_config = Struct("domain_config", [  
> >>>      ("disks", Array(libxl_device_disk, "num_disks")),  
> >>>      ("nics", Array(libxl_device_nic, "num_nics")),  
> >>>      ("pcidevs", Array(libxl_device_pci, "num_pcidevs")),  
> >>> +    ("usbs", Array(libxl_device_usb, "num_usbs")),  
> >>   
> >> Any reason you don't make it possible to specify usb controllers as well? 
> >  
> > For qemu emulated HVM usb device, usb controller is created by qemu, no 
> > way to specify it (?) Also I wonder if specifying usb controller is  
> necessary, 
> > seems it won't affect without usb controller here. Correct me if I'm wrong. 
> > If it's necessary, we can add it. 
>  
> On the contrary, there is a way to specify it. :-)  See 
> "usbversion=[n]".  At the moment we specify the usb device on the qemu 
> command-line; but I'm pretty sure that we can use qmp to hot-plug a USB 
> controller just like we can use it to hot-plug a USB device. 
>  
> qemu will automatically hot-plug a USB controller as necessary, similar 
> to your "automatically create a pvusb controller" functionality for 
> pvusb add.  But there may be circumstances where we want to specify a 
> controller (for instance, if you want to be able to control what kind of 
> controller it is). 
>  
> My long-term vision is to have the USB stuff unified.  Instead of 
> passing in USB devices on the qemu command-line, as we do now, we'd plug 
> them in after starting qemu but before letting the VM run (similar to 
> the way we do things with PCI pass-through). 

Thanks for explanation. So I'll add usb controllers to domain_config, and
for that libxl_device_usbctrl should be finally able to represent pvusb controller
and qemu emulated controller. Currently, it's defined to represent a pvusb
controller, in future, when HVM qemu emulated USB is implemented, it could
be extended.

- Chunyan

>  
> In any case, I agree with your design decision that you shouldn't *have* 
> to specify a controller.  However, I think you should be able to specify 
> a controller if you wish. 
>  
> Adding that functionality to libxl should be pretty straightforward. 
> Coming up with a sensible way to specify it in the xl config file would 
> be a bit more work, and I would be open to the argument that it 
> shouldn't be a requirement for this series to go in. 
>
>  
>  -George 
>  
>  

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH RFC V2 3/5] libxl: add pvusb API
  2015-01-19  8:28 ` [PATCH RFC V2 3/5] libxl: add pvusb API Chunyan Liu
                     ` (3 preceding siblings ...)
  2015-03-03 11:38   ` Ian Campbell
@ 2015-03-06 16:50   ` George Dunlap
  2015-03-09  9:39     ` Ian Campbell
  2015-03-20  9:37     ` Chun Yan Liu
  2015-03-17 14:03   ` Juergen Gross
  5 siblings, 2 replies; 40+ messages in thread
From: George Dunlap @ 2015-03-06 16:50 UTC (permalink / raw)
  To: Chunyan Liu; +Cc: Lars Kurth, Ian Jackson, Simon Cao, Ian Campbell, xen-devel

On Mon, Jan 19, 2015 at 8:28 AM, Chunyan Liu <cyliu@suse.com> wrote:
> diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
> index 0a123f1..2e89244 100644
> --- a/tools/libxl/libxl.h
> +++ b/tools/libxl/libxl.h

> +int libxl_intf_to_device_usb(libxl_ctx *ctx, uint32_t domid,
> +                            char *intf, libxl_device_usb *usb)
> +                            LIBXL_EXTERNAL_CALLERS_ONLY;

I guess this function will go away?

> diff --git a/tools/libxl/libxl_usb.c b/tools/libxl/libxl_usb.c
> new file mode 100644
> index 0000000..830a846
> --- /dev/null
> +++ b/tools/libxl/libxl_usb.c
> @@ -0,0 +1,1277 @@

> +static int libxl__usbport_add_xenstore(libxl__gc *gc,
> +                                       xs_transaction_t tran,
> +                                       uint32_t domid,
> +                                       libxl_device_usbctrl *usbctrl)

Would it be too much to ask to have all the pvusb-specific stuff in a
separate file -- say, "libxl_pvusb.c" or something?  That would make
it a lot easier when I add in the HVM USB stuff.

(Just to be clear, I'm asking as a favor -- it's policy that the first
mover gets to have it easier, and people who want to come and add
something later are the ones who have to do the refactoring.)

> +{
> +    char *path;
> +    int i;
> +
> +    path = GCSPRINTF("%s/backend/vusb/%d/%d/port",
> +                     libxl__xs_get_dompath(gc, 0), domid, usbctrl->devid);
> +
> +    libxl__xs_mkdir(gc, tran, path, NULL, 0);
> +
> +    for (i = 1; i <= usbctrl->num_ports; i++) {
> +        if (libxl__xs_write_checked(gc, tran, GCSPRINTF("%s/%d", path, i), ""))
> +            return ERROR_FAIL;
> +    }
> +
> +    return 0;
> +}
> +
> +static int libxl__usbctrl_add_xenstore(libxl__gc *gc, uint32_t domid,
> +                                       libxl_device_usbctrl *usbctrl)
> +{
> +    libxl_ctx *ctx = libxl__gc_owner(gc);
> +    flexarray_t *front;
> +    flexarray_t *back;
> +    libxl__device *device;
> +    xs_transaction_t tran;
> +    int rc = 0;
> +
> +    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(back, "frontend-id");
> +    flexarray_append(back, libxl__sprintf(gc, "%d", domid));
> +    flexarray_append(back, "online");
> +    flexarray_append(back, "1");
> +    flexarray_append(back, "state");
> +    flexarray_append(back, libxl__sprintf(gc, "%d", 1));
> +    flexarray_append(back, "usb-ver");
> +    flexarray_append(back, libxl__sprintf(gc, "%d", usbctrl->usb_version));
> +    flexarray_append(back, "num-ports");
> +    flexarray_append(back, libxl__sprintf(gc, "%d", usbctrl->num_ports));

So how much of this is pvusb-specific, and how much would be shared
between DEVICEMODEL?  Because this bit looks specifically like the
stuff used to set up the pvusb connection...

> +    flexarray_append(back, "type");
> +    switch(usbctrl->type) {
> +    case LIBXL_USBCTRL_TYPE_PV:{
> +        flexarray_append(back, "PVUSB");
> +        break;
> +    }
> +    case LIBXL_USBCTRL_TYPE_DEVICEMODEL: {
> +        flexarray_append(back, "IOEMU");
> +        break;
> +    }
> +    default:
> +        /* not supported */
> +        rc = ERROR_FAIL;
> +        goto out;
> +    }

...but this looks like it's trying to be shared between PVUSB and
DEVICEMODEL.  I'm pretty sure this isn't going to work long-run,
because if we were to write all this stuff for a devicemodel, wouldn't
the pvusb back-end take this as setting up a new pvusb port?

Also, you don't seem to be storing or retreiving usbctrl->name here --
if we want that to be part of the interface we need to use it.  (I
think we wanted that so that it could default to something like pv-0,
emul-1, &c).

In general, I don't think libxl should be storing stuff in the pvusb
front/back xenstore directories not related to that protocol.  We
should store extraneous information in a libxl-specific directory.
You can see an example of the kind of think I'm talking about in the
HVM USB patch I submitted last year (see usb_add_xenstore()):

http://lists.xen.org/archives/html/xen-devel/2014-06/msg00086.html

Alternately -- at the moment, the only extraneous information we've
got is the name of the controller; if you wanted to propose that we
get rid of the name field, then there wouldn't be any extra
information to store.

> +
> +    flexarray_append(front, "backend-id");
> +    flexarray_append(front, libxl__sprintf(gc, "%d", usbctrl->backend_domid));
> +    flexarray_append(front, "state");
> +    flexarray_append(front, libxl__sprintf(gc, "%d", 1));
> +
> +retry_transaction:
> +    tran = xs_transaction_start(ctx->xsh);
> +
> +    libxl__device_generic_add(gc, tran, device,
> +                              libxl__xs_kvs_of_flexarray(gc, back, back->count),
> +                              libxl__xs_kvs_of_flexarray(gc, front, front->count),
> +                              NULL);
> +    libxl__usbport_add_xenstore(gc, tran, domid, usbctrl);
> +
> +    if (!xs_transaction_end(ctx->xsh, tran, 0)) {
> +        if (errno == EAGAIN)
> +            goto retry_transaction;
> +        else {
> +            rc = ERROR_FAIL;
> +            goto out;
> +        }
> +    }
> +
> +out:
> +    return rc;
> +}
> +
> +static int libxl__device_usbctrl_add(libxl__gc *gc, uint32_t domid,
> +                                     libxl_device_usbctrl *usbctrl)
> +{
> +    int rc = 0;
> +
> +    rc = libxl__device_usbctrl_setdefault(gc, domid, usbctrl);
> +    if(rc) goto out;
> +
> +    if (usbctrl->devid == -1) {

This also needs to have a symbolic name; something with "AUTO" in it.

> +        if ((usbctrl->devid = libxl__device_nextid(gc, domid, "vusb")) < 0) {
> +            rc = ERROR_FAIL;
> +            goto out;
> +        }
> +    }
> +
> +    if (libxl__usbctrl_add_xenstore(gc, domid, usbctrl) < 0){
> +        rc = ERROR_FAIL;
> +        goto out;
> +    }
> +
> +out:
> +    return rc;
> +}
> +


> +/* Following functions are to get assignable usb devices */

<snip>

> +libxl_device_usb *
> +libxl_device_usb_assignable_list(libxl_ctx *ctx, int *num)

I'm a bit ambivalent about this one.  For people using xl, "lsusb"
should be just fine.  Is anyone building a toolstack on top of libxl
directly going to need this functionality?  Would libvirt use this
functionality, for instance, or would it use libusb?  Or just leave
that to the caller?


> +static int libxl__device_usb_setdefault(libxl__gc *gc, uint32_t domid,
> +                                        libxl_device_usb *usb)
> +{
> +    char *be_path, *tmp;
> +
> +    if (usb->ctrl == -1) {
> +        int ret = libxl__device_usb_set_default_usbctrl(gc, domid, usb);
> +        /* If no existing ctrl to host this usb device, setup a new one */
> +        if (ret) {
> +            libxl_device_usbctrl usbctrl;
> +            libxl_device_usbctrl_init(&usbctrl);
> +            libxl__device_usbctrl_add(gc, domid, &usbctrl);

What happens if this fails?

 -George

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH RFC V2 4/5] xl: add pvusb commands
  2015-01-19  8:28 ` [PATCH RFC V2 4/5] xl: add pvusb commands Chunyan Liu
  2015-02-10  6:25   ` Jürgen Groß
  2015-03-03 11:43   ` Ian Campbell
@ 2015-03-06 17:25   ` George Dunlap
  2015-03-20  9:02     ` Chun Yan Liu
  2 siblings, 1 reply; 40+ messages in thread
From: George Dunlap @ 2015-03-06 17:25 UTC (permalink / raw)
  To: Chunyan Liu; +Cc: Lars Kurth, Ian Jackson, Simon Cao, Ian Campbell, xen-devel

On Mon, Jan 19, 2015 at 8:28 AM, Chunyan Liu <cyliu@suse.com> wrote:
> Add pvusb commands.
>
> To attach a usb device to guest through pvusb, one could follow
> following example:
>
>  #xl usb-ctrl-attach test_vm version=1 num_ports=8

This doesn't allow you to specify controller name or devid.

I was looking at the other device-attach code, and they all seem to
have a "devicespec"-style specification.  Would it make sense to do
something similar?

For example:

xl usb-ctrl-attach test_vm name=pv-1,type=pv,version=1,ports=8

Then we could re-use this for the config file as well.

>  #xl usb-list test_vm
>  will show the usb controllers and port usage under the domain.
>
>  #xl usb-assignable-list
>  will list all assignable usb devices now in host, with their
>  sysfs interface. (This is very useful since later we will use
>  sysfs interface to attach a usb devie to guest)
>
>  #xl usb-attach test_vm 2-1.1
>  will find the first usable controller:port, and attach usb
>  device with sysfs interface 2-1.1 (sys/bus/usb/devices/2-1.1)
>  to it. One could also specify which <controller> and which <port>
>
>  #xl usb-detach test_vm 2-1.1

Long-term we want to be able to attach and detach more kinds of
devices than just host devices; for example for HVM guests we want to
be able to attach mice, keyboards, tablets, &c.

What if we continued with the "devicespec" idea above, it might make
more sense to say something like

xl usb-attach test_vm type=hostdev,hostbus=X,hostaddr=Y,ctrl=pv-1

(Assuming you had a controller named pv-1, for example.)

And then maybe in the future we could have something like

xl usb-attach test_vm type=tablet

Thoughts?

 -George

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH RFC V2 3/5] libxl: add pvusb API
  2015-03-06 16:50   ` George Dunlap
@ 2015-03-09  9:39     ` Ian Campbell
  2015-03-09 10:17       ` George Dunlap
  2015-03-20  9:37     ` Chun Yan Liu
  1 sibling, 1 reply; 40+ messages in thread
From: Ian Campbell @ 2015-03-09  9:39 UTC (permalink / raw)
  To: George Dunlap; +Cc: Lars Kurth, Ian Jackson, Simon Cao, Chunyan Liu, xen-devel

On Fri, 2015-03-06 at 16:50 +0000, George Dunlap wrote:
> > +libxl_device_usb *
> > +libxl_device_usb_assignable_list(libxl_ctx *ctx, int *num)
> 
> I'm a bit ambivalent about this one.  For people using xl, "lsusb"
> should be just fine.  Is anyone building a toolstack on top of libxl
> directly going to need this functionality?  Would libvirt use this
> functionality, for instance, or would it use libusb?  Or just leave
> that to the caller?

Do USB devices not need to be bound to some sort of placeholder driver
(a la xen-pciback) or at least unbound from their actual driver before
they can be assigned to a guest?

If so then I would expect a function such as this to list the subset of
devices which have been correctly configured for USB passthrough, which
would be a subset of the output of lsusb I think.

Ian.

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH RFC V2 3/5] libxl: add pvusb API
  2015-03-09  9:39     ` Ian Campbell
@ 2015-03-09 10:17       ` George Dunlap
  2015-03-09 10:41         ` Ian Campbell
  0 siblings, 1 reply; 40+ messages in thread
From: George Dunlap @ 2015-03-09 10:17 UTC (permalink / raw)
  To: Ian Campbell; +Cc: Lars Kurth, Ian Jackson, Simon Cao, Chunyan Liu, xen-devel

On 03/09/2015 09:39 AM, Ian Campbell wrote:
> On Fri, 2015-03-06 at 16:50 +0000, George Dunlap wrote:
>>> +libxl_device_usb *
>>> +libxl_device_usb_assignable_list(libxl_ctx *ctx, int *num)
>>
>> I'm a bit ambivalent about this one.  For people using xl, "lsusb"
>> should be just fine.  Is anyone building a toolstack on top of libxl
>> directly going to need this functionality?  Would libvirt use this
>> functionality, for instance, or would it use libusb?  Or just leave
>> that to the caller?
> 
> Do USB devices not need to be bound to some sort of placeholder driver
> (a la xen-pciback) or at least unbound from their actual driver before
> they can be assigned to a guest?
> 
> If so then I would expect a function such as this to list the subset of
> devices which have been correctly configured for USB passthrough, which
> would be a subset of the output of lsusb I think.

Are you saying you think this is what the function *should* do, or are
you saying that you think it should be renamed because that's what the
name would lead you to expect it did?

This code, following xend's lead, seems to do the plugging stuff
automatically; similar to the "seize=1" flag I added for PCI devices.  I
think this is probably the best interface here; the reason it's not
enabled by default in the PCI case is that it's so dangerous (you might
yank out your own hard disk by accident).

Given this "auto-seize" is what xend did, and what qemu does (and what
VirtualBox does, and what presumably every other virtualization-related
software does), I think adding the "make assignable" step would be
unnecessary and confusing.

 -George

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH RFC V2 3/5] libxl: add pvusb API
  2015-03-09 10:17       ` George Dunlap
@ 2015-03-09 10:41         ` Ian Campbell
  0 siblings, 0 replies; 40+ messages in thread
From: Ian Campbell @ 2015-03-09 10:41 UTC (permalink / raw)
  To: George Dunlap; +Cc: Lars Kurth, Ian Jackson, Simon Cao, Chunyan Liu, xen-devel

On Mon, 2015-03-09 at 10:17 +0000, George Dunlap wrote:
> On 03/09/2015 09:39 AM, Ian Campbell wrote:
> > On Fri, 2015-03-06 at 16:50 +0000, George Dunlap wrote:
> >>> +libxl_device_usb *
> >>> +libxl_device_usb_assignable_list(libxl_ctx *ctx, int *num)
> >>
> >> I'm a bit ambivalent about this one.  For people using xl, "lsusb"
> >> should be just fine.  Is anyone building a toolstack on top of libxl
> >> directly going to need this functionality?  Would libvirt use this
> >> functionality, for instance, or would it use libusb?  Or just leave
> >> that to the caller?
> > 
> > Do USB devices not need to be bound to some sort of placeholder driver
> > (a la xen-pciback) or at least unbound from their actual driver before
> > they can be assigned to a guest?
> > 
> > If so then I would expect a function such as this to list the subset of
> > devices which have been correctly configured for USB passthrough, which
> > would be a subset of the output of lsusb I think.
> 
> Are you saying you think this is what the function *should* do, or are
> you saying that you think it should be renamed because that's what the
> name would lead you to expect it did?

I was saying that's what I would have expected, but also asking how USB
passthru worked because I didn't know.

> This code, following xend's lead, seems to do the plugging stuff
> automatically; similar to the "seize=1" flag I added for PCI devices.  I
> think this is probably the best interface here; the reason it's not
> enabled by default in the PCI case is that it's so dangerous (you might
> yank out your own hard disk by accident).
> 
> Given this "auto-seize" is what xend did, and what qemu does (and what
> VirtualBox does, and what presumably every other virtualization-related
> software does), I think adding the "make assignable" step would be
> unnecessary and confusing.

I agree, given non-optional auto-seize I'm not sure having a function to
enumerate the USB devices is all that useful, unless we happen to need
it internally and it is convenient to expose it.

However, it might be the sort of thing we could put in libxlutil, since
it is the sort of thing every toolstack would have to write for itself
otherwise.

Ian.

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH RFC V2 3/5] libxl: add pvusb API
  2015-01-19  8:28 ` [PATCH RFC V2 3/5] libxl: add pvusb API Chunyan Liu
                     ` (4 preceding siblings ...)
  2015-03-06 16:50   ` George Dunlap
@ 2015-03-17 14:03   ` Juergen Gross
  5 siblings, 0 replies; 40+ messages in thread
From: Juergen Gross @ 2015-03-17 14:03 UTC (permalink / raw)
  To: Chunyan Liu, xen-devel
  Cc: george.dunlap, lars.kurth, caobosimon, ian.campbell, ian.jackson

Hi Chunyan,

I've found another problem while trying to write a qemu based pvUSB
backend.

On 01/19/2015 09:28 AM, Chunyan Liu wrote:
> Add pvusb APIs, including:
>   - attach/detach (create/destroy) virtual usb controller.
>   - attach/detach usb device
>   - list assignable usb devices in host
>   - some other helper functions
>
> Signed-off-by: Chunyan Liu <cyliu@suse.com>
> Signed-off-by: Simon Cao <caobosimon@gmail.com>
> ---

...

> diff --git a/tools/libxl/libxl_usb.c b/tools/libxl/libxl_usb.c
> new file mode 100644
> index 0000000..830a846
> --- /dev/null
> +++ b/tools/libxl/libxl_usb.c

...

> +/* xenstore usb data */
> +static int libxl__device_usb_add_xenstore(libxl__gc *gc, uint32_t domid,
> +                                          libxl_device_usb *usb)
> +{
> +    libxl_ctx *ctx = CTX;
> +    char *be_path;
> +    int rc;
> +    libxl_domain_config d_config;
> +    libxl_device_usb usb_saved;
> +    libxl__domain_userdata_lock *lock = NULL;
> +
> +    libxl_domain_config_init(&d_config);
> +    libxl_device_usb_init(&usb_saved);
> +    libxl_device_usb_copy(CTX, &usb_saved, usb);
> +
> +    be_path = libxl__sprintf(gc, "%s/backend/vusb/%d/%d",
> +                        libxl__xs_get_dompath(gc, 0), domid, usb->ctrl);
> +    if (libxl__wait_for_backend(gc, be_path, "4") < 0) {

Don't do this! That's the reason I had to change my backend driver in
order to support assignment of a usb device via config file. Normally
the backend will witch to state 4 only after the frontend is started.

You can just remove waiting for the backend here. The backend has to
check all ports when it is changing is state to 4 ("connected").

> +        rc = ERROR_FAIL;
> +        goto out;
> +    }
> +
> +    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(usb, usbs, domid, &usb_saved, COMPARE_USB, &d_config);
> +
> +    rc = libxl__set_domain_configuration(gc, domid, &d_config);
> +    if (rc) goto out;
> +
> +    be_path = libxl__sprintf(gc, "%s/port/%d", be_path, usb->port);
> +    LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, "Adding new usb device to xenstore");
> +    if (libxl__xs_write_checked(gc, XBT_NULL, be_path, usb->intf)) {
> +        rc = ERROR_FAIL;
> +        goto out;
> +    }
> +
> +    rc = 0;
> +
> +out:
> +    if (lock) libxl__unlock_domain_userdata(lock);
> +    libxl_device_usb_dispose(&usb_saved);
> +    libxl_domain_config_dispose(&d_config);
> +    return rc;
> +
> +}
> +
> +static int libxl__device_usb_remove_xenstore(libxl__gc *gc, uint32_t domid,
> +                                             libxl_device_usb *usb)
> +{
> +    libxl_ctx *ctx = CTX;
> +    char *be_path;
> +
> +    be_path = libxl__sprintf(gc, "%s/backend/vusb/%d/%d",
> +                        libxl__xs_get_dompath(gc, 0), domid, usb->ctrl);
> +    if (libxl__wait_for_backend(gc, be_path, "4") < 0)

Remove this one, too.

Juergen

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH RFC V2 4/5] xl: add pvusb commands
  2015-03-06 17:25   ` George Dunlap
@ 2015-03-20  9:02     ` Chun Yan Liu
  0 siblings, 0 replies; 40+ messages in thread
From: Chun Yan Liu @ 2015-03-20  9:02 UTC (permalink / raw)
  To: George Dunlap; +Cc: Ian Jackson, Simon Cao, xen-devel, Ian Campbell, Lars Kurth



>>> On 3/7/2015 at 01:25 AM, in message
<CAFLBxZb1N3_9PVvg-yC8dyVaiySZVRA3H2e8496vHNEfvrm6Zg@mail.gmail.com>, George
Dunlap <George.Dunlap@eu.citrix.com> wrote: 
> On Mon, Jan 19, 2015 at 8:28 AM, Chunyan Liu <cyliu@suse.com> wrote: 
> > Add pvusb commands. 
> > 
> > To attach a usb device to guest through pvusb, one could follow 
> > following example: 
> > 
> >  #xl usb-ctrl-attach test_vm version=1 num_ports=8 
>  
> This doesn't allow you to specify controller name or devid. 
>  
> I was looking at the other device-attach code, and they all seem to 
> have a "devicespec"-style specification.  Would it make sense to do 
> something similar? 
>  
> For example: 
>  
> xl usb-ctrl-attach test_vm name=pv-1,type=pv,version=1,ports=8 
>  
> Then we could re-use this for the config file as well. 
>  
> >  #xl usb-list test_vm 
> >  will show the usb controllers and port usage under the domain. 
> > 
> >  #xl usb-assignable-list 
> >  will list all assignable usb devices now in host, with their 
> >  sysfs interface. (This is very useful since later we will use 
> >  sysfs interface to attach a usb devie to guest) 
> > 
> >  #xl usb-attach test_vm 2-1.1 
> >  will find the first usable controller:port, and attach usb 
> >  device with sysfs interface 2-1.1 (sys/bus/usb/devices/2-1.1) 
> >  to it. One could also specify which <controller> and which <port> 
> > 
> >  #xl usb-detach test_vm 2-1.1 
>  
> Long-term we want to be able to attach and detach more kinds of 
> devices than just host devices; for example for HVM guests we want to 
> be able to attach mice, keyboards, tablets, &c. 
>  
> What if we continued with the "devicespec" idea above, it might make 
> more sense to say something like 
>  
> xl usb-attach test_vm type=hostdev,hostbus=X,hostaddr=Y,ctrl=pv-1 
>  
> (Assuming you had a controller named pv-1, for example.) 
>  
> And then maybe in the future we could have something like 
>  
> xl usb-attach test_vm type=tablet 
>  
> Thoughts? 

This could be. I can update.

>  
>  -George 
>  
>  

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH RFC V2 3/5] libxl: add pvusb API
  2015-03-06 16:50   ` George Dunlap
  2015-03-09  9:39     ` Ian Campbell
@ 2015-03-20  9:37     ` Chun Yan Liu
  1 sibling, 0 replies; 40+ messages in thread
From: Chun Yan Liu @ 2015-03-20  9:37 UTC (permalink / raw)
  To: George Dunlap; +Cc: Ian Jackson, Simon Cao, xen-devel, Ian Campbell, Lars Kurth



>>> On 3/7/2015 at 12:50 AM, in message
<CAFLBxZZfzL2F4qnuWGbPzA8v1fFGvvkBGn+gCO6CeEkvBf6hHA@mail.gmail.com>, George
Dunlap <George.Dunlap@eu.citrix.com> wrote: 
> On Mon, Jan 19, 2015 at 8:28 AM, Chunyan Liu <cyliu@suse.com> wrote: 
> > diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h 
> > index 0a123f1..2e89244 100644 
> > --- a/tools/libxl/libxl.h 
> > +++ b/tools/libxl/libxl.h 
>  
> > +int libxl_intf_to_device_usb(libxl_ctx *ctx, uint32_t domid, 
> > +                            char *intf, libxl_device_usb *usb) 
> > +                            LIBXL_EXTERNAL_CALLERS_ONLY; 
>  
> I guess this function will go away? 

With using bus:addr instead of sysfs interface, this will be removed.

>  
> > diff --git a/tools/libxl/libxl_usb.c b/tools/libxl/libxl_usb.c 
> > new file mode 100644 
> > index 0000000..830a846 
> > --- /dev/null 
> > +++ b/tools/libxl/libxl_usb.c 
> > @@ -0,0 +1,1277 @@ 
>  
> > +static int libxl__usbport_add_xenstore(libxl__gc *gc, 
> > +                                       xs_transaction_t tran, 
> > +                                       uint32_t domid, 
> > +                                       libxl_device_usbctrl *usbctrl) 
>  
> Would it be too much to ask to have all the pvusb-specific stuff in a 
> separate file -- say, "libxl_pvusb.c" or something?  That would make 
> it a lot easier when I add in the HVM USB stuff. 

Sure.

>  
> (Just to be clear, I'm asking as a favor -- it's policy that the first 
> mover gets to have it easier, and people who want to come and add 
> something later are the ones who have to do the refactoring.) 
>  
> > +{ 
> > +    char *path; 
> > +    int i; 
> > + 
> > +    path = GCSPRINTF("%s/backend/vusb/%d/%d/port", 
> > +                     libxl__xs_get_dompath(gc, 0), domid, usbctrl->devid); 
> > + 
> > +    libxl__xs_mkdir(gc, tran, path, NULL, 0); 
> > + 
> > +    for (i = 1; i <= usbctrl->num_ports; i++) { 
> > +        if (libxl__xs_write_checked(gc, tran, GCSPRINTF("%s/%d", path, i),  
> "")) 
> > +            return ERROR_FAIL; 
> > +    } 
> > + 
> > +    return 0; 
> > +} 
> > + 
> > +static int libxl__usbctrl_add_xenstore(libxl__gc *gc, uint32_t domid, 
> > +                                       libxl_device_usbctrl *usbctrl) 
> > +{ 
> > +    libxl_ctx *ctx = libxl__gc_owner(gc); 
> > +    flexarray_t *front; 
> > +    flexarray_t *back; 
> > +    libxl__device *device; 
> > +    xs_transaction_t tran; 
> > +    int rc = 0; 
> > + 
> > +    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(back, "frontend-id"); 
> > +    flexarray_append(back, libxl__sprintf(gc, "%d", domid)); 
> > +    flexarray_append(back, "online"); 
> > +    flexarray_append(back, "1"); 
> > +    flexarray_append(back, "state"); 
> > +    flexarray_append(back, libxl__sprintf(gc, "%d", 1)); 
> > +    flexarray_append(back, "usb-ver"); 
> > +    flexarray_append(back, libxl__sprintf(gc, "%d", usbctrl->usb_version)); 
> > +    flexarray_append(back, "num-ports"); 
> > +    flexarray_append(back, libxl__sprintf(gc, "%d", usbctrl->num_ports)); 
>  
> So how much of this is pvusb-specific, and how much would be shared 
> between DEVICEMODEL?  Because this bit looks specifically like the 
> stuff used to set up the pvusb connection... 

To share with qemu emulated usb controller? I think pvusb backend driver will
probe things under backend/vusb/* and setup connection with pvusb frontend
driver, qemu emulated usb controller should not be placed there at all maybe.

>  
> > +    flexarray_append(back, "type"); 
> > +    switch(usbctrl->type) { 
> > +    case LIBXL_USBCTRL_TYPE_PV:{ 
> > +        flexarray_append(back, "PVUSB"); 
> > +        break; 
> > +    } 
> > +    case LIBXL_USBCTRL_TYPE_DEVICEMODEL: { 
> > +        flexarray_append(back, "IOEMU"); 
> > +        break; 
> > +    } 
> > +    default: 
> > +        /* not supported */ 
> > +        rc = ERROR_FAIL; 
> > +        goto out; 
> > +    } 
>  
> ...but this looks like it's trying to be shared between PVUSB and 
> DEVICEMODEL.  I'm pretty sure this isn't going to work long-run, 
> because if we were to write all this stuff for a devicemodel, wouldn't 
> the pvusb back-end take this as setting up a new pvusb port? 

Yes, I think you are right. This place should only allow pvusb type.
Qemu emulated usb controller should not be stored here.

>  
> Also, you don't seem to be storing or retreiving usbctrl->name here -- 
> if we want that to be part of the interface we need to use it.  (I 
> think we wanted that so that it could default to something like pv-0, 
> emul-1, &c). 

First I wonder usbctrl->name is really needed. If just for interface, we can
use devid (index), it could be 0, 1, and with usb-list one knows info like:
0 is pv, 1 is emulated. But if it helps a lot with a 'name', surely we can
add :)

>  
> In general, I don't think libxl should be storing stuff in the pvusb 
> front/back xenstore directories not related to that protocol.  We 
> should store extraneous information in a libxl-specific directory. 
> You can see an example of the kind of think I'm talking about in the 
> HVM USB patch I submitted last year (see usb_add_xenstore()): 
>  
> http://lists.xen.org/archives/html/xen-devel/2014-06/msg00086.html 
>  
> Alternately -- at the moment, the only extraneous information we've 
> got is the name of the controller; if you wanted to propose that we 
> get rid of the name field, then there wouldn't be any extra 
> information to store. 
>  
> > + 
> > +    flexarray_append(front, "backend-id"); 
> > +    flexarray_append(front, libxl__sprintf(gc, "%d",  
> usbctrl->backend_domid)); 
> > +    flexarray_append(front, "state"); 
> > +    flexarray_append(front, libxl__sprintf(gc, "%d", 1)); 
> > + 
> > +retry_transaction: 
> > +    tran = xs_transaction_start(ctx->xsh); 
> > + 
> > +    libxl__device_generic_add(gc, tran, device, 
> > +                              libxl__xs_kvs_of_flexarray(gc, back,  
> back->count), 
> > +                              libxl__xs_kvs_of_flexarray(gc, front,  
> front->count), 
> > +                              NULL); 
> > +    libxl__usbport_add_xenstore(gc, tran, domid, usbctrl); 
> > + 
> > +    if (!xs_transaction_end(ctx->xsh, tran, 0)) { 
> > +        if (errno == EAGAIN) 
> > +            goto retry_transaction; 
> > +        else { 
> > +            rc = ERROR_FAIL; 
> > +            goto out; 
> > +        } 
> > +    } 
> > + 
> > +out: 
> > +    return rc; 
> > +} 
> > + 
> > +static int libxl__device_usbctrl_add(libxl__gc *gc, uint32_t domid, 
> > +                                     libxl_device_usbctrl *usbctrl) 
> > +{ 
> > +    int rc = 0; 
> > + 
> > +    rc = libxl__device_usbctrl_setdefault(gc, domid, usbctrl); 
> > +    if(rc) goto out; 
> > + 
> > +    if (usbctrl->devid == -1) { 
>  
> This also needs to have a symbolic name; something with "AUTO" in it. 
>  
> > +        if ((usbctrl->devid = libxl__device_nextid(gc, domid, "vusb")) < 0) { 
> > +            rc = ERROR_FAIL; 
> > +            goto out; 
> > +        } 
> > +    } 
> > + 
> > +    if (libxl__usbctrl_add_xenstore(gc, domid, usbctrl) < 0){ 
> > +        rc = ERROR_FAIL; 
> > +        goto out; 
> > +    } 
> > + 
> > +out: 
> > +    return rc; 
> > +} 
> > + 
>  
>  
> > +/* Following functions are to get assignable usb devices */ 
>  
> <snip> 
>  
> > +libxl_device_usb * 
> > +libxl_device_usb_assignable_list(libxl_ctx *ctx, int *num) 
>  
> I'm a bit ambivalent about this one.  For people using xl, "lsusb" 
> should be just fine.  Is anyone building a toolstack on top of libxl 
> directly going to need this functionality?  Would libvirt use this 
> functionality, for instance, or would it use libusb?  Or just leave 
> that to the caller? 

This exists mainly because the proposed interface before using usb sysfs
interface rather than bus:addr, user has no much idea about which sysfs
interface is related to which usb device. Now if we decide to use bus:addr,
I agree this API could be removed. Just use lsusb. (But user should have this
knowledge in mind: a HUB could not be assigned to guest).

>  
>  
> > +static int libxl__device_usb_setdefault(libxl__gc *gc, uint32_t domid, 
> > +                                        libxl_device_usb *usb) 
> > +{ 
> > +    char *be_path, *tmp; 
> > + 
> > +    if (usb->ctrl == -1) { 
> > +        int ret = libxl__device_usb_set_default_usbctrl(gc, domid, usb); 
> > +        /* If no existing ctrl to host this usb device, setup a new one */ 
> > +        if (ret) { 
> > +            libxl_device_usbctrl usbctrl; 
> > +            libxl_device_usbctrl_init(&usbctrl); 
> > +            libxl__device_usbctrl_add(gc, domid, &usbctrl); 
>  
> What happens if this fails? 

Currently it will check usb port existence later, so if this fails, errors will be
reported in that step. But I think I'd better check the return value here to report
error earlier. Thank you.

- Chunyan

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

^ permalink raw reply	[flat|nested] 40+ messages in thread

end of thread, other threads:[~2015-03-20  9:37 UTC | newest]

Thread overview: 40+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-01-19  8:28 [PATCH RFC V2 0/5] pvusb toolstack work Chunyan Liu
2015-01-19  8:28 ` [PATCH RFC V2 1/5] libxl: add pvusb definitions Chunyan Liu
2015-03-03 11:10   ` Ian Campbell
2015-03-03 16:45     ` George Dunlap
2015-03-04  7:26     ` Chun Yan Liu
2015-03-04 10:00       ` Ian Campbell
2015-03-04 12:26         ` George Dunlap
2015-03-04 12:33           ` Ian Campbell
2015-03-05  5:04             ` Chun Yan Liu
2015-03-03 17:15   ` George Dunlap
2015-03-04  8:28     ` Chun Yan Liu
2015-03-04 14:41       ` George Dunlap
2015-03-05  6:07         ` Chun Yan Liu
2015-01-19  8:28 ` [PATCH RFC V2 2/5] libxl: export some functions for pvusb use Chunyan Liu
2015-03-03 11:10   ` Ian Campbell
2015-01-19  8:28 ` [PATCH RFC V2 3/5] libxl: add pvusb API Chunyan Liu
2015-01-28 15:54   ` Ian Campbell
2015-01-29  3:24     ` Chun Yan Liu
2015-02-10 10:08   ` Jürgen Groß
2015-02-10 16:01   ` Jürgen Groß
2015-03-03 11:38   ` Ian Campbell
2015-03-04  7:47     ` Chun Yan Liu
2015-03-06 16:50   ` George Dunlap
2015-03-09  9:39     ` Ian Campbell
2015-03-09 10:17       ` George Dunlap
2015-03-09 10:41         ` Ian Campbell
2015-03-20  9:37     ` Chun Yan Liu
2015-03-17 14:03   ` Juergen Gross
2015-01-19  8:28 ` [PATCH RFC V2 4/5] xl: add pvusb commands Chunyan Liu
2015-02-10  6:25   ` Jürgen Groß
2015-03-03 11:43   ` Ian Campbell
2015-03-04  7:48     ` Chun Yan Liu
2015-03-06 17:25   ` George Dunlap
2015-03-20  9:02     ` Chun Yan Liu
2015-01-19  8:28 ` [PATCH RFC V2 5/5] domcreate: support pvusb in configuration file Chunyan Liu
2015-03-03 11:44   ` Ian Campbell
2015-01-28 15:51 ` [PATCH RFC V2 0/5] pvusb toolstack work Ian Campbell
2015-01-28 16:07   ` Pasi Kärkkäinen
2015-01-28 16:17     ` Ian Campbell
2015-01-29  3:22   ` Chun Yan Liu

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.