debuggers.hg

changeset 20659:2e5032921b07

PVUSB: xm/xend support

You can see the following slides to understand the usage.
http://www.xen.org/files/xensummit_intel09/PVUSBStatusUpdate.pdf
Limitations:
"xm usb-hc-create" accepts up to 16 ports, but, current usbfront
can work with up to 15 ports. This may be bug and I'm preparing
to fix it.

This xm/xend support requires linux-2.6.18-xen.hg c/s 939 or above.
I recommend latest tip.

Signed-off-by: Noboru Iwamatsu <n_iwamatsu@jp.fujitsu.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Dec 11 08:52:17 2009 +0000 (2009-12-11)
parents 1f5f36e11114
children b7cf749e14fc
files tools/hotplug/Linux/xend.rules tools/python/xen/util/vusb_util.py tools/python/xen/xend/XendConfig.py tools/python/xen/xend/XendDevices.py tools/python/xen/xend/XendDomainInfo.py tools/python/xen/xend/XendNode.py tools/python/xen/xend/server/udevevent.py tools/python/xen/xend/server/vusbif.py tools/python/xen/xm/create.py tools/python/xen/xm/main.py
line diff
     1.1 --- a/tools/hotplug/Linux/xend.rules	Fri Dec 11 08:51:21 2009 +0000
     1.2 +++ b/tools/hotplug/Linux/xend.rules	Fri Dec 11 08:52:17 2009 +0000
     1.3 @@ -1,3 +1,4 @@
     1.4  SUBSYSTEM=="pci", RUN+="socket:/org/xen/xend/udev_event"
     1.5  SUBSYSTEM=="scsi", RUN+="socket:/org/xen/xend/udev_event"
     1.6 +SUBSYSTEM=="usb", RUN+="socket:/org/xen/xend/udev_event"
     1.7  #SUBSYSTEM=="net", KERNEL!="vif[0-9]*.[0-9]*|tap[0-9]*.[0-9]*", RUN+="socket:/org/xen/xend/udev_event"
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/tools/python/xen/util/vusb_util.py	Fri Dec 11 08:52:17 2009 +0000
     2.3 @@ -0,0 +1,338 @@
     2.4 +#============================================================================
     2.5 +# This library is free software; you can redistribute it and/or
     2.6 +# modify it under the terms of version 2.1 of the GNU Lesser General Public
     2.7 +# License as published by the Free Software Foundation.
     2.8 +#
     2.9 +# This library is distributed in the hope that it will be useful,
    2.10 +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    2.11 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    2.12 +# Lesser General Public License for more details.
    2.13 +#
    2.14 +# You should have received a copy of the GNU Lesser General Public
    2.15 +# License along with this library; if not, write to the Free Software
    2.16 +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    2.17 +#============================================================================
    2.18 +# Copyright (C) 2009, FUJITSU LABORATORIES LTD.
    2.19 +#  Author: Noboru Iwamatsu <n_iwamatsu@jp.fujitsu.com>
    2.20 +#============================================================================
    2.21 +
    2.22 +
    2.23 +"""Support for VUSB Devices.
    2.24 +"""
    2.25 +import os
    2.26 +import os.path
    2.27 +import sys
    2.28 +import re
    2.29 +import string
    2.30 +from xen.util import utils
    2.31 +
    2.32 +SYSFS_USB_DEVS_PATH = '/bus/usb/devices'
    2.33 +SYSFS_USB_DEV_BDEVICECLASS_PATH = '/bDeviceClass'
    2.34 +SYSFS_USB_DEV_BDEVICESUBCLASS_PATH = '/bDeviceSubClass'
    2.35 +SYSFS_USB_DEV_DEVNUM_PATH = '/devnum'
    2.36 +SYSFS_USB_DEV_IDVENDOR_PATH = '/idVendor'
    2.37 +SYSFS_USB_DEV_IDPRODUCT_PATH = '/idProduct'
    2.38 +SYSFS_USB_DEV_MANUFACTURER_PATH = '/manufacturer'
    2.39 +SYSFS_USB_DEV_PRODUCT_PATH = '/product'
    2.40 +SYSFS_USB_DEV_SERIAL_PATH = '/serial'
    2.41 +SYSFS_USB_DEV_DRIVER_PATH = '/driver'
    2.42 +SYSFS_USB_DRIVER_BIND_PATH = '/bind'
    2.43 +SYSFS_USB_DRIVER_UNBIND_PATH = '/unbind'
    2.44 +SYSFS_USBBACK_PATH = '/bus/usb/drivers/usbback'
    2.45 +SYSFS_PORTIDS_PATH = '/port_ids'
    2.46 +USBHUB_CLASS_CODE = '09'
    2.47 +
    2.48 +def get_usb_bDeviceClass(dev):
    2.49 +    try:
    2.50 +        sysfs_mnt = utils.find_sysfs_mount() 
    2.51 +        sysfs_usb_dev_path = \
    2.52 +            os.path.join(sysfs_mnt + SYSFS_USB_DEVS_PATH, dev)
    2.53 +        if os.path.exists(sysfs_usb_dev_path + SYSFS_USB_DEV_BDEVICECLASS_PATH):
    2.54 +            usb_deviceclass = \
    2.55 +                os.popen('cat ' + sysfs_usb_dev_path + \
    2.56 +                              SYSFS_USB_DEV_BDEVICECLASS_PATH).readline()
    2.57 +            return usb_deviceclass.splitlines()[0]
    2.58 +        else:
    2.59 +            return ""
    2.60 +    except:
    2.61 +        return None
    2.62 +
    2.63 +def get_usb_bDeviceSubClass(dev):
    2.64 +    try:
    2.65 +        sysfs_mnt = utils.find_sysfs_mount() 
    2.66 +        sysfs_usb_dev_path = \
    2.67 +            os.path.join(sysfs_mnt + SYSFS_USB_DEVS_PATH, dev)
    2.68 +        if os.path.exists(sysfs_usb_dev_path + SYSFS_USB_DEV_BDEVICESUBCLASS_PATH):
    2.69 +            usb_devicesubclass = \
    2.70 +                os.popen('cat ' + sysfs_usb_dev_path + \
    2.71 +                              SYSFS_USB_DEV_BDEVICESUBCLASS_PATH).readline()
    2.72 +            return usb_devicesubclass.splitlines()[0]
    2.73 +        else:
    2.74 +            return ""
    2.75 +    except:
    2.76 +        return None
    2.77 +
    2.78 +def get_usb_devnum(dev):
    2.79 +    try:
    2.80 +        sysfs_mnt = utils.find_sysfs_mount() 
    2.81 +        sysfs_usb_dev_path = \
    2.82 +            os.path.join(sysfs_mnt + SYSFS_USB_DEVS_PATH, dev)
    2.83 +        if os.path.exists(sysfs_usb_dev_path + SYSFS_USB_DEV_DEVNUM_PATH):
    2.84 +            usb_devicesubclass = \
    2.85 +                os.popen('cat ' + sysfs_usb_dev_path + \
    2.86 +                              SYSFS_USB_DEV_DEVNUM_PATH).readline()
    2.87 +            return usb_devicesubclass.splitlines()[0]
    2.88 +        else:
    2.89 +            return ""
    2.90 +    except:
    2.91 +        return None
    2.92 +
    2.93 +def get_usb_idvendor(dev):
    2.94 +    try:
    2.95 +        sysfs_mnt = utils.find_sysfs_mount() 
    2.96 +        sysfs_usb_dev_path = \
    2.97 +            os.path.join(sysfs_mnt + SYSFS_USB_DEVS_PATH, dev)
    2.98 +        if os.path.exists(sysfs_usb_dev_path + SYSFS_USB_DEV_IDVENDOR_PATH):
    2.99 +            usb_idvendor = \
   2.100 +                os.popen('cat ' + sysfs_usb_dev_path + \
   2.101 +                              SYSFS_USB_DEV_IDVENDOR_PATH).readline()
   2.102 +            return usb_idvendor.splitlines()[0]
   2.103 +        else:
   2.104 +            return ""
   2.105 +    except:
   2.106 +        return None
   2.107 +
   2.108 +def get_usb_idproduct(dev):
   2.109 +    try:
   2.110 +        sysfs_mnt = utils.find_sysfs_mount() 
   2.111 +        sysfs_usb_dev_path = \
   2.112 +            os.path.join(sysfs_mnt + SYSFS_USB_DEVS_PATH, dev)
   2.113 +        if os.path.exists(sysfs_usb_dev_path + SYSFS_USB_DEV_IDPRODUCT_PATH):
   2.114 +            usb_idproduct = \
   2.115 +                os.popen('cat ' + sysfs_usb_dev_path + \
   2.116 +                              SYSFS_USB_DEV_IDPRODUCT_PATH).readline()
   2.117 +            return usb_idproduct.splitlines()[0]
   2.118 +        else:
   2.119 +            return ""
   2.120 +    except:
   2.121 +        return None
   2.122 +
   2.123 +def get_usb_manufacturer(dev):
   2.124 +    try:
   2.125 +        sysfs_mnt = utils.find_sysfs_mount() 
   2.126 +        sysfs_usb_dev_path = \
   2.127 +            os.path.join(sysfs_mnt + SYSFS_USB_DEVS_PATH, dev)
   2.128 +
   2.129 +        if os.path.exists(sysfs_usb_dev_path + SYSFS_USB_DEV_MANUFACTURER_PATH):
   2.130 +            usb_manufacturer = \
   2.131 +                os.popen('cat ' + sysfs_usb_dev_path + \
   2.132 +                              SYSFS_USB_DEV_MANUFACTURER_PATH).readline()
   2.133 +            return usb_manufacturer.splitlines()[0]
   2.134 +        else:
   2.135 +            return ""
   2.136 +    except:
   2.137 +        return None
   2.138 +
   2.139 +def get_usb_product(dev):
   2.140 +    try:
   2.141 +        sysfs_mnt = utils.find_sysfs_mount() 
   2.142 +        sysfs_usb_dev_path = \
   2.143 +            os.path.join(sysfs_mnt + SYSFS_USB_DEVS_PATH, dev)
   2.144 +        if os.path.exists(sysfs_usb_dev_path + SYSFS_USB_DEV_PRODUCT_PATH):
   2.145 +            usb_product = \
   2.146 +                os.popen('cat ' + sysfs_usb_dev_path + \
   2.147 +                              SYSFS_USB_DEV_PRODUCT_PATH).readline()
   2.148 +            return usb_product.splitlines()[0]
   2.149 +        else:
   2.150 +            return ""
   2.151 +    except:
   2.152 +        return None
   2.153 +
   2.154 +def get_usb_serial(dev):
   2.155 +    try:
   2.156 +        sysfs_mnt = utils.find_sysfs_mount() 
   2.157 +        sysfs_usb_dev_path = \
   2.158 +            os.path.join(sysfs_mnt + SYSFS_USB_DEVS_PATH, dev)
   2.159 +        if os.path.exists(sysfs_usb_dev_path + SYSFS_USB_DEV_SERIAL_PATH):
   2.160 +            usb_serial = \
   2.161 +                os.popen('cat ' + sysfs_usb_dev_path + \
   2.162 +                              SYSFS_USB_DEV_SERIAL_PATH).readline()
   2.163 +            return usb_serial.splitlines()[0]
   2.164 +        else:
   2.165 +            return ""
   2.166 +    except:
   2.167 +        return None
   2.168 +
   2.169 +def get_usbdevice_info_by_lsusb(dev):
   2.170 +    try:
   2.171 +        vend = get_usb_idvendor(dev)
   2.172 +        prod = get_usb_idproduct(dev)
   2.173 +        output = os.popen('lsusb -d ' + vend + ':' + prod).readline().split()
   2.174 +        text = ""
   2.175 +        if len(output) > 6:
   2.176 +            for str in output[6:]:
   2.177 +                if text != "":
   2.178 +                    text= text + ' '
   2.179 +                text = text + str
   2.180 +            return text
   2.181 +        else:
   2.182 +            return ""
   2.183 +    except:
   2.184 +        return None
   2.185 +
   2.186 +def get_usbdevice_info(dev):
   2.187 +    try:
   2.188 +        manuf = get_usb_manufacturer(dev)
   2.189 +        prod = get_usb_product(dev)
   2.190 +        if manuf == "" or prod == "":
   2.191 +            return get_usbdevice_info_by_lsusb(dev)
   2.192 +        else:
   2.193 +            return manuf + ' ' + prod
   2.194 +    except:
   2.195 +        return None
   2.196 +
   2.197 +def usb_device_is_hub(dev):
   2.198 +    usb_classcode = get_usb_bDeviceClass(dev)
   2.199 +    if (usb_classcode == USBHUB_CLASS_CODE):
   2.200 +        return True
   2.201 +    else:
   2.202 +        return False
   2.203 +
   2.204 +def get_all_usb_names():
   2.205 +    usb_names = []
   2.206 +    try:
   2.207 +        sysfs_mnt = utils.find_sysfs_mount() 
   2.208 +        usb_names = os.popen('ls ' + sysfs_mnt + SYSFS_USB_DEVS_PATH).read().split()
   2.209 +    except:
   2.210 +        pass
   2.211 +    return usb_names
   2.212 +
   2.213 +def get_usb_devices():
   2.214 +    devs = []
   2.215 +    for name in get_all_usb_names():
   2.216 +        dev_match = re.match(r"(^(?P<bus>[0-9]{1,2})[-,])" + \
   2.217 +                     r"(?P<root_port>[0-9]{1,2})" + \
   2.218 +                     r"(?P<port>([\.,]{1}[0-9]{1,2}){0,5})$", name)
   2.219 +        if dev_match is not None:
   2.220 +            dev = dev_match.group('bus') + '-' \
   2.221 +            + dev_match.group('root_port') \
   2.222 +            + dev_match.group('port') 
   2.223 +            if (usb_device_is_hub(dev)):
   2.224 +                continue
   2.225 +            else:
   2.226 +                devs.append(dev)
   2.227 +    return devs
   2.228 +
   2.229 +def get_usb_intfs(dev):
   2.230 +    intfs = []
   2.231 +    try:
   2.232 +        search = re.compile(r'^' + dev + ':')
   2.233 +    except:
   2.234 +        raise UsbDeviceParseError("Invalid expression.")
   2.235 +    for name in get_all_usb_names():
   2.236 +        if search.match(name):
   2.237 +            intfs.append(name)
   2.238 +    return intfs
   2.239 +
   2.240 +def get_assigned_buses():
   2.241 +    buses = []
   2.242 +    try:
   2.243 +        sysfs_mnt = utils.find_sysfs_mount()
   2.244 +        if os.path.exists(sysfs_mnt + SYSFS_USBBACK_PATH + SYSFS_PORTIDS_PATH):
   2.245 +            portids = \
   2.246 +                os.popen('cat ' + sysfs_mnt + SYSFS_USBBACK_PATH + SYSFS_PORTIDS_PATH).read().splitlines()
   2.247 +            for portid in portids:
   2.248 +                buses.append(portid.split(':')[0])
   2.249 +    except:
   2.250 +        raise UsbDeviceParseError("Can't get assigned buses from port_ids.")
   2.251 +    return buses
   2.252 +
   2.253 +def get_assigned_bus(domid, dev, port):
   2.254 +    bus = ""
   2.255 +    try:
   2.256 +        sysfs_mnt = utils.find_sysfs_mount()
   2.257 +        if os.path.exists(sysfs_mnt + SYSFS_USBBACK_PATH + SYSFS_PORTIDS_PATH):
   2.258 +            portids = \
   2.259 +                os.popen('cat ' + sysfs_mnt + SYSFS_USBBACK_PATH + SYSFS_PORTIDS_PATH).read().splitlines()
   2.260 +        for portid in portids:
   2.261 +            if portid.split(':')[1] == str(domid) and portid.split(':')[2] == str(dev) and portid.split(':')[3] == str(port):
   2.262 +                bus = portid.split(':')[0]
   2.263 +    except:
   2.264 +        raise UsbDeviceParseError("Can't get assigned bus (%d:%d:%d)." % (domid, dev, port))
   2.265 +    return bus
   2.266 +
   2.267 +def bus_is_assigned(bus):
   2.268 +    assigned = False    
   2.269 +    try:
   2.270 +        sysfs_mnt = utils.find_sysfs_mount()
   2.271 +        if os.path.exists(sysfs_mnt + SYSFS_USBBACK_PATH + SYSFS_PORTIDS_PATH):
   2.272 +            portids = \
   2.273 +                os.popen('cat ' + sysfs_mnt + SYSFS_USBBACK_PATH + SYSFS_PORTIDS_PATH).read().splitlines()
   2.274 +        for portid in portids:
   2.275 +            if portid.split(':')[0] == bus:
   2.276 +                assigned = True
   2.277 +    except:
   2.278 +        raise UsbDeviceParseError("Can't get assignment status: (%s)." % bus)
   2.279 +    return assigned
   2.280 +
   2.281 +def usb_intf_is_binded(intf):
   2.282 +    if os.path.exists(SYSFS_USBBACK_PATH + '/' + intf):
   2.283 +        return True
   2.284 +    else:
   2.285 +        return False
   2.286 +
   2.287 +def usb_device_is_connected(dev):
   2.288 +    try:
   2.289 +        sysfs_mnt = utils.find_sysfs_mount()
   2.290 +        sysfs_dev_path = \
   2.291 +                os.path.join(sysfs_mnt + SYSFS_USB_DEVS_PATH, dev)
   2.292 +        if os.path.exists(sysfs_dev_path):
   2.293 +            return True
   2.294 +        else:
   2.295 +            return False
   2.296 +    except:
   2.297 +        raise UsbDeviceParseError("Can't get connection status (%s)." % dev)
   2.298 +
   2.299 +def unbind_usb_device(dev):
   2.300 +    try:
   2.301 +        sysfs_mnt = utils.find_sysfs_mount()
   2.302 +        for intf in get_usb_intfs(dev): 
   2.303 +            sysfs_usb_intf_path = \
   2.304 +                os.path.join(sysfs_mnt + SYSFS_USB_DEVS_PATH, intf)
   2.305 +            if os.path.exists(sysfs_usb_intf_path + SYSFS_USB_DEV_DRIVER_PATH):
   2.306 +                fd = os.open(sysfs_usb_intf_path + \
   2.307 +                             SYSFS_USB_DEV_DRIVER_PATH + \
   2.308 +                             SYSFS_USB_DRIVER_UNBIND_PATH, os.O_WRONLY)
   2.309 +                os.write(fd, intf)
   2.310 +                os.close(fd)
   2.311 +    except:
   2.312 +        raise UsbDeviceBindingError("can't unbind intf (%s). " % intf)
   2.313 +
   2.314 +def bind_usb_device(dev):
   2.315 +    try:
   2.316 +        sysfs_mnt = utils.find_sysfs_mount()
   2.317 +        for intf in get_usb_intfs(dev): 
   2.318 +            sysfs_usb_intf_path = \
   2.319 +                os.path.join(sysfs_mnt + SYSFS_USB_DEVS_PATH, intf)
   2.320 +            if os.path.exists(sysfs_usb_intf_path + SYSFS_USB_DEV_DRIVER_PATH):
   2.321 +                unbind_usb_device(dev)
   2.322 +
   2.323 +            fd = os.open(sysfs_mnt + SYSFS_USBBACK_PATH + \
   2.324 +                         SYSFS_USB_DRIVER_BIND_PATH, os.O_WRONLY)
   2.325 +            os.write(fd, intf)
   2.326 +            os.close(fd)
   2.327 +    except:
   2.328 +        raise UsbDeviceBindingError("can't bind intf (%s). " % intf)
   2.329 +
   2.330 +class UsbDeviceParseError(Exception):
   2.331 +    def __init__(self,msg):
   2.332 +        self.message = msg
   2.333 +    def __str__(self):
   2.334 +        return 'vusb: Error parsing USB device info: '+self.message
   2.335 +
   2.336 +class UsbDeviceBindingError(Exception):
   2.337 +    def __init__(self,msg):
   2.338 +        self.message = msg
   2.339 +    def __str__(self):
   2.340 +        return 'vusb: Failed to bind/unbind USB device: ' + \
   2.341 +            self.message
     3.1 --- a/tools/python/xen/xend/XendConfig.py	Fri Dec 11 08:51:21 2009 +0000
     3.2 +++ b/tools/python/xen/xend/XendConfig.py	Fri Dec 11 08:52:17 2009 +0000
     3.3 @@ -1400,6 +1400,14 @@ class XendConfig(dict):
     3.4                            (vscsi_devs, vscsi_mode))
     3.5                  return vscsi_devs_uuid
     3.6  
     3.7 +            if dev_type == 'vusb':
     3.8 +                vusb_devs_uuid = sxp.child_value(config, 'uuid',
     3.9 +                                                uuid.createString())
    3.10 +                vusb_dict = self.vusb_convert_sxp_to_dict(config)
    3.11 +                vusb_dict['uuid'] = vusb_devs_uuid
    3.12 +                target['devices'][vusb_devs_uuid] = (dev_type, vusb_dict)
    3.13 +                return vusb_devs_uuid
    3.14 +
    3.15              for opt_val in config[1:]:
    3.16                  try:
    3.17                      opt, val = opt_val
    3.18 @@ -1776,6 +1784,68 @@ class XendConfig(dict):
    3.19  
    3.20          return dev_config
    3.21  
    3.22 +    def vusb_convert_sxp_to_dict(self, dev_sxp):
    3.23 +        """Convert vusb device sxp to dict
    3.24 +        @param dev_sxp: device configuration
    3.25 +        @type  dev_sxp: SXP object (parsed config)
    3.26 +        @return: dev_config
    3.27 +        @rtype: dictionary
    3.28 +        """
    3.29 +        # Parsing USB devices SXP. 
    3.30 +        #
    3.31 +        # USB device's SXP looks like this:
    3.32 +        #
    3.33 +        # [device,
    3.34 +        #   [vusb,
    3.35 +        #     [usb-ver, 2],
    3.36 +        #     [num-ports, 8],
    3.37 +        #     [port,
    3.38 +        #          [1, 1-1],
    3.39 +        #          [2, 1-2],
    3.40 +        #          [3, ''],
    3.41 +        #          [4, ''],
    3.42 +        #          [5, ''],
    3.43 +        #          [6, ''],
    3.44 +        #          [7, 6-2.1],        
    3.45 +        #          [8, '']
    3.46 +        #     ]
    3.47 +        #   ],
    3.48 +        #   [vusb,
    3.49 +        #     [usb-ver, 1],
    3.50 +        #     [num-ports, 2],
    3.51 +        #     [port,
    3.52 +        #          [1, 4-1],
    3.53 +        #          [2, 4-2]
    3.54 +        #     ]
    3.55 +        #   ]  
    3.56 +        # ]
    3.57 +        #
    3.58 +        # The dict looks like this
    3.59 +        #
    3.60 +        # { usb-ver: 2,
    3.61 +        #   num-ports: 8,
    3.62 +        #   port-1: 1-1,
    3.63 +        #   port-2: 1-2,
    3.64 +        #   port-3: "",
    3.65 +        #   port-4: "",
    3.66 +        #   port-5: "",
    3.67 +        #   port-6: "",
    3.68 +        #   port-7: "",
    3.69 +        #   port-8: "" }
    3.70 +
    3.71 +        dev_config = {}
    3.72 +        dev_config['usb-ver'] = sxp.child(dev_sxp, 'usb-ver')[1]
    3.73 +        dev_config['num-ports'] = sxp.child(dev_sxp, 'num-ports')[1]
    3.74 +        ports = sxp.child(dev_sxp, 'port')
    3.75 +        for port in ports[1:]:
    3.76 +            try:
    3.77 +                num, bus = port
    3.78 +                dev_config['port-%i' % int(num)] = str(bus)
    3.79 +            except TypeError:
    3.80 +                pass
    3.81 +
    3.82 +        return dev_config
    3.83 +
    3.84      def console_add(self, protocol, location, other_config = {}):
    3.85          dev_uuid = uuid.createString()
    3.86          if protocol == 'vt100':
    3.87 @@ -2002,6 +2072,18 @@ class XendConfig(dict):
    3.88                  for pci_dev_info in dev_info['devs']:
    3.89                      sxpr.append(dev_dict_to_sxp(pci_dev_info))
    3.90                  sxprs.append((dev_type, sxpr))
    3.91 +            elif dev_type == 'vusb':
    3.92 +                sxpr = ['vusb', ['uuid', dev_info['uuid']],
    3.93 +                                ['usb-ver', dev_info['usb-ver']],
    3.94 +                                ['num-ports', dev_info['num-ports']]]
    3.95 +                port_sxpr = ['port']
    3.96 +                for i in range(1, int(dev_info['num-ports']) + 1):
    3.97 +                    if dev_info.has_key('port-%i' % i):
    3.98 +                        port_sxpr.append([i, str(dev_info['port-%i' % i])])
    3.99 +                    else:
   3.100 +                        port_sxpr.append([i, ""])
   3.101 +                sxpr.append(port_sxpr)
   3.102 +                sxprs.append((dev_type, sxpr))
   3.103              else:
   3.104                  sxpr = self.device_sxpr(dev_type = dev_type,
   3.105                                          dev_info = dev_info,
     4.1 --- a/tools/python/xen/xend/XendDevices.py	Fri Dec 11 08:51:21 2009 +0000
     4.2 +++ b/tools/python/xen/xend/XendDevices.py	Fri Dec 11 08:52:17 2009 +0000
     4.3 @@ -19,7 +19,7 @@
     4.4  # A collection of DevControllers 
     4.5  #
     4.6  
     4.7 -from xen.xend.server import blkif, netif, tpmif, pciif, iopif, irqif, vfbif, vscsiif, netif2
     4.8 +from xen.xend.server import blkif, netif, tpmif, pciif, iopif, irqif, vfbif, vscsiif, netif2, vusbif
     4.9  from xen.xend.server.BlktapController import BlktapController, Blktap2Controller
    4.10  from xen.xend.server.ConsoleController import ConsoleController
    4.11  
    4.12 @@ -48,6 +48,7 @@ class XendDevices:
    4.13          'vkbd': vfbif.VkbdifController,
    4.14          'console': ConsoleController,
    4.15          'vscsi': vscsiif.VSCSIController,
    4.16 +        'vusb': vusbif.VUSBController,
    4.17      }
    4.18  
    4.19      #@classmethod
     5.1 --- a/tools/python/xen/xend/XendDomainInfo.py	Fri Dec 11 08:51:21 2009 +0000
     5.2 +++ b/tools/python/xen/xend/XendDomainInfo.py	Fri Dec 11 08:52:17 2009 +0000
     5.3 @@ -1102,6 +1102,27 @@ class XendDomainInfo:
     5.4  
     5.5          return True
     5.6  
     5.7 +    def vusb_device_configure(self, dev_sxp, devid):
     5.8 +        """Configure a virtual root port.
     5.9 +        """
    5.10 +        dev_class = sxp.name(dev_sxp)
    5.11 +        if dev_class != 'vusb':
    5.12 +            return False
    5.13 +
    5.14 +        dev_config = {}
    5.15 +        ports = sxp.child(dev_sxp, 'port')
    5.16 +        for port in ports[1:]:
    5.17 +            try:
    5.18 +                num, bus = port
    5.19 +                dev_config['port-%i' % int(num)] = str(bus)
    5.20 +            except TypeError:
    5.21 +                pass
    5.22 +
    5.23 +        dev_control = self.getDeviceController(dev_class)
    5.24 +        dev_control.reconfigureDevice(devid, dev_config)
    5.25 +
    5.26 +        return True
    5.27 +
    5.28      def device_configure(self, dev_sxp, devid = None):
    5.29          """Configure an existing device.
    5.30          
    5.31 @@ -1123,6 +1144,9 @@ class XendDomainInfo:
    5.32          if dev_class == 'vscsi':
    5.33              return self.vscsi_device_configure(dev_sxp)
    5.34  
    5.35 +        if dev_class == 'vusb':
    5.36 +            return self.vusb_device_configure(dev_sxp, devid)
    5.37 +
    5.38          for opt_val in dev_sxp[1:]:
    5.39              try:
    5.40                  dev_config[opt_val[0]] = opt_val[1]
    5.41 @@ -1378,6 +1402,13 @@ class XendDomainInfo:
    5.42                  return dev_info
    5.43          return None
    5.44  
    5.45 +    def _getDeviceInfo_vusb(self, devid):
    5.46 +        for dev_type, dev_info in self.info.all_devices_sxpr():
    5.47 +            if dev_type != 'vusb':
    5.48 +                continue
    5.49 +            return dev_info
    5.50 +        return None
    5.51 +
    5.52      def _get_assigned_pci_devices(self, devid = 0):
    5.53          if self.domid is not None:
    5.54              return get_assigned_pci_devices(self.domid)
     6.1 --- a/tools/python/xen/xend/XendNode.py	Fri Dec 11 08:51:21 2009 +0000
     6.2 +++ b/tools/python/xen/xend/XendNode.py	Fri Dec 11 08:52:17 2009 +0000
     6.3 @@ -24,6 +24,7 @@ import xen.lowlevel.xc
     6.4  from xen.util import Brctl
     6.5  from xen.util import pci as PciUtil
     6.6  from xen.util import vscsi_util
     6.7 +from xen.util import vusb_util
     6.8  from xen.xend import XendAPIStore
     6.9  from xen.xend import osdep
    6.10  from xen.xend.XendConstants import *
    6.11 @@ -478,6 +479,20 @@ class XendNode:
    6.12  
    6.13                  return
    6.14  
    6.15 +    def add_usbdev(self, busid):
    6.16 +        # if the adding usb device should be owned by usbback
    6.17 +        # and is probed by other usb drivers, seize it!
    6.18 +        bus, intf = busid.split(':')
    6.19 +        buses = vusb_util.get_assigned_buses()
    6.20 +        if str(bus) in buses:
    6.21 +            if not vusb_util.usb_intf_is_binded(busid):
    6.22 +                log.debug("add_usb(): %s is binded to other driver" % busid)
    6.23 +                vusb_util.unbind_usb_device(bus)
    6.24 +                vusb_util.bind_usb_device(bus)
    6.25 +        return
    6.26 +
    6.27 +    def remove_usbdev(self, busid):
    6.28 +        log.debug("remove_usbdev(): Not implemented.")
    6.29  
    6.30  ##    def network_destroy(self, net_uuid):
    6.31   ##       del self.networks[net_uuid]
     7.1 --- a/tools/python/xen/xend/server/udevevent.py	Fri Dec 11 08:51:21 2009 +0000
     7.2 +++ b/tools/python/xen/xend/server/udevevent.py	Fri Dec 11 08:52:17 2009 +0000
     7.3 @@ -60,6 +60,18 @@ class UdevEventProtocol(protocol.Protoco
     7.4                      log.info("Removing scsi device %s", hctl)
     7.5                      XendNode.instance().remove_PSCSI(hctl)
     7.6  
     7.7 +            elif (udev_event.get('SUBSYSTEM', None) == 'usb'):
     7.8 +                busid = udev_event.get('KERNEL', None)
     7.9 +                if busid:
    7.10 +                    if len(busid.split(':')) != 2:
    7.11 +                        return
    7.12 +                if (udev_event['ACTION'] == 'add'):
    7.13 +                    log.info("Adding usb device %s", busid)
    7.14 +                    XendNode.instance().add_usbdev(busid)
    7.15 +                elif (udev_event['ACTION'] == 'remove'):
    7.16 +                    log.info("Removing usb device %s", busid)
    7.17 +                    XendNode.instance().remove_usbdev(busid)
    7.18 +
    7.19              elif (udev_event.get('SUBSYSTEM', None) == 'net'):
    7.20                  interface = udev_event.get('INTERFACE', None)
    7.21                  if (udev_event['ACTION'] == 'add'):
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/tools/python/xen/xend/server/vusbif.py	Fri Dec 11 08:52:17 2009 +0000
     8.3 @@ -0,0 +1,126 @@
     8.4 +#============================================================================
     8.5 +# This library is free software; you can redistribute it and/or
     8.6 +# modify it under the terms of version 2.1 of the GNU Lesser General Public
     8.7 +# License as published by the Free Software Foundation.
     8.8 +#
     8.9 +# This library is distributed in the hope that it will be useful,
    8.10 +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    8.11 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    8.12 +# Lesser General Public License for more details.
    8.13 +#
    8.14 +# You should have received a copy of the GNU Lesser General Public
    8.15 +# License along with this library; if not, write to the Free Software
    8.16 +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    8.17 +#============================================================================
    8.18 +# Copyright (C) 2009, FUJITSU LABORATORIES LTD.
    8.19 +#  Author: Noboru Iwamatsu <n_iwamatsu@jp.fujitsu.com>
    8.20 +#============================================================================
    8.21 +
    8.22 +"""Support for virtual USB host controllers.
    8.23 +"""
    8.24 +import re
    8.25 +import string
    8.26 +
    8.27 +import types
    8.28 +
    8.29 +from xen.xend import sxp
    8.30 +from xen.xend.XendError import VmError
    8.31 +from xen.xend.XendLogging import log
    8.32 +
    8.33 +from xen.xend.server.DevController import DevController
    8.34 +from xen.xend.server.DevConstants import xenbusState
    8.35 +from xen.xend.xenstore.xstransact import xstransact
    8.36 +
    8.37 +from xen.util import vusb_util
    8.38 +
    8.39 +class VUSBController(DevController):
    8.40 +    """VUSB Devices.
    8.41 +    """
    8.42 +    def __init__(self, vm):
    8.43 +        """Create a VUSB Devices.
    8.44 +        """
    8.45 +        DevController.__init__(self, vm)
    8.46 +
    8.47 +    def sxprs(self):
    8.48 +        """@see DevController.sxprs"""
    8.49 +        devslist = []
    8.50 +        for devid in self.deviceIDs():
    8.51 +            vusb_config = []
    8.52 +            backid = self.readFrontend(devid, 'backend-id')
    8.53 +            vusb_config.append(['backend-id', backid])
    8.54 +            state = self.readFrontend(devid, 'state')
    8.55 +            vusb_config.append(['state', state])
    8.56 +            backpath = self.readFrontend(devid, 'backend')
    8.57 +            vusb_config.append(['backend', backpath]) 
    8.58 +            usbver = self.readBackend(devid, 'usb-ver')
    8.59 +            vusb_config.append(['usb-ver', usbver])
    8.60 +            numports = self.readBackend(devid, 'num-ports') 
    8.61 +            vusb_config.append(['num-ports', numports])             
    8.62 +
    8.63 +            portpath = "port/"
    8.64 +            ports = ['port']
    8.65 +            for i in range(1, int(numports) + 1):
    8.66 +                bus = self.readBackend(devid, portpath + '%i' % i)
    8.67 +                ports.append(['%i' % i, str(bus)])
    8.68 +
    8.69 +            vusb_config.append(ports)             
    8.70 +            devslist.append([devid, vusb_config])
    8.71 +
    8.72 +        return devslist
    8.73 +
    8.74 +    def getDeviceDetails(self, config):
    8.75 +        """@see DevController.getDeviceDetails"""
    8.76 +        back = {}
    8.77 +        devid = self.allocateDeviceID()
    8.78 +        usbver = config.get('usb-ver', '')
    8.79 +        numports = config.get('num-ports', '')
    8.80 +        back['usb-ver'] = str(usbver)
    8.81 +        back['num-ports'] = str(numports)
    8.82 +        for i in range(1, int(numports) + 1):
    8.83 +            back['port/%i' % i] = config['port-%i' % i]
    8.84 +        return (devid, back, {})
    8.85 +
    8.86 +    def getDeviceConfiguration(self, devid, transaction = None):
    8.87 +        """@see DevController.configuration"""
    8.88 +        config = DevController.getDeviceConfiguration(self, devid, transaction)
    8.89 +        if transaction is None:
    8.90 +            hcinfo = self.readBackend(devid, 'usb-ver', 'num-ports')
    8.91 +        else:
    8.92 +            hcinfo = self.readBackendTxn(transaction, devid,
    8.93 +                                          'usb-ver', 'num-ports')
    8.94 +        (usbver, numports) = hcinfo
    8.95 +        config['usb-ver'] = str(usbver)
    8.96 +        config['num-ports'] = str(numports)
    8.97 +        for i in range(1, int(numports) + 1):
    8.98 +            if transaction is None:
    8.99 +                config['port-%i' % i] = self.readBackend(devid, 'port/%i' % i)
   8.100 +            else:
   8.101 +                config['port-%i' % i] = self.readBackendTxn(transaction, devid,
   8.102 +                                                             'port/%i' % i)
   8.103 +        return config
   8.104 +
   8.105 +    def reconfigureDevice(self, devid, config):
   8.106 +        """@see DevController.reconfigureDevice"""
   8.107 +        cur_config = self.getDeviceConfiguration(devid)
   8.108 +
   8.109 +        numports = cur_config['num-ports']
   8.110 +        for i in range(1, int(numports) + 1):
   8.111 +            if config.has_key('port-%i' % i):
   8.112 +                if not config['port-%i' % i] == cur_config['port-%i' % i]:
   8.113 +                    if not cur_config['port-%i' % i] == "":
   8.114 +                        vusb_util.unbind_usb_device(cur_config['port-%i' % i])
   8.115 +                    self.writeBackend(devid, 'port/%i' % i, 
   8.116 +                                      config['port-%i' % i])
   8.117 +                    if not config['port-%i' % i] == "":
   8.118 +                        vusb_util.bind_usb_device(config['port-%i' % i])
   8.119 +
   8.120 +        return self.readBackend(devid, 'uuid')
   8.121 +
   8.122 +    def waitForBackend(self, devid):
   8.123 +        return (0, "ok - no hotplug")
   8.124 +
   8.125 +    def waitForBackend_destroy(self, backpath):
   8.126 +        return 0
   8.127 +
   8.128 +    def migrate(self, deviceConfig, network, dst, step, domName):
   8.129 +        raise VmError('Migration not permitted with assigned USB device.')
     9.1 --- a/tools/python/xen/xm/create.py	Fri Dec 11 08:51:21 2009 +0000
     9.2 +++ b/tools/python/xen/xm/create.py	Fri Dec 11 08:52:17 2009 +0000
     9.3 @@ -350,6 +350,18 @@ gopts.var('vscsi', val='PDEV,VDEV[,DOM]'
     9.4            use="""Add a SCSI device to a domain. The physical device is PDEV,
     9.5            which is exported to the domain as VDEV(X:X:X:X).""")
     9.6  
     9.7 +gopts.var('vusb', val="usbver=USBVER,numports=NUMPORTS," + \
     9.8 +          "port_1=PORT1,port_2=PORT2,port_3=PORT3,port_4=PORT4" + \
     9.9 +          "port_5=PORT5,port_6=PORT6,port_7=PORT7,port_8=PORT8" + \
    9.10 +          "port_9=PORT9,port_10=PORT10,port_11=PORT11,port_12=PORT12" + \
    9.11 +          "port_13=PORT13,port_14=PORT14,port_15=PORT15,port_16=PORT16",
    9.12 +          fn=append_value, default=[],
    9.13 +          use="""Add a Virtual USB Host Controller to a domain.
    9.14 +          The USB Spec Version is usbver (1|2, default: 2).
    9.15 +          usbver=1 means USB1.1, usbver=2 mens USB2.0.
    9.16 +          The number of root ports is numports (1 to 16, default: 8).
    9.17 +          This option may be repeated to add more than one host controller.""")
    9.18 +
    9.19  gopts.var('ioports', val='FROM[-TO]',
    9.20            fn=append_value, default=[],
    9.21            use="""Add a legacy I/O range to a domain, using given params (in hex).
    9.22 @@ -849,6 +861,38 @@ def configure_vscsis(config_devs, vals):
    9.23              device.append(['backend', config['backend']])
    9.24          config_devs.append(['device', device])
    9.25  
    9.26 +def configure_vusbs(config_devs, vals):
    9.27 +    """Create the config for virtual usb host controllers.
    9.28 +    """
    9.29 +    for f in vals.vusb:
    9.30 +        d = comma_sep_kv_to_dict(f)
    9.31 +        config = ['vusb']
    9.32 +
    9.33 +        usbver = 2
    9.34 +        if d.has_key('usbver'):
    9.35 +            usbver = int(d['usbver'])
    9.36 +        if usbver == 1 or usbver == 2:
    9.37 +            config.append(['usb-ver', str(usbver)])
    9.38 +        else:
    9.39 +            err('Invalid vusb option: ' + 'usbver')
    9.40 +
    9.41 +        numports = 8
    9.42 +        if d.has_key('numports'):
    9.43 +            numports = d['numports']
    9.44 +        if int(numports) < 1 or int(numports) > 16:
    9.45 +            err('Invalid vusb option: ' + 'numports')
    9.46 +        config.append(['num-ports', str(numports)])
    9.47 +
    9.48 +        port_config = []
    9.49 +        for i in range(1, int(numports) + 1):
    9.50 +            if d.has_key('port_%i' % i):
    9.51 +                port_config.append(['%i' % i, str(d['port_%i' % i])])
    9.52 +            else:
    9.53 +                port_config.append(['%i' % i, ""])
    9.54 +        port_config.insert(0, 'port')
    9.55 +        config.append(port_config)
    9.56 +        config_devs.append(['device', config])        
    9.57 +
    9.58  def configure_ioports(config_devs, vals):
    9.59      """Create the config for legacy i/o ranges.
    9.60      """
    9.61 @@ -1103,6 +1147,7 @@ def make_config(vals):
    9.62      configure_disks(config_devs, vals)
    9.63      configure_pci(config_devs, vals)
    9.64      configure_vscsis(config_devs, vals)
    9.65 +    configure_vusbs(config_devs, vals)
    9.66      configure_ioports(config_devs, vals)
    9.67      configure_irq(config_devs, vals)
    9.68      configure_vifs(config_devs, vals)
    10.1 --- a/tools/python/xen/xm/main.py	Fri Dec 11 08:51:21 2009 +0000
    10.2 +++ b/tools/python/xen/xm/main.py	Fri Dec 11 08:52:17 2009 +0000
    10.3 @@ -39,6 +39,7 @@ import xml.dom.minidom
    10.4  from xen.util.blkif import blkdev_name_to_number
    10.5  from xen.util import vscsi_util
    10.6  from xen.util.pci import *
    10.7 +from xen.util import vusb_util
    10.8  
    10.9  import warnings
   10.10  warnings.filterwarnings('ignore', category=FutureWarning)
   10.11 @@ -211,6 +212,17 @@ SUBCOMMAND_HELP = {
   10.12                          'Detach a specified SCSI device.'),
   10.13      'scsi-list'    :  ('<Domain> [--long]',
   10.14                          'List all SCSI devices currently attached.'),
   10.15 +    'usb-attach'  :  ('<Domain> <DevId> <PortNumber> <BusId>',
   10.16 +                        'Attach a new USB physical bus to domain\'s virtual port.'),
   10.17 +    'usb-detach'  :  ('<Domain> <DevId> <PortNumber>',
   10.18 +                        'Detach a USB physical bus from domain\'s virtual port.'),
   10.19 +    'usb-list'    :  ('<Domain>',
   10.20 +                        'List domain\'s attachment state of all virtual port .'),
   10.21 +    'usb-list-assignable-devices' : ('', 'List all the assignable usb devices'),
   10.22 +    'usb-hc-create'  :  ('<Domain> <USBSpecVer> <NumberOfPorts>',
   10.23 +                        'Create a domain\'s new virtual USB host controller.'),
   10.24 +    'usb-hc-destroy'  :  ('<Domain> <DevId>',
   10.25 +                        'Destroy a domain\'s virtual USB host controller.'),
   10.26  
   10.27      # tmem
   10.28      'tmem-list'     :  ('[-l|--long] [<Domain>|-a|--all]', 'List tmem pools.'),
   10.29 @@ -429,6 +441,12 @@ device_commands = [
   10.30      "scsi-attach",
   10.31      "scsi-detach",
   10.32      "scsi-list",
   10.33 +    "usb-attach",
   10.34 +    "usb-detach",
   10.35 +    "usb-list",
   10.36 +    "usb-list-assignable-devices",
   10.37 +    "usb-hc-create",
   10.38 +    "usb-hc-destroy",
   10.39      ]
   10.40  
   10.41  vnet_commands = [
   10.42 @@ -2409,6 +2427,58 @@ def xm_scsi_list(args):
   10.43                  print "%(idx)-3d %(backend-id)-3d %(state)-5d %(feature-host)-4d " % ni,
   10.44                  print "%(p-dev)-10s %(p-devname)-5s %(v-dev)-10s %(frontstate)-4s" % mi
   10.45  
   10.46 +def xm_usb_list(args):
   10.47 +    xenapi_unsupported()
   10.48 +    arg_check(args, 'usb-list', 1)
   10.49 +    dom = args[0]
   10.50 +    devs = server.xend.domain.getDeviceSxprs(dom, 'vusb')
   10.51 +    for x in devs:
   10.52 +        print "%-3s %-3s %-5s %-7s  %-30s" \
   10.53 +            % ('Idx', 'BE', 'state', 'usb-ver', 'BE-path')
   10.54 +        ni = parse_dev_info(x[1])
   10.55 +        ni['idx'] = int(x[0])
   10.56 +        usbver = sxp.child_value(x[1], 'usb-ver')
   10.57 +        if int(usbver) == 1:
   10.58 +            ni['usb-ver'] = 'USB1.1'
   10.59 +        else:
   10.60 +            ni['usb-ver'] = 'USB2.0'
   10.61 +        print "%(idx)-3d %(backend-id)-3d %(state)-5d %(usb-ver)-7s %(be-path)-30s  " % ni
   10.62 +
   10.63 +        ports = sxp.child(x[1], 'port')
   10.64 +        for port in ports[1:]:
   10.65 +            try:
   10.66 +                num, bus = port
   10.67 +                if bus != "" and vusb_util.usb_device_is_connected(bus):
   10.68 +                        idvendor = vusb_util.get_usb_idvendor(bus)
   10.69 +                        idproduct = vusb_util.get_usb_idproduct(bus)
   10.70 +                        prodinfo = vusb_util.get_usbdevice_info(bus)
   10.71 +                        print "port %i: %s [ID %-4s:%-4s %s]" \
   10.72 +                            % (int(num), str(bus), idvendor, idproduct, prodinfo)
   10.73 +                else:
   10.74 +                    print "port %i: " % int(num) + str(bus)
   10.75 +            except TypeError:
   10.76 +                pass
   10.77 +
   10.78 +def xm_usb_list_assignable_devices(args):
   10.79 +    xenapi_unsupported()
   10.80 +    arg_check(args, 'usb-list-assignable-devices', 0)
   10.81 +
   10.82 +    usb_devs = vusb_util.get_usb_devices()
   10.83 +    buses = vusb_util.get_assigned_buses()
   10.84 +
   10.85 +    for x in buses:
   10.86 +        try:
   10.87 +            usb_devs.remove(x)
   10.88 +        except ValueError:
   10.89 +            pass
   10.90 +
   10.91 +    for dev in usb_devs:
   10.92 +        idvendor = vusb_util.get_usb_idvendor(dev)
   10.93 +        idproduct = vusb_util.get_usb_idproduct(dev)
   10.94 +        prodinfo = vusb_util.get_usbdevice_info(dev)
   10.95 +        print "%-13s: ID %-4s:%-4s %s" \
   10.96 +                % (dev, idvendor, idproduct, prodinfo)
   10.97 +
   10.98  def parse_block_configuration(args):
   10.99      dom = args[0]
  10.100  
  10.101 @@ -2757,6 +2827,64 @@ def xm_scsi_attach(args):
  10.102              scsi.append(['backend', args[3]])
  10.103          server.xend.domain.device_configure(dom, scsi)
  10.104  
  10.105 +def xm_usb_attach(args):
  10.106 +    xenapi_unsupported()
  10.107 +    arg_check(args, 'usb-attach', 4)
  10.108 +    dom = args[0]
  10.109 +    dev = args[1]
  10.110 +    port = args[2]
  10.111 +    bus = args[3]
  10.112 +
  10.113 +    dev_exist = 0
  10.114 +    num_ports = 0
  10.115 +    devs = server.xend.domain.getDeviceSxprs(dom, 'vusb')
  10.116 +    for x in devs:
  10.117 +        if int(x[0]) == int(dev):
  10.118 +            dev_exist = 1
  10.119 +            num_ports = sxp.child_value(x[1], 'num-ports')
  10.120 +
  10.121 +    if dev_exist == 0:
  10.122 +        print "Cannot find device '%s' in domain '%s'" % (dev,dom)
  10.123 +        return False
  10.124 +
  10.125 +    if int(port) < 1 or int(port) > int(num_ports):
  10.126 +        print "Invalid Port Number '%s'" % port
  10.127 +        return False
  10.128 +
  10.129 +    bus_match = re.match(r"(^(?P<bus>[0-9]{1,2})[-,])" + \
  10.130 +                         r"(?P<root_port>[0-9]{1,2})" + \
  10.131 +                         r"(?P<port>([\.,]{1}[0-9]{1,2}){0,5})$", bus)
  10.132 +    if bus_match is None:
  10.133 +        print "Invalid Busid '%s'" % bus
  10.134 +        return False
  10.135 +
  10.136 +    if vusb_util.bus_is_assigned(bus):
  10.137 +        print "Cannot assign already attached bus '%s', detach first." % bus
  10.138 +        return False
  10.139 +
  10.140 +    prev_bus = vusb_util.get_assigned_bus(domain_name_to_domid(dom), dev, port)
  10.141 +    if not prev_bus == "": 
  10.142 +        print "Cannot override already attached port '%s', detach first." % port
  10.143 +        return False
  10.144 +
  10.145 +    usb = ['vusb', ['port', [port, str(bus)]]]
  10.146 +    server.xend.domain.device_configure(dom, usb, dev)
  10.147 +
  10.148 +def xm_usb_hc_create(args):
  10.149 +    xenapi_unsupported()
  10.150 +    arg_check(args, 'usb-hc-create', 3)
  10.151 +    dom = args[0]
  10.152 +    ver = args[1]
  10.153 +    num = args[2]
  10.154 +    vusb_config = ['vusb']
  10.155 +    vusb_config.append(['usb-ver', str(ver)])
  10.156 +    vusb_config.append(['num-ports', str(num)])
  10.157 +    port_config = ['port']
  10.158 +    for i in range(1, int(num) + 1):
  10.159 +        port_config.append(['%i' % i, ""])
  10.160 +    vusb_config.append(port_config)
  10.161 +    server.xend.domain.device_create(dom, vusb_config)
  10.162 +
  10.163  def detach(args, deviceClass):
  10.164      rm_cfg = True
  10.165      dom = args[0]
  10.166 @@ -2942,6 +3070,22 @@ def xm_scsi_detach(args):
  10.167      else:
  10.168          server.xend.domain.device_configure(dom, scsi)
  10.169  
  10.170 +def xm_usb_detach(args):
  10.171 +    xenapi_unsupported()
  10.172 +    arg_check(args, 'usb-detach', 3)
  10.173 +    dom = args[0]
  10.174 +    dev = args[1]
  10.175 +    port = args[2]
  10.176 +    usb = ['vusb', ['port', [port, '']]]
  10.177 +    server.xend.domain.device_configure(dom, usb, dev)
  10.178 +
  10.179 +def xm_usb_hc_destroy(args):
  10.180 +    xenapi_unsupported()
  10.181 +    arg_check(args, 'usb-hc-destroy', 2)
  10.182 +    dom = args[0]
  10.183 +    dev = args[1]
  10.184 +    server.xend.domain.destroyDevice(dom, 'vusb', dev)
  10.185 +
  10.186  def xm_vnet_list(args):
  10.187      xenapi_unsupported()
  10.188      try:
  10.189 @@ -3372,6 +3516,13 @@ commands = {
  10.190      "scsi-attach": xm_scsi_attach,
  10.191      "scsi-detach": xm_scsi_detach,
  10.192      "scsi-list": xm_scsi_list,
  10.193 +    # vusb
  10.194 +    "usb-attach": xm_usb_attach,
  10.195 +    "usb-detach": xm_usb_detach,
  10.196 +    "usb-list": xm_usb_list,
  10.197 +    "usb-list-assignable-devices": xm_usb_list_assignable_devices,
  10.198 +    "usb-hc-create": xm_usb_hc_create,
  10.199 +    "usb-hc-destroy": xm_usb_hc_destroy,
  10.200      # tmem
  10.201      "tmem-thaw": xm_tmem_thaw,
  10.202      "tmem-freeze": xm_tmem_freeze,