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