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

Re: [Xen-devel] [PATCH V5 3/7] libxl: add pvusb API



As 4.6 goes to bug fixing stage, maybe we can pick up this thread? :-)

Beside to call for your precious review comments and suggestions so that we can
make progress, I also want to confirm about the previous discussed two TODO
things:
1) use UDEV name rule to specify usb device uniquely even across reboot. That
    got consensus. Next thing is exposing that name to some sysfs entry, right?
2) use libusb instead of reading sysfs by ourselves. As George mentioned, using
    libusb is not simpler than reading sysfs; and if UDEV name is stored to some
    sysfs entry for us to retrieve, then we still need reading sysfs things. 
Could we
    get to a final decision?
If these are settled down, I can update related code.

Thanks,
Chunyan

>>> On 7/7/2015 at 05:57 PM, in message <559BA270.4000006@xxxxxxxxxxxxx>, George
Dunlap <george.dunlap@xxxxxxxxxxxxx> wrote: 
> On 07/07/2015 02:25 AM, Chun Yan Liu wrote: 
> > Any comments on the implementation? If there is anything improper, I can  
> update. 
>  
> Since we decided to wait until the next release, I've been prioritizing 
> reviewing patch series which might make it into 4.6.  I'll come back to 
> it once the freeze starts. 
>  
> Believe me, I'd much rather be working on the USB stuff. :-) 
>  
>  -George 
>  
> >  
> > Thanks, 
> > Chunyan 
> >  
> >>>> On 6/25/2015 at 06:07 PM, in message 
> > <1435226838-3067-4-git-send-email-cyliu@xxxxxxxx>, Chunyan Liu 
> > <cyliu@xxxxxxxx> 
> > wrote:  
> >> Add pvusb APIs, including:  
> >>  - attach/detach (create/destroy) virtual usb controller.  
> >>  - attach/detach usb device  
> >>  - list usb controller and usb devices  
> >>  - some other helper functions  
> >>   
> >> Signed-off-by: Chunyan Liu <cyliu@xxxxxxxx>  
> >> Signed-off-by: Simon Cao <caobosimon@xxxxxxxxx>  
> >> ---  
> >> changes:  
> >>   - Use macros DEFINE_DEVICE_ADD and DEFINE_DEVICES_ADD for adding  
> >>     usbctrl and usb, update all related codes.  
> >>   - Use an extend macro DEFINE_DEVICE_REMOVE_EXT for removimg usbctrl 
> >>     update all related codes.  
> >>   - Remove busid from libxl_device_usb definition, keep bus.addr only,  
> >>     update all related codes.  
> >>   - Remove documentation since it's mostly about design, move to  
> >>     cover-letter. Some parts are moved to code comments.  
> >>   - Address some other comments  
> >>   
> >>  tools/libxl/Makefile                 |    2 +-  
> >>  tools/libxl/libxl.c                  |   53 ++  
> >>  tools/libxl/libxl.h                  |   64 ++  
> >>  tools/libxl/libxl_device.c           |    4 +  
> >>  tools/libxl/libxl_internal.h         |   20 +-  
> >>  tools/libxl/libxl_osdeps.h           |   13 +  
> >>  tools/libxl/libxl_pvusb.c            | 1305   
> >> ++++++++++++++++++++++++++++++++++  
> >>  tools/libxl/libxl_types.idl          |   50 ++  
> >>  tools/libxl/libxl_types_internal.idl |    1 +  
> >>  tools/libxl/libxl_utils.c            |   16 +  
> >>  tools/libxl/libxl_utils.h            |    5 +  
> >>  11 files changed, 1531 insertions(+), 2 deletions(-)  
> >>  create mode 100644 tools/libxl/libxl_pvusb.c  
> >>   
> >> diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile  
> >> index cc9c152..b820105 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_vnuma.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_pvusb.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 6570476..6542127 100644  
> >> --- a/tools/libxl/libxl.c  
> >> +++ b/tools/libxl/libxl.c  
> >> @@ -4233,11 +4233,54 @@ DEFINE_DEVICE_REMOVE(vtpm, destroy, 1)  
> >>    
> >>    
> >>  
> /**************************************************************************** 
>  
>  
> >> **/  
> >>    
> >> +/* Macro for defining device remove/destroy functions for usbctrl */  
> >> +/* Following functions are defined:  
> >> + * libxl_device_usbctrl_remove  
> >> + * libxl_device_usbctrl_destroy  
> >> + */  
> >> +  
> >> +#define DEFINE_DEVICE_REMOVE_EXT(type, removedestroy, f)                \ 
> >>  
> >> +    int libxl_device_##type##_##removedestroy(libxl_ctx *ctx,           \ 
> >>  
> >> +        uint32_t domid, libxl_device_##type *type,                      \ 
> >>  
> >> +        const libxl_asyncop_how *ao_how)                                \ 
> >>  
> >> +    {                                                                   \ 
> >>  
> >> +        AO_CREATE(ctx, domid, ao_how);                                  \ 
> >>  
> >> +        libxl__device *device;                                          \ 
> >>  
> >> +        libxl__ao_device *aodev;                                        \ 
> >>  
> >> +        int rc;                                                         \ 
> >>  
> >> +                                                                        \ 
> >>  
> >> +        GCNEW(device);                                                  \ 
> >>  
> >> +        rc = libxl__device_from_##type(gc, domid, type, device);        \ 
> >>  
> >> +        if (rc != 0) goto out;                                          \ 
> >>  
> >> +                                                                        \ 
> >>  
> >> +        GCNEW(aodev);                                                   \ 
> >>  
> >> +        libxl__prepare_ao_device(ao, aodev);                            \ 
> >>  
> >> +        aodev->action = LIBXL__DEVICE_ACTION_REMOVE;                    \ 
> >>  
> >> +        aodev->dev = device;                                            \ 
> >>  
> >> +        aodev->callback = device_addrm_aocomplete;                      \ 
> >>  
> >> +        aodev->force = f;                                               \ 
> >>  
> >> +        libxl__initiate_device_##type##_remove(egc, aodev);             \ 
> >>  
> >> +                                                                        \ 
> >>  
> >> +    out:                                                                \ 
> >>  
> >> +        if (rc) return AO_ABORT(rc);                                    \ 
> >>  
> >> +        return AO_INPROGRESS;                                           \ 
> >>  
> >> +    }  
> >> +  
> >> +  
> >> +DEFINE_DEVICE_REMOVE_EXT(usbctrl, remove, 0)  
> >> +DEFINE_DEVICE_REMOVE_EXT(usbctrl, destroy, 1)  
> >> +  
> >> +#undef DEFINE_DEVICE_REMOVE_EXT  
> >> +  
> >>  
> +/**************************************************************************  
> >> ****/  
> >> +  
> >>  /* Macro for defining device addition functions in a compact way */  
> >>  /* The following functions are defined:  
> >>   * libxl_device_disk_add  
> >>   * libxl_device_nic_add  
> >>   * libxl_device_vtpm_add  
> >> + * libxl_device_usbctrl_add  
> >> + * libxl_device_usb_add  
> >>   */  
> >>    
> >>  #define DEFINE_DEVICE_ADD(type)                                         \ 
> >>  
> >> @@ -4269,6 +4312,12 @@ DEFINE_DEVICE_ADD(nic)  
> >>  /* vtpm */  
> >>  DEFINE_DEVICE_ADD(vtpm)  
> >>    
> >> +/* usbctrl */  
> >> +DEFINE_DEVICE_ADD(usbctrl)  
> >> +  
> >> +/* usb */  
> >> +DEFINE_DEVICE_ADD(usb)  
> >> +  
> >>  #undef DEFINE_DEVICE_ADD  
> >>    
> >>    
> >>  
> /**************************************************************************** 
>  
>  
> >> **/  
> >> @@ -6770,6 +6819,10 @@ int libxl_retrieve_domain_configuration(libxl_ctx   
> >> *ctx, uint32_t domid,  
> >>    
> >>      MERGE(pci, pcidevs, COMPARE_PCI, {});  
> >>    
> >> +    MERGE(usbctrl, usbctrls, COMPARE_USBCTRL, {});  
> >> +  
> >> +    MERGE(usb, usbs, COMPARE_USB, {});  
> >> +  
> >>      /* Take care of removable device. We maintain invariant in the  
> >>       * insert / remove operation so that:  
> >>       * 1. if xenstore is "empty" while JSON is not, the result  
> >> diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h  
> >> index 0a7913b..6669835 100644  
> >> --- a/tools/libxl/libxl.h  
> >> +++ b/tools/libxl/libxl.h  
> >> @@ -123,6 +123,23 @@  
> >>  #define LIBXL_HAVE_DOMAIN_NODEAFFINITY 1  
> >>    
> >>  /*  
> >> + * LIBXL_HAVE_PVUSB indicates the functions for doing hot-plug of  
> >> + * USB devices through pvusb.  
> >> + *  
> >> + * With this functionality, one can add/remove USB controllers to/from  
> >> + * guest, and attach/detach USB devices to/from USB controllers. To add  
> >> + * USB controllers and USB devices, one can either adding USB controllers 
> >>  
> >> + * first and then attaching USB devices to some USB controller, or adding 
> >>  
> >> + * USB devices to guest directly, it will automatically create a USB  
> >> + * controller for USB devices to attach. To remove USB controllers or USB 
> >>  
> >> + * devices, one can either remove USB devices under USB controller one by 
> >>  
> >> + * one and then remove USB controller, or remove USB controller directly, 
> >>  
> >> + * it will remove all USB devices under it automatically.  
> >> + *  
> >> + */  
> >> +#define LIBXL_HAVE_PVUSB 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  
> >> @@ -1269,6 +1286,53 @@ 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);  
> >> +  
> >> +void libxl_device_usbctrl_list_free(libxl_device_usbctrl* list, int nr);  
> >> +  
> >> +  
> >> +int libxl_device_usbctrl_getinfo(libxl_ctx *ctx, uint32_t domid,  
> >> +                                libxl_device_usbctrl *usbctrl,  
> >> +                                libxl_usbctrlinfo *usbctrlinfo);  
> >> +  
> >> +/* 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;  
> >> +  
> >> +libxl_device_usb *  
> >> +libxl_device_usb_list(libxl_ctx *ctx, uint32_t domid, int *num);  
> >> +  
> >> +libxl_device_usb *  
> >> +libxl_device_usb_list_per_usbctrl(libxl_ctx *ctx, uint32_t domid,  
> >> +                                  libxl_devid usbctrl, int *num);  
> >> +  
> >> +void libxl_device_usb_list_free(libxl_device_usb* list, int nr);  
> >> +  
> >> +int libxl_device_usb_getinfo(libxl_ctx *ctx, libxl_device_usb *usb,  
> >> +                             libxl_usbinfo *usbinfo);  
> >> +  
> >>  /* Network Interfaces */  
> >>  int libxl_device_nic_add(libxl_ctx *ctx, uint32_t domid, libxl_device_nic 
> >>   
>  
> >> *nic,  
> >>                           const libxl_asyncop_how *ao_how)  
> >> diff --git a/tools/libxl/libxl_device.c b/tools/libxl/libxl_device.c  
> >> index 93bb41e..9869a21 100644  
> >> --- a/tools/libxl/libxl_device.c  
> >> +++ b/tools/libxl/libxl_device.c  
> >> @@ -676,6 +676,10 @@ void libxl__devices_destroy(libxl__egc *egc,   
> >> libxl__devices_remove_state *drs)  
> >>                  aodev->action = LIBXL__DEVICE_ACTION_REMOVE;  
> >>                  aodev->dev = dev;  
> >>                  aodev->force = drs->force;  
> >> +                if (dev->backend_kind == LIBXL__DEVICE_KIND_VUSB) {  
> >> +                    libxl__initiate_device_usbctrl_remove(egc, aodev);  
> >> +                    continue;  
> >> +                }  
> >>                  libxl__initiate_device_remove(egc, aodev);  
> >>              }  
> >>          }  
> >> diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h  
> >> index 0965e08..6a8d4ee 100644  
> >> --- a/tools/libxl/libxl_internal.h  
> >> +++ b/tools/libxl/libxl_internal.h  
> >> @@ -2438,6 +2438,14 @@ _hidden void libxl__device_vtpm_add(libxl__egc 
> >> *egc,   
>  
> >> uint32_t domid,  
> >>                                     libxl_device_vtpm *vtpm,  
> >>                                     libxl__ao_device *aodev);  
> >>    
> >> +_hidden void libxl__device_usbctrl_add(libxl__egc *egc, uint32_t domid,  
> >> +                               libxl_device_usbctrl *usbctrl,  
> >> +                               libxl__ao_device *aodev);  
> >> +  
> >> +_hidden void libxl__device_usb_add(libxl__egc *egc, uint32_t domid,  
> >> +                                   libxl_device_usb *usb,  
> >> +                                   libxl__ao_device *aodev);  
> >> +  
> >>  /* Internal function to connect a vkb device */  
> >>  _hidden int libxl__device_vkb_add(libxl__gc *gc, uint32_t domid,  
> >>                                    libxl_device_vkb *vkb);  
> >> @@ -2470,6 +2478,13 @@ _hidden void   
> >> libxl__wait_device_connection(libxl__egc*,  
> >>  _hidden void libxl__initiate_device_remove(libxl__egc *egc,  
> >>                                             libxl__ao_device *aodev);  
> >>    
> >> +_hidden int libxl__device_from_usbctrl(libxl__gc *gc, uint32_t domid,  
> >> +                               libxl_device_usbctrl *usbctrl,  
> >> +                               libxl__device *device);  
> >> +  
> >> +_hidden void libxl__initiate_device_usbctrl_remove(libxl__egc *egc,  
> >> +                                                   libxl__ao_device   
> >> *aodev);  
> >> +  
> >>  /*  
> >>   * libxl__get_hotplug_script_info returns the args and env that should  
> >>   * be passed to the hotplug script for the requested device.  
> >> @@ -3645,7 +3660,10 @@ 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) ((a)->hostbus == (b)->hostbus &&  \  
> >> +                           (a)->hostaddr == (b)->hostaddr)  
> >> +#define COMPARE_USBCTRL(a, b) ((a)->devid == (b)->devid)  
> >> +   
> >>  /* DEVICE_ADD  
> >>   *  
> >>   * Add a device in libxl_domain_config structure  
> >> diff --git a/tools/libxl/libxl_osdeps.h b/tools/libxl/libxl_osdeps.h  
> >> index 08eaf0c..55caf71 100644  
> >> --- a/tools/libxl/libxl_osdeps.h  
> >> +++ b/tools/libxl/libxl_osdeps.h  
> >> @@ -24,6 +24,8 @@  
> >>  #define _GNU_SOURCE  
> >>    
> >>  #if defined(__NetBSD__)  
> >> +#define SYSFS_USB_DEV          "/sys/bus/usb/devices"  
> >> +#define SYSFS_USBBACK_DRIVER   "/kern/xen/usb"  
> >>  #define SYSFS_PCI_DEV          "/sys/bus/pci/devices"  
> >>  #define SYSFS_PCIBACK_DRIVER   "/kern/xen/pci"  
> >>  #define NETBACK_NIC_NAME       "xvif%ui%d"  
> >> @@ -31,6 +33,8 @@  
> >>  #elif defined(__OpenBSD__)  
> >>  #include <util.h>  
> >>  #elif defined(__linux__)  
> >> +#define SYSFS_USB_DEV          "/sys/bus/usb/devices"  
> >> +#define SYSFS_USBBACK_DRIVER   "/sys/bus/usb/drivers/usbback"  
> >>  #define SYSFS_PCI_DEV          "/sys/bus/pci/devices"  
> >>  #define SYSFS_PCIBACK_DRIVER   "/sys/bus/pci/drivers/pciback"  
> >>  #define NETBACK_NIC_NAME       "vif%u.%d"  
> >> @@ -38,12 +42,21 @@  
> >>  #elif defined(__sun__)  
> >>  #include <stropts.h>  
> >>  #elif defined(__FreeBSD__)  
> >> +#define SYSFS_USB_DEV          "/dev/null"  
> >> +#define SYSFS_USBBACK_DRIVER   "/dev/null"  
> >>  #define SYSFS_PCI_DEV          "/dev/null"  
> >>  #define SYSFS_PCIBACK_DRIVER   "/dev/null"  
> >>  #define NETBACK_NIC_NAME       "xnb%u.%d"  
> >>  #include <libutil.h>  
> >>  #endif  
> >>    
> >> +#ifndef SYSFS_USBBACK_DRIVER  
> >> +#error define SYSFS_USBBACK_DRIVER for your platform  
> >> +#endif  
> >> +#ifndef SYSFS_USB_DEV  
> >> +#error define SYSFS_USB_DEV for your platform  
> >> +#endif  
> >> +  
> >>  #ifndef SYSFS_PCIBACK_DRIVER  
> >>  #error define SYSFS_PCIBACK_DRIVER for your platform  
> >>  #endif  
> >> diff --git a/tools/libxl/libxl_pvusb.c b/tools/libxl/libxl_pvusb.c  
> >> new file mode 100644  
> >> index 0000000..d8cacd4  
> >> --- /dev/null  
> >> +++ b/tools/libxl/libxl_pvusb.c  
> >> @@ -0,0 +1,1305 @@  
> >> +/*  
> >> + * 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 USBBACK_INFO_PATH "/libxl/usbback"  
> >> +  
> >> +#define USBHUB_CLASS_CODE 0x09  
> >> +  
> >> +/* Utility to read backend xenstore keys */  
> >> +#define READ_BACKEND(tgc, subpath)                                    \  
> >> +            libxl__xs_read(tgc, XBT_NULL, GCSPRINTF("%s/" subpath,   
> >> be_path))  
> >> +  
> >> +/* Utility to read frontend xenstore keys */  
> >> +#define READ_FRONTEND(tgc, subpath)                                   \  
> >> +            libxl__xs_read(tgc, XBT_NULL, GCSPRINTF("%s/" subpath,   
> >> fe_path))  
> >> +  
> >> +static int libxl__device_usbctrl_setdefault(libxl__gc *gc, uint32_t 
> >> domid,  
>  
> >> +                                            libxl_device_usbctrl 
> >> *usbctrl)  
>  
> >> +{  
> >> +    int rc;  
> >> +  
> >> +    if (!usbctrl->version)  
> >> +        usbctrl->version = 2;  
> >> +  
> >> +    if (!usbctrl->ports)  
> >> +        usbctrl->ports = 8;  
> >> +  
> >> +    if (usbctrl->protocol == LIBXL_USB_PROTOCOL_AUTO)  
> >> +        usbctrl->protocol = LIBXL_USB_PROTOCOL_PV;  
> >> +  
> >> +    rc = libxl__resolve_domid(gc, usbctrl->backend_domname,  
> >> +                              &usbctrl->backend_domid);  
> >> +    return rc;  
> >> +}  
> >> +  
> >> +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;  
> >> +}  
> >> +  
> >> +/* Add usbctrl information to xenstore.  
> >> + *  
> >> + * Adding a usb controller will add a new 'vusb' device in xenstore, and  
> >> + * add corresponding frontend, backend information to it. According to  
> >> + * "update_json", decide wether to update json config file.  
> >> + */  
> >> +static int libxl__device_usbctrl_add_xenstore(libxl__gc *gc, uint32_t   
> >> domid,  
> >> +                                              libxl_device_usbctrl   
> >> *usbctrl,  
> >> +                                              bool update_json)  
> >> +{  
> >> +    libxl__device *device;  
> >> +    flexarray_t *front;  
> >> +    flexarray_t *back;  
> >> +    xs_transaction_t t = XBT_NULL;  
> >> +    int i, rc;  
> >> +    libxl_domain_config d_config;  
> >> +    libxl_device_usbctrl usbctrl_saved;  
> >> +    libxl__domain_userdata_lock *lock = NULL;  
> >> +  
> >> +    libxl_domain_config_init(&d_config);  
> >> +    libxl_device_usbctrl_init(&usbctrl_saved);  
> >> +    libxl_device_usbctrl_copy(CTX, &usbctrl_saved, usbctrl);  
> >> +  
> >> +    GCNEW(device);  
> >> +    rc = libxl__device_from_usbctrl(gc, domid, usbctrl, device);  
> >> +    if (rc) goto out;  
> >> +  
> >> +    front = flexarray_make(gc, 4, 1);  
> >> +    back = flexarray_make(gc, 12, 1);  
> >> +  
> >> +    flexarray_append_pair(back, "frontend-id", GCSPRINTF("%d", domid));  
> >> +    flexarray_append_pair(back, "online", "1");  
> >> +    flexarray_append_pair(back, "state", "1");  
> >> +    flexarray_append_pair(back, "type",  
> >> +                    (char  
> *)libxl_usb_protocol_to_string(usbctrl->protocol));  
> >> +    flexarray_append_pair(back, "usb-ver", GCSPRINTF("%d",  
> usbctrl->version));  
> >> +    flexarray_append_pair(back, "num-ports", GCSPRINTF("%d",  
> usbctrl->ports));  
> >> +    flexarray_append_pair(back, "port", "");  
> >> +    for (i = 0; i < usbctrl->ports; i++)  
> >> +        flexarray_append_pair(back, GCSPRINTF("port/%d", i + 1), "");  
> >> +  
> >> +    flexarray_append_pair(front, "backend-id",  
> >> +                          GCSPRINTF("%d", usbctrl->backend_domid));  
> >> +    flexarray_append_pair(front, "state", "1");  
> >> +  
> >> +    if (update_json) {  
> >> +        lock = libxl__lock_domain_userdata(gc, domid);  
> >> +        if (!lock) {  
> >> +            rc = ERROR_LOCK_FAIL;  
> >> +            goto out;  
> >> +        }  
> >> +  
> >> +        rc = libxl__get_domain_configuration(gc, domid, &d_config);  
> >> +        if (rc) goto out;  
> >> +  
> >> +        DEVICE_ADD(usbctrl, usbctrls, domid, &usbctrl_saved,  
> >> +                   COMPARE_USBCTRL, &d_config);  
> >> +    }  
> >> +  
> >> +    for (;;) {  
> >> +        rc = libxl__xs_transaction_start(gc, &t);  
> >> +        if (rc) goto out;  
> >> +  
> >> +        rc = libxl__device_exists(gc, t, device);  
> >> +        if (rc < 0) goto out;  
> >> +        if (rc == 1) {  
> >> +            /* already exists in xenstore */  
> >> +            LOG(ERROR, "device already exists in xenstore");  
> >> +            rc = ERROR_DEVICE_EXISTS;  
> >> +            goto out;  
> >> +        }  
> >> +  
> >> +        if (update_json) {  
> >> +            rc = libxl__set_domain_configuration(gc, domid, &d_config);  
> >> +            if (rc) goto out;  
> >> +        }  
> >> +  
> >> +        libxl__device_generic_add(gc, t, device,  
> >> +                          libxl__xs_kvs_of_flexarray(gc, back, 
> >> back->count),  
>  
> >> +                          libxl__xs_kvs_of_flexarray(gc, front,   
> >> front->count),  
> >> +                          NULL);  
> >> +  
> >> +        rc = libxl__xs_transaction_commit(gc, &t);  
> >> +        if (!rc) break;  
> >> +        if (rc < 0) goto out;  
> >> +    }  
> >> +  
> >> +out:  
> >> +    libxl__xs_transaction_abort(gc, &t);  
> >> +    if (lock) libxl__unlock_domain_userdata(lock);  
> >> +    libxl_device_usbctrl_dispose(&usbctrl_saved);  
> >> +    libxl_domain_config_dispose(&d_config);  
> >> +    return rc;  
> >> +}  
> >> +  
> >> +/* AO operation to add a usb controller.  
> >> + *  
> >> + * Generally, it does:  
> >> + * 1) fill in necessary usb controler information with default value  
> >> + * 2) write usb controller frontend/backend info to xenstore, update json 
> >>  
> >> + *    config file if necessary.  
> >> + * 3) wait for device connection. PVUSB frontend and backend driver will  
> >> + *    probe xenstore paths and build connection between frontend and   
> >> backend.  
> >> + */  
> >> +void libxl__device_usbctrl_add(libxl__egc *egc, uint32_t domid,  
> >> +                               libxl_device_usbctrl *usbctrl,  
> >> +                               libxl__ao_device *aodev)  
> >> +{  
> >> +    STATE_AO_GC(aodev->ao);  
> >> +    libxl__device *device;  
> >> +    int rc;  
> >> +  
> >> +    rc = libxl__device_usbctrl_setdefault(gc, domid, usbctrl);  
> >> +    if (rc < 0) goto out;  
> >> +  
> >> +    if (usbctrl->devid == -1) {  
> >> +        usbctrl->devid = libxl__device_nextid(gc, domid, "vusb");  
> >> +        if (usbctrl->devid < 0) {  
> >> +            rc = ERROR_FAIL;  
> >> +            goto out;  
> >> +        }  
> >> +    }  
> >> +  
> >> +    rc = libxl__device_usbctrl_add_xenstore(gc, domid, usbctrl,  
> >> +                                            aodev->update_json);  
> >> +    if (rc) goto out;  
> >> +  
> >> +    GCNEW(device);  
> >> +    rc = libxl__device_from_usbctrl(gc, domid, usbctrl, device);  
> >> +    if (rc) goto out;  
> >> +  
> >> +    aodev->dev = device;  
> >> +    aodev->action = LIBXL__DEVICE_ACTION_ADD;  
> >> +    libxl__wait_device_connection(egc, aodev);  
> >> +  
> >> +    rc = 0;  
> >> +  
> >> +out:  
> >> +    aodev->rc = rc;  
> >> +    if (rc) aodev->callback(egc, aodev);  
> >> +    return;  
> >> +}  
> >> +  
> >> +static int  
> >> +libxl__device_usb_list_per_usbctrl(libxl__gc *gc, uint32_t domid,  
> >> +                                   libxl_devid usbctrl,  
> >> +                                   libxl_device_usb **usbs, int *num);  
> >> +  
> >> +static int  
> >> +libxl__device_usb_remove(libxl__gc *gc, uint32_t domid, libxl_device_usb  
> >>  
> >> *usb);  
> >> +  
> >> +int libxl_devid_to_device_usbctrl(libxl_ctx *ctx,  
> >> +                                  uint32_t domid,  
> >> +                                  int devid,  
> >> +                                  libxl_device_usbctrl *usbctrl)  
> >> +{  
> >> +    GC_INIT(ctx);  
> >> +    libxl_device_usbctrl *usbctrls;  
> >> +    int nb = 0;  
> >> +    int i, rc = -1;  
> >> +  
> >> +    usbctrls = libxl_device_usbctrl_list(ctx, domid, &nb);  
> >> +    if (!nb) goto out;  
> >> +  
> >> +    libxl_device_usbctrl_init(usbctrl);  
> >> +    for (i = 0; i < nb; i++) {  
> >> +        if (devid == usbctrls[i].devid) {  
> >> +            *usbctrl = usbctrls[i];  
> >> +            rc = 0;  
> >> +            break;  
> >> +        }  
> >> +    }  
> >> +  
> >> +    libxl_device_usbctrl_list_free(usbctrls, nb);  
> >> +  
> >> +out:  
> >> +    GC_FREE;  
> >> +    return rc;  
> >> +}  
> >> +  
> >> +/* AO function to remove a usb controller.  
> >> + *  
> >> + * Generally, it does:  
> >> + * 1) check if the usb controller exists or not  
> >> + * 2) remove all usb devices under controller  
> >> + * 3) remove usb controller information from xenstore  
> >> + */  
> >> +void libxl__initiate_device_usbctrl_remove(libxl__egc *egc,  
> >> +                                           libxl__ao_device *aodev)  
> >> +{  
> >> +    STATE_AO_GC(aodev->ao);  
> >> +    libxl_device_usb *usbs = NULL;  
> >> +    int numusb = 0;  
> >> +    int i, rc;  
> >> +    uint32_t domid = ao->domid;  
> >> +    int usbctrl_devid = aodev->dev->devid;  
> >> +  
> >> +    /* Remove usb devices first */  
> >> +    rc  = libxl__device_usb_list_per_usbctrl(gc, domid, usbctrl_devid,  
> >> +                                             &usbs, &numusb);  
> >> +    if (rc) goto out;  
> >> +  
> >> +    for (i = 0; i < numusb; i++) {  
> >> +        if (libxl__device_usb_remove(gc, domid, &usbs[i])) {  
> >> +            LOG(ERROR, "libxl__device_usb_remove failed");  
> >> +            rc = ERROR_FAIL;  
> >> +            goto out;  
> >> +        }  
> >> +    }  
> >> +  
> >> +    libxl_device_usb_list_free(usbs, numusb);  
> >> +  
> >> +    /* Remove usbctrl */  
> >> +    return libxl__initiate_device_remove(egc, aodev);  
> >> +  
> >> +out:  
> >> +    libxl_device_usb_list_free(usbs, numusb);  
> >> +    aodev->rc = rc;  
> >> +    if (rc) aodev->callback(egc, aodev);  
> >> +    return;  
> >> +}  
> >> +  
> >> +libxl_device_usbctrl *  
> >> +libxl_device_usbctrl_list(libxl_ctx *ctx, uint32_t domid, int *num)  
> >> +{  
> >> +    GC_INIT(ctx);  
> >> +    libxl_device_usbctrl *usbctrls = NULL;  
> >> +    char *path = NULL;  
> >> +    char **dir = NULL;  
> >> +    unsigned int ndirs = 0;  
> >> +  
> >> +    *num = 0;  
> >> +  
> >> +    path = GCSPRINTF("%s/device/vusb",  
> >> +                     libxl__xs_get_dompath(gc, domid));  
> >> +    dir = libxl__xs_directory(gc, XBT_NULL, path, &ndirs);  
> >> +  
> >> +    if (dir && ndirs) {  
> >> +        usbctrls = libxl__zalloc(NOGC, sizeof(*usbctrls) * ndirs);  
> >> +        libxl_device_usbctrl* usbctrl;  
> >> +        libxl_device_usbctrl* end = usbctrls + ndirs;  
> >> +        for (usbctrl = usbctrls; usbctrl < end; usbctrl++, dir++, 
> >> (*num)++)  
>   
> >> {  
> >> +            const char *tmp, *be_path;  
> >> +            const char *fe_path = GCSPRINTF("%s/%s", path, *dir);  
> >> +  
> >> +            libxl_device_usbctrl_init(usbctrl);  
> >> +            usbctrl->devid = atoi(*dir);  
> >> +  
> >> +            be_path = READ_FRONTEND(gc, "backend");  
> >> +            if (!be_path) goto outerr;  
> >> +  
> >> +            tmp = READ_FRONTEND(gc, "backend-id");  
> >> +            if (!tmp) goto outerr;  
> >> +            usbctrl->backend_domid = atoi(tmp);  
> >> +  
> >> +            tmp = READ_BACKEND(gc, "usb-ver");  
> >> +            if (!tmp) goto outerr;  
> >> +            usbctrl->version = atoi(tmp);  
> >> +  
> >> +            tmp = READ_BACKEND(gc, "num-ports");  
> >> +            if (!tmp) goto outerr;  
> >> +            usbctrl->ports = atoi(tmp);  
> >> +  
> >> +            tmp = READ_BACKEND(gc, "type");  
> >> +            if (!tmp) goto outerr;  
> >> +            libxl_usb_protocol_from_string(tmp, &usbctrl->protocol);  
> >> +        }  
> >> +    }  
> >> +  
> >> +    goto out;  
> >> +  
> >> +outerr:  
> >> +    LOG(ERROR, "Unable to list USB Controllers");  
> >> +    libxl_device_usbctrl_list_free(usbctrls, *num);  
> >> +    *num = 0;  
> >> +    usbctrls = NULL;  
> >> +  
> >> +out:  
> >> +    GC_FREE;  
> >> +    return usbctrls;  
> >> +}  
> >> +  
> >> +int libxl_device_usbctrl_getinfo(libxl_ctx *ctx, uint32_t domid,  
> >> +                                libxl_device_usbctrl *usbctrl,  
> >> +                                libxl_usbctrlinfo *usbctrlinfo)  
> >> +{  
> >> +    GC_INIT(ctx);  
> >> +    char *dompath;  
> >> +    const char *fe_path, *be_path, *tmp;  
> >> +    int rc = 0;  
> >> +  
> >> +    usbctrlinfo->devid = usbctrl->devid;  
> >> +  
> >> +    dompath = libxl__xs_get_dompath(gc, domid);  
> >> +    fe_path = GCSPRINTF("%s/device/vusb/%d", dompath, 
> >> usbctrlinfo->devid);  
> >> +    be_path = READ_FRONTEND(gc, "backend");  
> >> +    if (!be_path) {  
> >> +        rc = ERROR_FAIL;  
> >> +        goto out;  
> >> +    }  
> >> +    usbctrlinfo->backend = libxl__strdup(NOGC, be_path);  
> >> +  
> >> +    tmp = READ_FRONTEND(gc, "backend-id");  
> >> +    usbctrlinfo->backend_id = tmp ? strtoul(tmp, NULL, 10) : -1;  
> >> +  
> >> +    tmp = READ_FRONTEND(gc, "state");  
> >> +    usbctrlinfo->state = tmp ? strtoul(tmp, NULL, 10) : -1;  
> >> +  
> >> +    tmp = READ_FRONTEND(gc, "event-channel");  
> >> +    usbctrlinfo->evtch = tmp ? strtoul(tmp, NULL, 10) : -1;  
> >> +  
> >> +    tmp = READ_FRONTEND(gc, "urb-ring-ref");  
> >> +    usbctrlinfo->ref_urb = tmp ? strtoul(tmp, NULL, 10) : -1;  
> >> +  
> >> +    tmp = READ_FRONTEND(gc, "conn-ring-ref");  
> >> +    usbctrlinfo->ref_conn= tmp ? strtoul(tmp, NULL, 10) : -1;  
> >> +  
> >> +    tmp = READ_BACKEND(gc, "frontend");  
> >> +    usbctrlinfo->frontend = libxl__strdup(NOGC, tmp);  
> >> +  
> >> +    tmp = READ_BACKEND(gc, "frontend-id");  
> >> +    usbctrlinfo->frontend_id = tmp ? strtoul(tmp, NULL, 10) : -1;  
> >> +  
> >> +    tmp = READ_BACKEND(gc, "num-ports");  
> >> +    usbctrlinfo->ports = tmp ? strtoul(tmp, NULL, 10) : -1;  
> >> +  
> >> +    tmp = READ_BACKEND(gc, "usb-ver");  
> >> +    usbctrlinfo->version = tmp ? strtoul(tmp, NULL, 10) : -1;  
> >> +  
> >> +    tmp = READ_BACKEND(gc, "type");  
> >> +    libxl_usb_protocol_from_string(tmp, &usbctrlinfo->protocol);  
> >> +  
> >> +out:  
> >> +    GC_FREE;  
> >> +    return rc;  
> >> +}  
> >> +  
> >> +static char *usb_busaddr_to_busid(libxl__gc *gc, int bus, int addr)  
> >> +{  
> >> +    libxl_ctx *ctx = CTX;  
> >> +    struct dirent *de;  
> >> +    DIR *dir;  
> >> +    char *busid = NULL;  
> >> +  
> >> +    assert(bus > 0 && addr > 0);  
> >> +  
> >> +    if (!(dir = opendir(SYSFS_USB_DEV)))  
> >> +        return NULL;  
> >> +  
> >> +    while((de = readdir(dir))) {  
> >> +        char *filename;  
> >> +        void *buf;  
> >> +        int busnum = -1;  
> >> +        int devnum = -1;  
> >> +  
> >> +        if (!de->d_name)  
> >> +            continue;  
> >> +  
> >> +        filename = GCSPRINTF(SYSFS_USB_DEV"/%s/devnum", de->d_name);  
> >> +        if (!libxl_read_sysfs_file_contents(ctx, filename, &buf, NULL))  
> >> +            sscanf(buf, "%x", &devnum);  
> >> +  
> >> +        filename = GCSPRINTF(SYSFS_USB_DEV"/%s/busnum", de->d_name);  
> >> +        if (!libxl_read_sysfs_file_contents(ctx, filename, &buf, NULL))  
> >> +            sscanf(buf, "%x", &busnum);  
> >> +  
> >> +        if (bus == busnum && addr == devnum) {  
> >> +            busid = libxl__strdup(NOGC, de->d_name);  
> >> +            break;  
> >> +        }  
> >> +    }  
> >> +  
> >> +    closedir(dir);  
> >> +    return busid;  
> >> +}  
> >> +  
> >> +static void usb_busaddr_from_busid(libxl__gc *gc, char *busid,  
> >> +                                   int *bus, int *addr)  
> >> +{  
> >> +    libxl_ctx *ctx = CTX;  
> >> +    char *filename;  
> >> +    void *buf;  
> >> +  
> >> +    assert(busid);  
> >> +  
> >> +    filename = GCSPRINTF(SYSFS_USB_DEV"/%s/busnum", busid);  
> >> +    if (!libxl_read_sysfs_file_contents(ctx, filename, &buf, NULL))  
> >> +        sscanf(buf, "%x", bus);  
> >> +  
> >> +    filename = GCSPRINTF(SYSFS_USB_DEV"/%s/devnum", busid);  
> >> +    if (!libxl_read_sysfs_file_contents(ctx, filename, &buf, NULL))  
> >> +        sscanf(buf, "%x", addr);  
> >> +}  
> >> +  
> >> +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 = GCSPRINTF("/local/domain/%d/backend/vusb",   
> >> LIBXL_TOOLSTACK_DOMID);  
> >> +    for (i = 0; i < nd; i++) {  
> >> +        char *path, *num_ports, **ctrl_list;  
> >> +        unsigned int nc = 0;  
> >> +        path = GCSPRINTF("%s/%s", be_path, domlist[i]);  
> >> +        ctrl_list = libxl__xs_directory(gc, XBT_NULL, path , &nc);  
> >> +  
> >> +        for (j = 0; j < nc; j++) {  
> >> +            path = GCSPRINTF("%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, *busid;  
> >> +  
> >> +                for (k = 0; k < nport; k++) {  
> >> +                    devpath = GCSPRINTF("%s/%s/%s/port/%u", be_path,  
> >> +                                        domlist[i], ctrl_list[j], k + 1); 
> >>  
> >> +                    busid = libxl__xs_read(gc, XBT_NULL, devpath);  
> >> +                    /* If there are USB device attached, add it to list 
> >> */  
>  
> >> +                    if (busid && strcmp(busid, "")) {  
> >> +                        GCREALLOC_ARRAY(*list, *num + 1);  
> >> +                        usb = *list + *num;  
> >> +                        usb->ctrl = atoi(ctrl_list[j]);  
> >> +                        usb->port = k + 1;  
> >> +                        usb_busaddr_from_busid(gc, busid,  
> >> +                                               &usb->hostbus, 
> >> &usb->hostaddr);  
> >> +                        (*num)++;  
> >> +                    }  
> >> +                }  
> >> +            }  
> >> +        }  
> >> +    }  
> >> +  
> >> +    return 0;  
> >> +}  
> >> +  
> >> +static bool is_usb_in_array(libxl_device_usb *usbs, int num,  
> >> +                            libxl_device_usb *usb)  
> >> +{  
> >> +    int i;  
> >> +  
> >> +    for (i = 0; i < num; i++) {  
> >> +        if (COMPARE_USB(&usbs[i], usb))  
> >> +            return true;  
> >> +    }  
> >> +  
> >> +    return false;  
> >> +}  
> >> +  
> >> +/* check if USB device is already assigned to a domain */  
> >> +static bool is_usb_assigned(libxl__gc *gc, libxl_device_usb *usb)  
> >> +{  
> >> +    libxl_device_usb *usbs;  
> >> +    int rc, num;  
> >> +  
> >> +    rc = libxl__device_usb_assigned_list(gc, &usbs, &num);  
> >> +    if (rc) {  
> >> +        LOG(ERROR, "Fail to get assigned usb list");  
> >> +        return true;  
> >> +    }  
> >> +  
> >> +    return is_usb_in_array(usbs, num, usb);  
> >> +}  
> >> +  
> >> +/* check if USB device type is assignable */  
> >> +static bool is_usb_assignable(libxl__gc *gc, libxl_device_usb *usb)  
> >> +{  
> >> +    libxl_ctx *ctx = CTX;  
> >> +    int classcode;  
> >> +    char *filename;  
> >> +    void *buf = NULL;  
> >> +    char *busid = NULL;  
> >> +  
> >> +    assert(usb->hostbus > 0 && usb->hostaddr > 0);  
> >> +    busid = usb_busaddr_to_busid(gc, usb->hostbus, usb->hostaddr);  
> >> +  
> >> +    filename = GCSPRINTF(SYSFS_USB_DEV"/%s/bDeviceClass", busid);  
> >> +    if (libxl_read_sysfs_file_contents(ctx, filename, &buf, NULL))  
> >> +        return false;  
> >> +  
> >> +    sscanf(buf, "%x", &classcode);  
> >> +    return classcode != USBHUB_CLASS_CODE;  
> >> +}  
> >> +  
> >> +/* get usb devices under certain usb controller */  
> >> +static int  
> >> +libxl__device_usb_list_per_usbctrl(libxl__gc *gc, uint32_t domid,  
> >> +                                   libxl_devid usbctrl,  
> >> +                                   libxl_device_usb **usbs, int *num)  
> >> +{  
> >> +    char *be_path, *num_devs;  
> >> +    int n, i;  
> >> +  
> >> +    *usbs = NULL;  
> >> +    *num = 0;  
> >> +  
> >> +    be_path = GCSPRINTF("%s/backend/vusb/%d/%d",  
> >> +                        libxl__xs_get_dompath(gc, LIBXL_TOOLSTACK_DOMID), 
> >>  
> >> +                        domid, usbctrl);  
> >> +    num_devs = libxl__xs_read(gc, XBT_NULL,  
> >> +                              GCSPRINTF("%s/num-ports", be_path));  
> >> +    if (!num_devs)  
> >> +        return 0;  
> >> +  
> >> +    n = atoi(num_devs);  
> >> +    *usbs = libxl__calloc(NOGC, n, sizeof(libxl_device_usb));  
> >> +  
> >> +    for (i = 0; i < n; i++) {  
> >> +        char *busid;  
> >> +        libxl_device_usb *usb = NULL;  
> >> +  
> >> +        busid = libxl__xs_read(gc, XBT_NULL,  
> >> +                               GCSPRINTF("%s/port/%d", be_path, i + 1));  
> >> +        if (busid && strcmp(busid, "")) {  
> >> +            usb = *usbs + *num;  
> >> +            usb->ctrl = usbctrl;  
> >> +            usb->port = i + 1;  
> >> +            usb_busaddr_from_busid(gc, busid,  
> >> +                                   &usb->hostbus, &usb->hostaddr);  
> >> +            (*num)++;  
> >> +        }  
> >> +    }  
> >> +  
> >> +    return 0;  
> >> +}  
> >> +  
> >> +/* get all usb devices of the domain */  
> >> +static libxl_device_usb *  
> >> +libxl__device_usb_list(libxl__gc *gc, uint32_t domid, int *num)  
> >> +{  
> >> +    char **usbctrls;  
> >> +    unsigned int nd = 0, i, j;  
> >> +    char *be_path;  
> >> +    int rc;  
> >> +    libxl_device_usb *usbs = NULL;  
> >> +  
> >> +    *num = 0;  
> >> +  
> >> +    be_path = GCSPRINTF("/local/domain/%d/backend/vusb/%d",  
> >> +                        LIBXL_TOOLSTACK_DOMID, 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_per_usbctrl(gc, domid,  
> >> +                                                atoi(usbctrls[i]), &tmp,  
> >>  
> >> &nc);  
> >> +        if (!nc) continue;  
> >> +  
> >> +        usbs = libxl__realloc(NOGC, usbs, sizeof(*usbs) * (*num + nc));  
> >> +        for (j = 0; j < nc; j++) {  
> >> +            usbs[*num] = tmp[j];  
> >> +            (*num)++;  
> >> +        }  
> >> +        libxl_device_usb_list_free(tmp, nc);  
> >> +    }  
> >> +    return usbs;  
> >> +}  
> >> +  
> >> +libxl_device_usb *  
> >> +libxl_device_usb_list(libxl_ctx *ctx, uint32_t domid, int *num)  
> >> +{  
> >> +    GC_INIT(ctx);  
> >> +    libxl_device_usb *usbs = NULL;  
> >> +  
> >> +    usbs = libxl__device_usb_list(gc, domid, num);  
> >> +  
> >> +    GC_FREE;  
> >> +    return usbs;  
> >> +}  
> >> +  
> >> +libxl_device_usb *  
> >> +libxl_device_usb_list_per_usbctrl(libxl_ctx *ctx, uint32_t domid,  
> >> +                                  libxl_devid usbctrl, int *num)  
> >> +{  
> >> +    GC_INIT(ctx);  
> >> +    libxl_device_usb *usbs = NULL;  
> >> +  
> >> +    libxl__device_usb_list_per_usbctrl(gc, domid, usbctrl, &usbs, num);  
> >> +  
> >> +    GC_FREE;  
> >> +    return usbs;  
> >> +}  
> >> +  
> >> +/* 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 = NULL;  
> >> +    int numctrl = 0;  
> >> +    int 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++) {  
> >> +        for (j = 0; j < usbctrls[i].ports; j++) {  
> >> +            be_path = GCSPRINTF("%s/backend/vusb/%d/%d/port/%d",  
> >> +                                libxl__xs_get_dompath(gc,   
> >> LIBXL_TOOLSTACK_DOMID),  
> >> +                                domid, usbctrls[i].devid, j + 1);  
> >> +            tmp = libxl__xs_read(gc, XBT_NULL, be_path);  
> >> +            if (tmp && !strcmp(tmp, "")) {  
> >> +                usb->ctrl = usbctrls[i].devid;  
> >> +                usb->port = j + 1;  
> >> +                rc = 0;  
> >> +                break;  
> >> +            }  
> >> +        }  
> >> +    }  
> >> +  
> >> +out:  
> >> +    libxl_device_usbctrl_list_free(usbctrls, numctrl);  
> >> +    return rc;  
> >> +}  
> >> +  
> >> +/* Fill in usb information with default value.  
> >> + *  
> >> + * Generally, it does:  
> >> + * 1) if "controller" is not specified:  
> >> + *    - if "port" is not specified, try to find an available   
> >> controller:port,  
> >> + *      if found, use that; otherwise, create a new controller, use this  
> >> + *      controller and its first port  
> >> + *    - if "port" is specified, report error.  
> >> + * 2) if "controller" is specified, but port is not specified:  
> >> + *    try to find an available port under this controller, if found, use  
> >> + *    that, otherwise, report error.  
> >> + * 3) if both "controller" and "port" are specified:  
> >> + *    check the controller:port is available, if not, report error.  
> >> + */  
> >> +static int libxl__device_usb_setdefault(libxl__gc *gc, uint32_t domid,  
> >> +                                        libxl_device_usb *usb,  
> >> +                                        bool update_json)  
> >> +{  
> >> +    int rc = -1;  
> >> +    char *be_path, *tmp;  
> >> +  
> >> +    if (usb->ctrl == -1) {  
> >> +        if (usb->port) {  
> >> +            LOG(ERROR, "USB controller must be specified if you specify   
> >> port ID");  
> >> +            return ERROR_INVAL;  
> >> +        }  
> >> +  
> >> +        rc = libxl__device_usb_set_default_usbctrl(gc, domid, usb);  
> >> +        /* If no existing controller to host this usb device, add a new  
> one   
> >> */  
> >> +        if (rc) {  
> >> +            libxl_device_usbctrl *usbctrl;  
> >> +            GCNEW(usbctrl);  
> >> +            libxl_device_usbctrl_init(usbctrl);  
> >> +  
> >> +            rc = libxl__device_usbctrl_setdefault(gc, domid, usbctrl);  
> >> +            if (rc < 0) goto out;  
> >> +  
> >> +            if (usbctrl->devid == -1) {  
> >> +                usbctrl->devid = libxl__device_nextid(gc, domid, "vusb"); 
> >>  
> >> +                if (usbctrl->devid < 0) {  
> >> +                    goto out;  
> >> +                }  
> >> +            }  
> >> +  
> >> +            rc = libxl__device_usbctrl_add_xenstore(gc, domid, usbctrl,  
> >> +                                                    update_json);  
> >> +            if (rc) goto out;  
> >> +  
> >> +            usb->ctrl = usbctrl->devid;  
> >> +            usb->port = 1;  
> >> +        }  
> >> +    } else if (!usb->port) {  
> >> +        /* Valid port starts from 1. Choose port for us. */  
> >> +        int i, ports;  
> >> +  
> >> +        be_path = GCSPRINTF("%s/backend/vusb/%d/%d",  
> >> +                            libxl__xs_get_dompath(gc,   
> >> LIBXL_TOOLSTACK_DOMID),  
> >> +                            domid, usb->ctrl);  
> >> +        tmp = READ_BACKEND(gc, "num-ports");  
> >> +        ports = tmp ? atoi(tmp) : 0;  
> >> +        for (i = 0; i < ports; i++) {  
> >> +            tmp = libxl__xs_read(gc, XBT_NULL,  
> >> +                                 GCSPRINTF("%s/port/%d", be_path, i + 
> >> 1));  
>  
> >> +            if (tmp && !strcmp(tmp, "")) {  
> >> +                usb->port = i + 1;  
> >> +                break;  
> >> +            }  
> >> +        }  
> >> +  
> >> +        if (!usb->port) {  
> >> +            LOG(ERROR, "No available port under specified controller");  
> >> +            goto out;  
> >> +        }  
> >> +    } else {  
> >> +        be_path = GCSPRINTF("%s/backend/vusb/%d/%d/port/%d",  
> >> +                            libxl__xs_get_dompath(gc,   
> >> LIBXL_TOOLSTACK_DOMID),  
> >> +                            domid, 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");  
> >> +            goto out;  
> >> +        }  
> >> +    }  
> >> +  
> >> +    rc = 0;  
> >> +  
> >> +out:  
> >> +    return rc;  
> >> +}  
> >> +  
> >> +/* Add usb information to xenstore  
> >> + *  
> >> + * Adding a usb device won't create new 'vusb' device, but only write  
> >> + * the device busid to the controller:port in xenstore.  
> >> + */  
> >> +static int libxl__device_usb_add_xenstore(libxl__gc *gc, uint32_t domid,  
> >> +                                          libxl_device_usb *usb,  
> >> +                                          bool update_json)  
> >> +{  
> >> +    char *be_path;  
> >> +    char *busid;  
> >> +    int rc;  
> >> +    xs_transaction_t t = XBT_NULL;  
> >> +    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);  
> >> +  
> >> +    busid = usb_busaddr_to_busid(gc, usb->hostbus, usb->hostaddr);  
> >> +    if (!busid) {  
> >> +        LOG(DEBUG, "Fail to get busid of usb device");  
> >> +        goto out;  
> >> +    }  
> >> +  
> >> +    if (update_json) {  
> >> +        lock = libxl__lock_domain_userdata(gc, domid);  
> >> +        if (!lock) {  
> >> +            rc = ERROR_LOCK_FAIL;  
> >> +            goto out;  
> >> +        }  
> >> +  
> >> +        rc = libxl__get_domain_configuration(gc, domid, &d_config);  
> >> +        if (rc) goto out;  
> >> +  
> >> +        DEVICE_ADD(usb, usbs, domid, &usb_saved, COMPARE_USB, &d_config); 
> >>  
> >> +    }  
> >> +  
> >> +    for (;;) {  
> >> +        rc = libxl__xs_transaction_start(gc, &t);  
> >> +        if (rc) goto out;  
> >> +  
> >> +        if (update_json) {  
> >> +            rc = libxl__set_domain_configuration(gc, domid, &d_config);  
> >> +            if (rc) goto out;  
> >> +        }  
> >> +  
> >> +        be_path = GCSPRINTF("%s/backend/vusb/%d/%d/port/%d",  
> >> +                            libxl__xs_get_dompath(gc,   
> >> LIBXL_TOOLSTACK_DOMID),  
> >> +                            domid, usb->ctrl, usb->port);  
> >> +  
> >> +        LOG(DEBUG, "Adding new usb device to xenstore");  
> >> +        if (libxl__xs_write_checked(gc, t, be_path, busid))  
> >> +            goto out;  
> >> +  
> >> +        rc = libxl__xs_transaction_commit(gc, &t);  
> >> +        if (!rc) break;  
> >> +        if (rc < 0) goto out;  
> >> +    }  
> >> +  
> >> +    rc = 0;  
> >> +  
> >> +out:  
> >> +    if (lock) libxl__unlock_domain_userdata(lock);  
> >> +    libxl_device_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)  
> >> +{  
> >> +    char *be_path;  
> >> +  
> >> +    be_path = GCSPRINTF("%s/backend/vusb/%d/%d/port/%d",  
> >> +                        libxl__xs_get_dompath(gc, LIBXL_TOOLSTACK_DOMID), 
> >>  
> >> +                        domid, usb->ctrl, usb->port);  
> >> +    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, *spath, *dp = NULL;  
> >> +    int fd = -1;  
> >> +    int rc = 0;  
> >> +    struct stat st;  
> >> +  
> >> +    spath = GCSPRINTF(SYSFS_USB_DEV"/%s/driver", intf);  
> >> +    if (!lstat(spath, &st)) {  
> >> +        /* Find the canonical path to the driver. */  
> >> +        dp = libxl__zalloc(gc, PATH_MAX);  
> >> +        dp = realpath(spath, dp);  
> >> +  
> >> +        path = GCSPRINTF("%s/unbind", spath);  
> >> +        fd = open(path, O_WRONLY);  
> >> +        if (fd < 0)  
> >> +            return ERROR_FAIL;  
> >> +        rc = write(fd, intf, strlen(intf));  
> >> +        close(fd);  
> >> +        if (rc < 0)  
> >> +            return ERROR_FAIL;  
> >> +    }  
> >> +  
> >> +    if (drvpath)  
> >> +        *drvpath = dp;  
> >> +  
> >> +    return 0;  
> >> +}  
> >> +  
> >> +static int bind_usb_intf(libxl__gc *gc, char *intf, char *drvpath)  
> >> +{  
> >> +    char *path;  
> >> +    struct stat st;  
> >> +    int fd, rc = 0;  
> >> +  
> >> +    path = GCSPRINTF("%s/%s", drvpath, intf);  
> >> +    rc = lstat(path, &st);  
> >> +    /* already bind, return */  
> >> +    if (rc == 0)  
> >> +        return 0;  
> >> +  
> >> +    path = GCSPRINTF("%s/bind", drvpath);  
> >> +    fd = open(path, O_WRONLY);  
> >> +    if (fd < 0)  
> >> +        return ERROR_FAIL;  
> >> +  
> >> +    rc = write(fd, intf, strlen(intf));  
> >> +    close(fd);  
> >> +    if (rc < 0)  
> >> +        return ERROR_FAIL;  
> >> +  
> >> +    return 0;  
> >> +}  
> >> +  
> >> +/* Is usb interface bound to usbback? */  
> >> +static int usb_intf_is_assigned(libxl__gc *gc, char *intf)  
> >> +{  
> >> +    char *spath;  
> >> +    int rc;  
> >> +    struct stat st;  
> >> +  
> >> +    spath = GCSPRINTF(SYSFS_USBBACK_DRIVER"/%s", intf);  
> >> +    rc = lstat(spath, &st);  
> >> +  
> >> +    if (rc == 0)  
> >> +        return 1;  
> >> +    if (rc < 0 && errno == ENOENT)  
> >> +        return 0;  
> >> +    LOGE(ERROR, "Accessing %s", spath);  
> >> +    return -1;  
> >> +}  
> >> +  
> >> +static int usb_get_all_interfaces(libxl__gc *gc, libxl_device_usb *usb,  
> >> +                                  char ***intfs, int *num)  
> >> +{  
> >> +    DIR *dir;  
> >> +    struct dirent *entry;  
> >> +    char *buf;  
> >> +    char *busid;  
> >> +    int rc = 0;  
> >> +  
> >> +    *intfs = NULL;  
> >> +    *num = 0;  
> >> +  
> >> +    busid = usb_busaddr_to_busid(gc, usb->hostbus, usb->hostaddr);  
> >> +    if (!busid) {  
> >> +        rc = ERROR_FAIL;  
> >> +        goto out;  
> >> +    }  
> >> +  
> >> +    buf = GCSPRINTF("%s:", busid);  
> >> +  
> >> +    if (!(dir = opendir(SYSFS_USB_DEV))) {  
> >> +        rc = ERROR_FAIL;  
> >> +        goto out;  
> >> +    }  
> >> +  
> >> +    while ((entry = readdir(dir)) != NULL) {  
> >> +        if (!strncmp(entry->d_name, buf, strlen(buf))) {  
> >> +            GCREALLOC_ARRAY(*intfs, *num + 1);  
> >> +            if (*intfs == NULL) {  
> >> +                rc = ERROR_FAIL;  
> >> +                goto out;  
> >> +            }  
> >> +            (*intfs)[*num] = libxl__strdup(gc, entry->d_name);  
> >> +            (*num)++;  
> >> +        }  
> >> +    }  
> >> +  
> >> +    closedir(dir);  
> >> +  
> >> +out:  
> >> +    return rc;  
> >> +}  
> >> +  
> >> +/* Encode usb interface so that it could be written to xenstore as a key. 
> >>  
> >> + *  
> >> + * Since xenstore key cannot include '.' or ':', we'll change '.' to '_', 
> >>  
> >> + * change ':' to '-'. For example, 3-1:2.1 will be encoded to 3-1-2_1.  
> >> + * This will be used to save original driver of USB device to xenstore.  
> >> + */  
> >> +static char *usb_interface_xenstore_encode(char *busid)  
> >> +{  
> >> +    char *str = strdup(busid);  
> >> +    int i, len = strlen(str);  
> >> +  
> >> +    for (i = 0; i < len; i++) {  
> >> +        if (str[i] == '.')  
> >> +            str[i] = '_';  
> >> +         if (str[i] == ':')  
> >> +            str[i] = '-';  
> >> +    }  
> >> +    return str;  
> >> +}  
> >> +  
> >> +/* Unbind USB device from "usbback" driver.  
> >> + *  
> >> + * If there are many interfaces under USB device, check each interface,  
> >> + * unbind from "usbback" driver and rebind to its original driver.  
> >> + */  
> >> +static int usbback_dev_unassign(libxl__gc *gc, libxl_device_usb *usb)  
> >> +{  
> >> +    char **intfs = NULL;  
> >> +    char *path;  
> >> +    int num = 0, i;  
> >> +    int rc = 0;  
> >> +    char *busid;  
> >> +    char *usb_encode = NULL;  
> >> +  
> >> +    if (usb_get_all_interfaces(gc, usb, &intfs, &num) < 0)  
> >> +        return ERROR_FAIL;  
> >> +  
> >> +    busid = usb_busaddr_to_busid(gc, usb->hostbus, usb->hostaddr);  
> >> +    usb_encode = usb_interface_xenstore_encode(busid);  
> >> +  
> >> +    for (i = 0; i < num; i++) {  
> >> +        char *intf = intfs[i];  
> >> +        char *drvpath = NULL;  
> >> +  
> >> +        /* check if the USB interface is already bound to "usbbcak" */  
> >> +        if (usb_intf_is_assigned(gc, intf) > 0) {  
> >> +            /* unbind interface from usbback driver */  
> >> +            if (unbind_usb_intf(gc, intf, NULL) < 0) {  
> >> +                rc = ERROR_FAIL;  
> >> +                goto out;  
> >> +            }  
> >> +        }  
> >> +  
> >> +        /* bind interface to its originial driver */  
> >> +        drvpath = libxl__xs_read(gc, XBT_NULL,  
> >> +                  GCSPRINTF(USBBACK_INFO_PATH"/%s/%s/driver_path",  
> >> +                  usb_encode, usb_interface_xenstore_encode(intf)));  
> >> +        if (drvpath && bind_usb_intf(gc, intf, drvpath))  
> >> +            LOGE(WARN, "Couldn't bind %s to %s", intf, drvpath);  
> >> +    }  
> >> +  
> >> +    /* finally, remove xs driver path */  
> >> +    path = GCSPRINTF(USBBACK_INFO_PATH"/%s", usb_encode);  
> >> +    libxl__xs_rm_checked(gc, XBT_NULL, path);  
> >> +  
> >> +out:  
> >> +    free(usb_encode);  
> >> +    return rc;  
> >> +}  
> >> +  
> >> +/* Bind USB device to "usbback" driver.  
> >> + *  
> >> + * If there are many interfaces under USB device, check each interface,  
> >> + * unbind from original driver and bind to "usbback" driver.  
> >> + */  
> >> +static int usbback_dev_assign(libxl__gc *gc, libxl_device_usb *usb)  
> >> +{  
> >> +    char **intfs = NULL;  
> >> +    int num = 0, i;  
> >> +    int rc = 0;  
> >> +    char *busid;  
> >> +    char *usb_encode = NULL;  
> >> +  
> >> +    if (usb_get_all_interfaces(gc, usb, &intfs, &num) < 0)  
> >> +        return ERROR_FAIL;  
> >> +  
> >> +    busid = usb_busaddr_to_busid(gc, usb->hostbus, usb->hostaddr);  
> >> +    usb_encode = usb_interface_xenstore_encode(busid);  
> >> +  
> >> +    for (i = 0; i < num; i++) {  
> >> +        char *intf = intfs[i];  
> >> +        char *path = NULL;  
> >> +        char *drvpath = NULL;  
> >> +  
> >> +        /* already assigned to usbback */  
> >> +        if (usb_intf_is_assigned(gc, intf) > 0)  
> >> +            continue;  
> >> +  
> >> +        /* 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_encode,   
> >> usb_interface_xenstore_encode(intf));  
> >> +            if (libxl__xs_write_checked(gc, XBT_NULL, path, drvpath) < 0) 
> >> {  
>  
> >> +                LOG(WARN, "Write of %s to node %s failed", drvpath, 
> >> path);  
>  
> >> +            }  
> >> +        }  
> >> +  
> >> +        /* bind interface to usbback */  
> >> +        if (bind_usb_intf(gc, intf, SYSFS_USBBACK_DRIVER) < 0) {  
> >> +            LOGE(ERROR, "Couldn't bind %s to %s", intf,   
> >> SYSFS_USBBACK_DRIVER);  
> >> +            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  
> >> +     */  
> >> +    usbback_dev_unassign(gc, usb);  
> >> +out:  
> >> +    free(usb_encode);  
> >> +    return rc;  
> >> +}  
> >> +  
> >> +/* AO operation to add a usb device.  
> >> + *  
> >> + * Generally, it does:  
> >> + * 1) check if the usb device type is assignable  
> >> + * 2) check if the usb device is already assigned to a domain  
> >> + * 3) add 'busid' of the usb device to xenstore contoller/port/.  
> >> + *    (PVUSB driver watches the xenstore changes and will detect that.)  
> >> + * 4) unbind usb device from original driver and bind to usbback.  
> >> + *    If usb device has many interfaces, then:  
> >> + *    - unbind each interface from its original driver and bind to 
> >> usbback.  
>  
> >> + *    - store the original driver to xenstore for later rebinding when  
> >> + *      detaching the device.  
> >> + */  
> >> +void libxl__device_usb_add(libxl__egc *egc, uint32_t domid,  
> >> +                           libxl_device_usb *usb,  
> >> +                           libxl__ao_device *aodev)  
> >> +{  
> >> +    STATE_AO_GC(aodev->ao);  
> >> +    int rc = -1;  
> >> +    char *busid = NULL;  
> >> +  
> >> +    assert(usb->hostbus > 0 && usb->hostaddr > 0);  
> >> +  
> >> +    busid = usb_busaddr_to_busid(gc, usb->hostbus, usb->hostaddr);  
> >> +    if (!busid) {  
> >> +        LOG(ERROR, "USB device doesn't exist in sysfs");  
> >> +        goto out;  
> >> +    }  
> >> +  
> >> +    if (!is_usb_assignable(gc, usb)) {  
> >> +        LOG(ERROR, "USB device is not assignable.");  
> >> +        goto out;  
> >> +    }  
> >> +  
> >> +    /* check usb device is already assigned */  
> >> +    if (is_usb_assigned(gc, usb)) {  
> >> +        LOG(ERROR, "USB device is already attached to a domain.");  
> >> +        goto out;  
> >> +    }  
> >> +  
> >> +    rc = libxl__device_usb_setdefault(gc, domid, usb, 
> >> aodev->update_json);  
> >> +    if (rc) goto out;  
> >> +  
> >> +    rc = libxl__device_usb_add_xenstore(gc, domid, usb, 
> >> aodev->update_json);  
>  
> >> +    if (rc) goto out;  
> >> +  
> >> +    rc = usbback_dev_assign(gc, usb);  
> >> +    if (rc) {  
> >> +        libxl__device_usb_remove_xenstore(gc, domid, usb);  
> >> +        goto out;  
> >> +    }  
> >> +  
> >> +    libxl__ao_complete(egc, ao, 0);  
> >> +    rc = 0;  
> >> +  
> >> +out:  
> >> +    aodev->rc = rc;  
> >> +    if (rc) aodev->callback(egc, aodev);  
> >> +    return;  
> >> +}  
> >> +  
> >> +int libxl_ctrlport_to_device_usb(libxl_ctx *ctx,  
> >> +                                 uint32_t domid,  
> >> +                                 int ctrl,  
> >> +                                 int port,  
> >> +                                 libxl_device_usb *usb)  
> >> +{  
> >> +    GC_INIT(ctx);  
> >> +    char *dompath, *be_path, *busid;  
> >> +    int rc = ERROR_FAIL;  
> >> +  
> >> +    dompath = libxl__xs_get_dompath(gc, domid);  
> >> +    if (!dompath)  
> >> +        goto out;  
> >> +  
> >> +    be_path = libxl__xs_read(gc, XBT_NULL,  
> >> +                  GCSPRINTF("%s/device/vusb/%d/backend", dompath, ctrl)); 
> >>  
> >> +    if (!be_path)  
> >> +        goto out;  
> >> +  
> >> +    busid = libxl__xs_read(gc, XBT_NULL,  
> >> +                           GCSPRINTF("%s/port/%d", be_path, port));  
> >> +    if (busid && strcmp(busid, "")) {  
> >> +        usb->ctrl = ctrl;  
> >> +        usb->port = port;  
> >> +        usb_busaddr_from_busid(gc, busid, &usb->hostbus, &usb->hostaddr); 
> >>  
> >> +        rc = 0;  
> >> +    }  
> >> +  
> >> +out:  
> >> +    GC_FREE;  
> >> +    return rc;  
> >> +}  
> >> +  
> >> +/* Operation to remove usb device.  
> >> + *  
> >> + * Generally, it does:  
> >> + * 1) check if the usb device is assigned to the domain  
> >> + * 2) remove the usb device from xenstore controller/port.  
> >> + * 3) unbind usb device from usbback and rebind to its original driver.  
> >> + *    If usb device has many interfaces, do it to each interface.  
> >> + */  
> >> +static int libxl__device_usb_remove(libxl__gc *gc, uint32_t domid,  
> >> +                                    libxl_device_usb *usb)  
> >> +{  
> >> +    if (libxl__device_usb_remove_xenstore(gc, domid, usb))  
> >> +        return -1;  
> >> +  
> >> +    usbback_dev_unassign(gc, usb);  
> >> +  
> >> +    return 0;  
> >> +}  
> >> +  
> >> +int libxl_device_usb_remove(libxl_ctx *ctx, uint32_t domid,  
> >> +                            libxl_device_usb *usb,  
> >> +                            const libxl_asyncop_how *ao_how)  
> >> +  
> >> +{  
> >> +    AO_CREATE(ctx, domid, ao_how);  
> >> +    int rc;  
> >> +  
> >> +    rc = libxl__device_usb_remove(gc, domid, usb);  
> >> +  
> >> +    libxl__ao_complete(egc, ao, rc);  
> >> +    return AO_INPROGRESS;  
> >> +}  
> >> +  
> >> +int libxl_device_usb_getinfo(libxl_ctx *ctx, libxl_device_usb *usb,  
> >> +                             libxl_usbinfo *usbinfo)  
> >> +{  
> >> +    GC_INIT(ctx);  
> >> +    char *filename;  
> >> +    char *busid;  
> >> +    void *buf = NULL;  
> >> +    int buflen, rc;  
> >> +  
> >> +    usbinfo->ctrl = usb->ctrl;  
> >> +    usbinfo->port = usb->port;  
> >> +  
> >> +    busid = usb_busaddr_to_busid(gc, usb->hostbus, usb->hostaddr);  
> >> +    if (!busid) {  
> >> +        rc = ERROR_FAIL;  
> >> +        goto out;  
> >> +    }  
> >> +  
> >> +    filename = GCSPRINTF(SYSFS_USB_DEV"/%s/devnum", busid);  
> >> +    if (!libxl_read_sysfs_file_contents(ctx, filename, &buf, NULL))  
> >> +        sscanf(buf, "%x", &usbinfo->devnum);  
> >> +  
> >> +    filename = GCSPRINTF(SYSFS_USB_DEV"/%s/busnum", busid);  
> >> +    if (!libxl_read_sysfs_file_contents(ctx, filename, &buf, NULL))  
> >> +        sscanf(buf, "%x", &usbinfo->busnum);  
> >> +  
> >> +    filename = GCSPRINTF(SYSFS_USB_DEV"/%s/idVendor", busid);  
> >> +    if (!libxl_read_sysfs_file_contents(ctx, filename, &buf, NULL))  
> >> +        sscanf(buf, "%x", &usbinfo->idVendor);  
> >> +  
> >> +    filename = GCSPRINTF(SYSFS_USB_DEV"/%s/idProduct", busid);  
> >> +    if (!libxl_read_sysfs_file_contents(ctx, filename, &buf, NULL))  
> >> +        sscanf(buf, "%x", &usbinfo->idProduct);  
> >> +  
> >> +    filename = GCSPRINTF(SYSFS_USB_DEV"/%s/manufacturer", busid);  
> >> +    if (!libxl_read_sysfs_file_contents(ctx, filename, &buf, &buflen) &&  
> >> +        buflen > 0) {  
> >> +        /* replace \n to \0 */  
> >> +        if (((char *)buf)[buflen - 1] == '\n')  
> >> +            ((char *)buf)[buflen - 1] = '\0';  
> >> +        usbinfo->manuf = libxl__strdup(NOGC, buf);  
> >> +   }  
> >> +  
> >> +    filename = GCSPRINTF(SYSFS_USB_DEV"/%s/product", busid);  
> >> +    if (!libxl_read_sysfs_file_contents(ctx, filename, &buf, &buflen) &&  
> >> +        buflen > 0) {  
> >> +        /* replace \n to \0 */  
> >> +        if (((char *)buf)[buflen - 1] == '\n')  
> >> +            ((char *)buf)[buflen - 1] = '\0';  
> >> +        usbinfo->prod = libxl__strdup(NOGC, buf);  
> >> +    }  
> >> +  
> >> +    rc = 0;  
> >> +  
> >> +out:  
> >> +    GC_FREE;  
> >> +    return rc;  
> >> +}  
> >> +/*  
> >> + * Local variables:  
> >> + * mode: C  
> >> + * c-basic-offset: 4  
> >> + * indent-tabs-mode: nil  
> >> + * End:  
> >> + */  
> >> diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl  
> >> index 23f27d4..5278d03 100644  
> >> --- a/tools/libxl/libxl_types.idl  
> >> +++ b/tools/libxl/libxl_types.idl  
> >> @@ -541,6 +541,28 @@ libxl_device_pci = Struct("device_pci", [  
> >>      ("seize", bool),  
> >>      ])  
> >>    
> >> +libxl_usb_protocol = Enumeration("usb_protocol", [  
> >> +    (0, "AUTO"),  
> >> +    (1, "PV"),  
> >> +    (2, "QEMU"),  
> >> +    ])  
> >> +  
> >> +libxl_device_usbctrl = Struct("device_usbctrl", [  
> >> +    ("protocol", libxl_usb_protocol),  
> >> +    ("devid", libxl_devid),  
> >> +    ("version", integer),  
> >> +    ("ports", integer),  
> >> +    ("backend_domid", libxl_domid),  
> >> +    ("backend_domname", string),  
> >> +   ])  
> >> +  
> >> +libxl_device_usb = Struct("device_usb", [  
> >> +    ("ctrl", libxl_devid),  
> >> +    ("port", integer),  
> >> +    ("hostbus",   integer),  
> >> +    ("hostaddr",  integer),  
> >> +    ])  
> >> +  
> >>  libxl_device_dtdev = Struct("device_dtdev", [  
> >>      ("path", string),  
> >>      ])  
> >> @@ -572,6 +594,8 @@ libxl_domain_config = Struct("domain_config", [  
> >>      ("nics", Array(libxl_device_nic, "num_nics")),  
> >>      ("pcidevs", Array(libxl_device_pci, "num_pcidevs")),  
> >>      ("dtdevs", Array(libxl_device_dtdev, "num_dtdevs")),  
> >> +    ("usbctrls", Array(libxl_device_usbctrl, "num_usbctrls")),  
> >> +    ("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")),  
> >> @@ -620,6 +644,32 @@ libxl_vtpminfo = Struct("vtpminfo", [  
> >>      ("uuid", libxl_uuid),  
> >>      ], dir=DIR_OUT)  
> >>    
> >> +libxl_usbctrlinfo = Struct("usbctrlinfo", [  
> >> +    ("protocol", libxl_usb_protocol),  
> >> +    ("devid", libxl_devid),  
> >> +    ("version", integer),  
> >> +    ("ports", integer),  
> >> +    ("backend", string),  
> >> +    ("backend_id", uint32),  
> >> +    ("frontend", string),  
> >> +    ("frontend_id", uint32),  
> >> +    ("state", integer),  
> >> +    ("evtch", integer),  
> >> +    ("ref_urb", integer),  
> >> +    ("ref_conn", integer),  
> >> +    ], dir=DIR_OUT)  
> >> +  
> >> +libxl_usbinfo = Struct("usbinfo", [  
> >> +    ("ctrl", libxl_devid),  
> >> +    ("port", integer),  
> >> +    ("busnum", 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", [  
> >> diff --git a/tools/libxl/libxl_utils.c b/tools/libxl/libxl_utils.c  
> >> index dc5465e..a627662 100644  
> >> --- a/tools/libxl/libxl_utils.c  
> >> +++ b/tools/libxl/libxl_utils.c  
> >> @@ -1187,6 +1187,22 @@ int libxl__random_bytes(libxl__gc *gc, uint8_t 
> >> *buf,   
>  
> >> size_t len)  
> >>      return ret;  
> >>  }  
> >>    
> >> +void libxl_device_usbctrl_list_free(libxl_device_usbctrl* list, int nr)  
> >> +{  
> >> +   int i;  
> >> +   for (i = 0; i < nr; i++)  
> >> +      libxl_device_usbctrl_dispose(&list[i]);  
> >> +   free(list);  
> >> +}  
> >> +  
> >> +void libxl_device_usb_list_free(libxl_device_usb* list, int nr)  
> >> +{  
> >> +   int i;  
> >> +   for (i = 0; i < nr; i++)  
> >> +      libxl_device_usb_dispose(&list[i]);  
> >> +   free(list);  
> >> +}  
> >> +  
> >>  /*  
> >>   * Local variables:  
> >>   * mode: C  
> >> diff --git a/tools/libxl/libxl_utils.h b/tools/libxl/libxl_utils.h  
> >> index 1c1761d..321df9d 100644  
> >> --- a/tools/libxl/libxl_utils.h  
> >> +++ b/tools/libxl/libxl_utils.h  
> >> @@ -76,6 +76,11 @@ int libxl_uuid_to_device_vtpm(libxl_ctx *ctx, uint32_t  
> >>  
> >> domid,  
> >>                                 libxl_uuid *uuid, libxl_device_vtpm 
> >> *vtpm);  
>  
> >>  int libxl_devid_to_device_vtpm(libxl_ctx *ctx, uint32_t domid,  
> >>                                 int devid, libxl_device_vtpm *vtpm);  
> >> +int libxl_devid_to_device_usbctrl(libxl_ctx *ctx, uint32_t domid,  
> >> +                                  int devid, libxl_device_usbctrl   
> >> *usbctrl);  
> >> +int libxl_ctrlport_to_device_usb(libxl_ctx *ctx, uint32_t domid,  
> >> +                                 int ctrl, int port,  
> >> +                                 libxl_device_usb *usb);  
> >>    
> >>  int libxl_bitmap_alloc(libxl_ctx *ctx, libxl_bitmap *bitmap, int n_bits); 
> >>  
> >>      /* Allocated bimap is from malloc, libxl_bitmap_dispose() to be  
> >   
> >  
>  
>  
> _______________________________________________ 
> Xen-devel mailing list 
> Xen-devel@xxxxxxxxxxxxx 
> http://lists.xen.org/xen-devel 
>  
>  


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


 


Rackspace

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