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

[Xen-devel] [PATCH][RFC] PVUSB: xm/xend support



Hi,

Attached patches add xm/xend support for pvusb that I have
explained in the last Xen Summit.

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.

Both patches can be applied cleanly, but I have been testing
only with xen-3.4-testing.hg.

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

This is the initial version. I don't consider the command
interface is mature enough. Any comments and hacks are welcome.

Signed-off-by: Noboru Iwamatsu <n_iwamatsu@xxxxxxxxxxxxxx>
diff -r 20a0a2e75c52 -r 52f07c5779d8 tools/hotplug/Linux/xend.rules
--- a/tools/hotplug/Linux/xend.rules    Thu Dec 10 13:09:13 2009 +0900
+++ b/tools/hotplug/Linux/xend.rules    Thu Dec 10 14:04:34 2009 +0900
@@ -1,3 +1,4 @@
 SUBSYSTEM=="pci", RUN+="socket:/org/xen/xend/udev_event"
 SUBSYSTEM=="scsi", RUN+="socket:/org/xen/xend/udev_event"
+SUBSYSTEM=="usb", RUN+="socket:/org/xen/xend/udev_event"
 #SUBSYSTEM=="net", KERNEL!="vif[0-9]*.[0-9]*|tap[0-9]*.[0-9]*", 
RUN+="socket:/org/xen/xend/udev_event"
diff -r 20a0a2e75c52 -r 52f07c5779d8 tools/python/xen/util/vusb_util.py
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/python/xen/util/vusb_util.py        Thu Dec 10 14:04:34 2009 +0900
@@ -0,0 +1,338 @@
+#============================================================================
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of version 2.1 of the GNU Lesser General Public
+# License as published by the Free Software Foundation.
+#
+# This library 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.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#============================================================================
+# Copyright (C) 2009, FUJITSU LABORATORIES LTD.
+#  Author: Noboru Iwamatsu <n_iwamatsu@xxxxxxxxxxxxxx>
+#============================================================================
+
+
+"""Support for VUSB Devices.
+"""
+import os
+import os.path
+import sys
+import re
+import string
+from xen.util import utils
+
+SYSFS_USB_DEVS_PATH = '/bus/usb/devices'
+SYSFS_USB_DEV_BDEVICECLASS_PATH = '/bDeviceClass'
+SYSFS_USB_DEV_BDEVICESUBCLASS_PATH = '/bDeviceSubClass'
+SYSFS_USB_DEV_DEVNUM_PATH = '/devnum'
+SYSFS_USB_DEV_IDVENDOR_PATH = '/idVendor'
+SYSFS_USB_DEV_IDPRODUCT_PATH = '/idProduct'
+SYSFS_USB_DEV_MANUFACTURER_PATH = '/manufacturer'
+SYSFS_USB_DEV_PRODUCT_PATH = '/product'
+SYSFS_USB_DEV_SERIAL_PATH = '/serial'
+SYSFS_USB_DEV_DRIVER_PATH = '/driver'
+SYSFS_USB_DRIVER_BIND_PATH = '/bind'
+SYSFS_USB_DRIVER_UNBIND_PATH = '/unbind'
+SYSFS_USBBACK_PATH = '/bus/usb/drivers/usbback'
+SYSFS_PORTIDS_PATH = '/port_ids'
+USBHUB_CLASS_CODE = '09'
+
+def get_usb_bDeviceClass(dev):
+    try:
+        sysfs_mnt = utils.find_sysfs_mount() 
+        sysfs_usb_dev_path = \
+            os.path.join(sysfs_mnt + SYSFS_USB_DEVS_PATH, dev)
+        if os.path.exists(sysfs_usb_dev_path + 
SYSFS_USB_DEV_BDEVICECLASS_PATH):
+            usb_deviceclass = \
+                os.popen('cat ' + sysfs_usb_dev_path + \
+                              SYSFS_USB_DEV_BDEVICECLASS_PATH).readline()
+            return usb_deviceclass.splitlines()[0]
+        else:
+            return ""
+    except:
+        return None
+
+def get_usb_bDeviceSubClass(dev):
+    try:
+        sysfs_mnt = utils.find_sysfs_mount() 
+        sysfs_usb_dev_path = \
+            os.path.join(sysfs_mnt + SYSFS_USB_DEVS_PATH, dev)
+        if os.path.exists(sysfs_usb_dev_path + 
SYSFS_USB_DEV_BDEVICESUBCLASS_PATH):
+            usb_devicesubclass = \
+                os.popen('cat ' + sysfs_usb_dev_path + \
+                              SYSFS_USB_DEV_BDEVICESUBCLASS_PATH).readline()
+            return usb_devicesubclass.splitlines()[0]
+        else:
+            return ""
+    except:
+        return None
+
+def get_usb_devnum(dev):
+    try:
+        sysfs_mnt = utils.find_sysfs_mount() 
+        sysfs_usb_dev_path = \
+            os.path.join(sysfs_mnt + SYSFS_USB_DEVS_PATH, dev)
+        if os.path.exists(sysfs_usb_dev_path + SYSFS_USB_DEV_DEVNUM_PATH):
+            usb_devicesubclass = \
+                os.popen('cat ' + sysfs_usb_dev_path + \
+                              SYSFS_USB_DEV_DEVNUM_PATH).readline()
+            return usb_devicesubclass.splitlines()[0]
+        else:
+            return ""
+    except:
+        return None
+
+def get_usb_idvendor(dev):
+    try:
+        sysfs_mnt = utils.find_sysfs_mount() 
+        sysfs_usb_dev_path = \
+            os.path.join(sysfs_mnt + SYSFS_USB_DEVS_PATH, dev)
+        if os.path.exists(sysfs_usb_dev_path + SYSFS_USB_DEV_IDVENDOR_PATH):
+            usb_idvendor = \
+                os.popen('cat ' + sysfs_usb_dev_path + \
+                              SYSFS_USB_DEV_IDVENDOR_PATH).readline()
+            return usb_idvendor.splitlines()[0]
+        else:
+            return ""
+    except:
+        return None
+
+def get_usb_idproduct(dev):
+    try:
+        sysfs_mnt = utils.find_sysfs_mount() 
+        sysfs_usb_dev_path = \
+            os.path.join(sysfs_mnt + SYSFS_USB_DEVS_PATH, dev)
+        if os.path.exists(sysfs_usb_dev_path + SYSFS_USB_DEV_IDPRODUCT_PATH):
+            usb_idproduct = \
+                os.popen('cat ' + sysfs_usb_dev_path + \
+                              SYSFS_USB_DEV_IDPRODUCT_PATH).readline()
+            return usb_idproduct.splitlines()[0]
+        else:
+            return ""
+    except:
+        return None
+
+def get_usb_manufacturer(dev):
+    try:
+        sysfs_mnt = utils.find_sysfs_mount() 
+        sysfs_usb_dev_path = \
+            os.path.join(sysfs_mnt + SYSFS_USB_DEVS_PATH, dev)
+
+        if os.path.exists(sysfs_usb_dev_path + 
SYSFS_USB_DEV_MANUFACTURER_PATH):
+            usb_manufacturer = \
+                os.popen('cat ' + sysfs_usb_dev_path + \
+                              SYSFS_USB_DEV_MANUFACTURER_PATH).readline()
+            return usb_manufacturer.splitlines()[0]
+        else:
+            return ""
+    except:
+        return None
+
+def get_usb_product(dev):
+    try:
+        sysfs_mnt = utils.find_sysfs_mount() 
+        sysfs_usb_dev_path = \
+            os.path.join(sysfs_mnt + SYSFS_USB_DEVS_PATH, dev)
+        if os.path.exists(sysfs_usb_dev_path + SYSFS_USB_DEV_PRODUCT_PATH):
+            usb_product = \
+                os.popen('cat ' + sysfs_usb_dev_path + \
+                              SYSFS_USB_DEV_PRODUCT_PATH).readline()
+            return usb_product.splitlines()[0]
+        else:
+            return ""
+    except:
+        return None
+
+def get_usb_serial(dev):
+    try:
+        sysfs_mnt = utils.find_sysfs_mount() 
+        sysfs_usb_dev_path = \
+            os.path.join(sysfs_mnt + SYSFS_USB_DEVS_PATH, dev)
+        if os.path.exists(sysfs_usb_dev_path + SYSFS_USB_DEV_SERIAL_PATH):
+            usb_serial = \
+                os.popen('cat ' + sysfs_usb_dev_path + \
+                              SYSFS_USB_DEV_SERIAL_PATH).readline()
+            return usb_serial.splitlines()[0]
+        else:
+            return ""
+    except:
+        return None
+
+def get_usbdevice_info_by_lsusb(dev):
+    try:
+        vend = get_usb_idvendor(dev)
+        prod = get_usb_idproduct(dev)
+        output = os.popen('lsusb -d ' + vend + ':' + prod).readline().split()
+        text = ""
+        if len(output) > 6:
+            for str in output[6:]:
+                if text != "":
+                    text= text + ' '
+                text = text + str
+            return text
+        else:
+            return ""
+    except:
+        return None
+
+def get_usbdevice_info(dev):
+    try:
+        manuf = get_usb_manufacturer(dev)
+        prod = get_usb_product(dev)
+        if manuf == "" or prod == "":
+            return get_usbdevice_info_by_lsusb(dev)
+        else:
+            return manuf + ' ' + prod
+    except:
+        return None
+
+def usb_device_is_hub(dev):
+    usb_classcode = get_usb_bDeviceClass(dev)
+    if (usb_classcode == USBHUB_CLASS_CODE):
+        return True
+    else:
+        return False
+
+def get_all_usb_names():
+    usb_names = []
+    try:
+        sysfs_mnt = utils.find_sysfs_mount() 
+        usb_names = os.popen('ls ' + sysfs_mnt + 
SYSFS_USB_DEVS_PATH).read().split()
+    except:
+        pass
+    return usb_names
+
+def get_usb_devices():
+    devs = []
+    for name in get_all_usb_names():
+        dev_match = re.match(r"(^(?P<bus>[0-9]{1,2})[-,])" + \
+                     r"(?P<root_port>[0-9]{1,2})" + \
+                     r"(?P<port>([\.,]{1}[0-9]{1,2}){0,5})$", name)
+        if dev_match is not None:
+            dev = dev_match.group('bus') + '-' \
+            + dev_match.group('root_port') \
+            + dev_match.group('port') 
+            if (usb_device_is_hub(dev)):
+                continue
+            else:
+                devs.append(dev)
+    return devs
+
+def get_usb_intfs(dev):
+    intfs = []
+    try:
+        search = re.compile(r'^' + dev + ':')
+    except:
+        raise UsbDeviceParseError("Invalid expression.")
+    for name in get_all_usb_names():
+        if search.match(name):
+            intfs.append(name)
+    return intfs
+
+def get_assigned_buses():
+    buses = []
+    try:
+        sysfs_mnt = utils.find_sysfs_mount()
+        if os.path.exists(sysfs_mnt + SYSFS_USBBACK_PATH + SYSFS_PORTIDS_PATH):
+            portids = \
+                os.popen('cat ' + sysfs_mnt + SYSFS_USBBACK_PATH + 
SYSFS_PORTIDS_PATH).read().splitlines()
+            for portid in portids:
+                buses.append(portid.split(':')[0])
+    except:
+        raise UsbDeviceParseError("Can't get assigned buses from port_ids.")
+    return buses
+
+def get_assigned_bus(domid, dev, port):
+    bus = ""
+    try:
+        sysfs_mnt = utils.find_sysfs_mount()
+        if os.path.exists(sysfs_mnt + SYSFS_USBBACK_PATH + SYSFS_PORTIDS_PATH):
+            portids = \
+                os.popen('cat ' + sysfs_mnt + SYSFS_USBBACK_PATH + 
SYSFS_PORTIDS_PATH).read().splitlines()
+        for portid in portids:
+            if portid.split(':')[1] == str(domid) and portid.split(':')[2] == 
str(dev) and portid.split(':')[3] == str(port):
+                bus = portid.split(':')[0]
+    except:
+        raise UsbDeviceParseError("Can't get assigned bus (%d:%d:%d)." % 
(domid, dev, port))
+    return bus
+
+def bus_is_assigned(bus):
+    assigned = False    
+    try:
+        sysfs_mnt = utils.find_sysfs_mount()
+        if os.path.exists(sysfs_mnt + SYSFS_USBBACK_PATH + SYSFS_PORTIDS_PATH):
+            portids = \
+                os.popen('cat ' + sysfs_mnt + SYSFS_USBBACK_PATH + 
SYSFS_PORTIDS_PATH).read().splitlines()
+        for portid in portids:
+            if portid.split(':')[0] == bus:
+                assigned = True
+    except:
+        raise UsbDeviceParseError("Can't get assignment status: (%s)." % bus)
+    return assigned
+
+def usb_intf_is_binded(intf):
+    if os.path.exists(SYSFS_USBBACK_PATH + '/' + intf):
+        return True
+    else:
+        return False
+
+def usb_device_is_connected(dev):
+    try:
+        sysfs_mnt = utils.find_sysfs_mount()
+        sysfs_dev_path = \
+                os.path.join(sysfs_mnt + SYSFS_USB_DEVS_PATH, dev)
+        if os.path.exists(sysfs_dev_path):
+            return True
+        else:
+            return False
+    except:
+        raise UsbDeviceParseError("Can't get connection status (%s)." % dev)
+
+def unbind_usb_device(dev):
+    try:
+        sysfs_mnt = utils.find_sysfs_mount()
+        for intf in get_usb_intfs(dev): 
+            sysfs_usb_intf_path = \
+                os.path.join(sysfs_mnt + SYSFS_USB_DEVS_PATH, intf)
+            if os.path.exists(sysfs_usb_intf_path + SYSFS_USB_DEV_DRIVER_PATH):
+                fd = os.open(sysfs_usb_intf_path + \
+                             SYSFS_USB_DEV_DRIVER_PATH + \
+                             SYSFS_USB_DRIVER_UNBIND_PATH, os.O_WRONLY)
+                os.write(fd, intf)
+                os.close(fd)
+    except:
+        raise UsbDeviceBindingError("can't unbind intf (%s). " % intf)
+
+def bind_usb_device(dev):
+    try:
+        sysfs_mnt = utils.find_sysfs_mount()
+        for intf in get_usb_intfs(dev): 
+            sysfs_usb_intf_path = \
+                os.path.join(sysfs_mnt + SYSFS_USB_DEVS_PATH, intf)
+            if os.path.exists(sysfs_usb_intf_path + SYSFS_USB_DEV_DRIVER_PATH):
+                unbind_usb_device(dev)
+
+            fd = os.open(sysfs_mnt + SYSFS_USBBACK_PATH + \
+                         SYSFS_USB_DRIVER_BIND_PATH, os.O_WRONLY)
+            os.write(fd, intf)
+            os.close(fd)
+    except:
+        raise UsbDeviceBindingError("can't bind intf (%s). " % intf)
+
+class UsbDeviceParseError(Exception):
+    def __init__(self,msg):
+        self.message = msg
+    def __str__(self):
+        return 'vusb: Error parsing USB device info: '+self.message
+
+class UsbDeviceBindingError(Exception):
+    def __init__(self,msg):
+        self.message = msg
+    def __str__(self):
+        return 'vusb: Failed to bind/unbind USB device: ' + \
+            self.message
diff -r 20a0a2e75c52 -r 52f07c5779d8 tools/python/xen/xend/XendConfig.py
--- a/tools/python/xen/xend/XendConfig.py       Thu Dec 10 13:09:13 2009 +0900
+++ b/tools/python/xen/xend/XendConfig.py       Thu Dec 10 14:04:34 2009 +0900
@@ -1400,6 +1400,14 @@
                           (vscsi_devs, vscsi_mode))
                 return vscsi_devs_uuid
 
+            if dev_type == 'vusb':
+                vusb_devs_uuid = sxp.child_value(config, 'uuid',
+                                                uuid.createString())
+                vusb_dict = self.vusb_convert_sxp_to_dict(config)
+                vusb_dict['uuid'] = vusb_devs_uuid
+                target['devices'][vusb_devs_uuid] = (dev_type, vusb_dict)
+                return vusb_devs_uuid
+
             for opt_val in config[1:]:
                 try:
                     opt, val = opt_val
@@ -1776,6 +1784,68 @@
 
         return dev_config
 
+    def vusb_convert_sxp_to_dict(self, dev_sxp):
+        """Convert vusb device sxp to dict
+        @param dev_sxp: device configuration
+        @type  dev_sxp: SXP object (parsed config)
+        @return: dev_config
+        @rtype: dictionary
+        """
+        # Parsing USB devices SXP. 
+        #
+        # USB device's SXP looks like this:
+        #
+        # [device,
+        #   [vusb,
+        #     [usb-ver, 2],
+        #     [num-ports, 8],
+        #     [port,
+        #          [1, 1-1],
+        #          [2, 1-2],
+        #          [3, ''],
+        #          [4, ''],
+        #          [5, ''],
+        #          [6, ''],
+        #          [7, 6-2.1],        
+        #          [8, '']
+        #     ]
+        #   ],
+        #   [vusb,
+        #     [usb-ver, 1],
+        #     [num-ports, 2],
+        #     [port,
+        #          [1, 4-1],
+        #          [2, 4-2]
+        #     ]
+        #   ]  
+        # ]
+        #
+        # The dict looks like this
+        #
+        # { usb-ver: 2,
+        #   num-ports: 8,
+        #   port-1: 1-1,
+        #   port-2: 1-2,
+        #   port-3: "",
+        #   port-4: "",
+        #   port-5: "",
+        #   port-6: "",
+        #   port-7: "",
+        #   port-8: "" }
+
+        dev_config = {}
+        dev_config['usb-ver'] = sxp.child(dev_sxp, 'usb-ver')[1]
+        dev_config['num-ports'] = sxp.child(dev_sxp, 'num-ports')[1]
+        ports = sxp.child(dev_sxp, 'port')
+        for port in ports[1:]:
+            try:
+                num, bus = port
+                dev_config['port-%i' % int(num)] = str(bus)
+            except TypeError:
+                pass
+
+        return dev_config
+
     def console_add(self, protocol, location, other_config = {}):
         dev_uuid = uuid.createString()
         if protocol == 'vt100':
@@ -2002,6 +2072,18 @@
                 for pci_dev_info in dev_info['devs']:
                     sxpr.append(dev_dict_to_sxp(pci_dev_info))
                 sxprs.append((dev_type, sxpr))
+            elif dev_type == 'vusb':
+                sxpr = ['vusb', ['uuid', dev_info['uuid']],
+                                ['usb-ver', dev_info['usb-ver']],
+                                ['num-ports', dev_info['num-ports']]]
+                port_sxpr = ['port']
+                for i in range(1, int(dev_info['num-ports']) + 1):
+                    if dev_info.has_key('port-%i' % i):
+                        port_sxpr.append([i, str(dev_info['port-%i' % i])])
+                    else:
+                        port_sxpr.append([i, ""])
+                sxpr.append(port_sxpr)
+                sxprs.append((dev_type, sxpr))
             else:
                 sxpr = self.device_sxpr(dev_type = dev_type,
                                         dev_info = dev_info,
diff -r 20a0a2e75c52 -r 52f07c5779d8 tools/python/xen/xend/XendDevices.py
--- a/tools/python/xen/xend/XendDevices.py      Thu Dec 10 13:09:13 2009 +0900
+++ b/tools/python/xen/xend/XendDevices.py      Thu Dec 10 14:04:34 2009 +0900
@@ -19,7 +19,7 @@
 # A collection of DevControllers 
 #
 
-from xen.xend.server import blkif, netif, tpmif, pciif, iopif, irqif, vfbif, 
vscsiif, netif2
+from xen.xend.server import blkif, netif, tpmif, pciif, iopif, irqif, vfbif, 
vscsiif, netif2, vusbif
 from xen.xend.server.BlktapController import BlktapController, 
Blktap2Controller
 from xen.xend.server.ConsoleController import ConsoleController
 
@@ -48,6 +48,7 @@
         'vkbd': vfbif.VkbdifController,
         'console': ConsoleController,
         'vscsi': vscsiif.VSCSIController,
+        'vusb': vusbif.VUSBController,
     }
 
     #@classmethod
diff -r 20a0a2e75c52 -r 52f07c5779d8 tools/python/xen/xend/XendDomainInfo.py
--- a/tools/python/xen/xend/XendDomainInfo.py   Thu Dec 10 13:09:13 2009 +0900
+++ b/tools/python/xen/xend/XendDomainInfo.py   Thu Dec 10 14:04:34 2009 +0900
@@ -1102,6 +1102,27 @@
 
         return True
 
+    def vusb_device_configure(self, dev_sxp, devid):
+        """Configure a virtual root port.
+        """
+        dev_class = sxp.name(dev_sxp)
+        if dev_class != 'vusb':
+            return False
+
+        dev_config = {}
+        ports = sxp.child(dev_sxp, 'port')
+        for port in ports[1:]:
+            try:
+                num, bus = port
+                dev_config['port-%i' % int(num)] = str(bus)
+            except TypeError:
+                pass
+
+        dev_control = self.getDeviceController(dev_class)
+        dev_control.reconfigureDevice(devid, dev_config)
+
+        return True
+
     def device_configure(self, dev_sxp, devid = None):
         """Configure an existing device.
         
@@ -1123,6 +1144,9 @@
         if dev_class == 'vscsi':
             return self.vscsi_device_configure(dev_sxp)
 
+        if dev_class == 'vusb':
+            return self.vusb_device_configure(dev_sxp, devid)
+
         for opt_val in dev_sxp[1:]:
             try:
                 dev_config[opt_val[0]] = opt_val[1]
@@ -1378,6 +1402,13 @@
                 return dev_info
         return None
 
+    def _getDeviceInfo_vusb(self, devid):
+        for dev_type, dev_info in self.info.all_devices_sxpr():
+            if dev_type != 'vusb':
+                continue
+            return dev_info
+        return None
+
     def _get_assigned_pci_devices(self, devid = 0):
         if self.domid is not None:
             return get_assigned_pci_devices(self.domid)
diff -r 20a0a2e75c52 -r 52f07c5779d8 tools/python/xen/xend/XendNode.py
--- a/tools/python/xen/xend/XendNode.py Thu Dec 10 13:09:13 2009 +0900
+++ b/tools/python/xen/xend/XendNode.py Thu Dec 10 14:04:34 2009 +0900
@@ -24,6 +24,7 @@
 from xen.util import Brctl
 from xen.util import pci as PciUtil
 from xen.util import vscsi_util
+from xen.util import vusb_util
 from xen.xend import XendAPIStore
 from xen.xend import osdep
 from xen.xend.XendConstants import *
@@ -478,6 +479,20 @@
 
                 return
 
+    def add_usbdev(self, busid):
+        # if the adding usb device should be owned by usbback
+        # and is probed by other usb drivers, seize it!
+        bus, intf = busid.split(':')
+        buses = vusb_util.get_assigned_buses()
+        if str(bus) in buses:
+            if not vusb_util.usb_intf_is_binded(busid):
+                log.debug("add_usb(): %s is binded to other driver" % busid)
+                vusb_util.unbind_usb_device(bus)
+                vusb_util.bind_usb_device(bus)
+        return
+
+    def remove_usbdev(self, busid):
+        log.debug("remove_usbdev(): Not implemented.")
 
 ##    def network_destroy(self, net_uuid):
  ##       del self.networks[net_uuid]
diff -r 20a0a2e75c52 -r 52f07c5779d8 tools/python/xen/xend/server/udevevent.py
--- a/tools/python/xen/xend/server/udevevent.py Thu Dec 10 13:09:13 2009 +0900
+++ b/tools/python/xen/xend/server/udevevent.py Thu Dec 10 14:04:34 2009 +0900
@@ -60,6 +60,18 @@
                     log.info("Removing scsi device %s", hctl)
                     XendNode.instance().remove_PSCSI(hctl)
 
+            elif (udev_event.get('SUBSYSTEM', None) == 'usb'):
+                busid = udev_event.get('KERNEL', None)
+                if busid:
+                    if len(busid.split(':')) != 2:
+                        return
+                if (udev_event['ACTION'] == 'add'):
+                    log.info("Adding usb device %s", busid)
+                    XendNode.instance().add_usbdev(busid)
+                elif (udev_event['ACTION'] == 'remove'):
+                    log.info("Removing usb device %s", busid)
+                    XendNode.instance().remove_usbdev(busid)
+
             elif (udev_event.get('SUBSYSTEM', None) == 'net'):
                 interface = udev_event.get('INTERFACE', None)
                 if (udev_event['ACTION'] == 'add'):
diff -r 20a0a2e75c52 -r 52f07c5779d8 tools/python/xen/xend/server/vusbif.py
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/python/xen/xend/server/vusbif.py    Thu Dec 10 14:04:34 2009 +0900
@@ -0,0 +1,126 @@
+#============================================================================
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of version 2.1 of the GNU Lesser General Public
+# License as published by the Free Software Foundation.
+#
+# This library 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.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#============================================================================
+# Copyright (C) 2009, FUJITSU LABORATORIES LTD.
+#  Author: Noboru Iwamatsu <n_iwamatsu@xxxxxxxxxxxxxx>
+#============================================================================
+
+"""Support for virtual USB host controllers.
+"""
+import re
+import string
+
+import types
+
+from xen.xend import sxp
+from xen.xend.XendError import VmError
+from xen.xend.XendLogging import log
+
+from xen.xend.server.DevController import DevController
+from xen.xend.server.DevConstants import xenbusState
+from xen.xend.xenstore.xstransact import xstransact
+
+from xen.util import vusb_util
+
+class VUSBController(DevController):
+    """VUSB Devices.
+    """
+    def __init__(self, vm):
+        """Create a VUSB Devices.
+        """
+        DevController.__init__(self, vm)
+
+    def sxprs(self):
+        """@see DevController.sxprs"""
+        devslist = []
+        for devid in self.deviceIDs():
+            vusb_config = []
+            backid = self.readFrontend(devid, 'backend-id')
+            vusb_config.append(['backend-id', backid])
+            state = self.readFrontend(devid, 'state')
+            vusb_config.append(['state', state])
+            backpath = self.readFrontend(devid, 'backend')
+            vusb_config.append(['backend', backpath]) 
+            usbver = self.readBackend(devid, 'usb-ver')
+            vusb_config.append(['usb-ver', usbver])
+            numports = self.readBackend(devid, 'num-ports') 
+            vusb_config.append(['num-ports', numports])             
+
+            portpath = "port/"
+            ports = ['port']
+            for i in range(1, int(numports) + 1):
+                bus = self.readBackend(devid, portpath + '%i' % i)
+                ports.append(['%i' % i, str(bus)])
+
+            vusb_config.append(ports)             
+            devslist.append([devid, vusb_config])
+
+        return devslist
+
+    def getDeviceDetails(self, config):
+        """@see DevController.getDeviceDetails"""
+        back = {}
+        devid = self.allocateDeviceID()
+        usbver = config.get('usb-ver', '')
+        numports = config.get('num-ports', '')
+        back['usb-ver'] = str(usbver)
+        back['num-ports'] = str(numports)
+        for i in range(1, int(numports) + 1):
+            back['port/%i' % i] = config['port-%i' % i]
+        return (devid, back, {})
+
+    def getDeviceConfiguration(self, devid, transaction = None):
+        """@see DevController.configuration"""
+        config = DevController.getDeviceConfiguration(self, devid, transaction)
+        if transaction is None:
+            hcinfo = self.readBackend(devid, 'usb-ver', 'num-ports')
+        else:
+            hcinfo = self.readBackendTxn(transaction, devid,
+                                          'usb-ver', 'num-ports')
+        (usbver, numports) = hcinfo
+        config['usb-ver'] = str(usbver)
+        config['num-ports'] = str(numports)
+        for i in range(1, int(numports) + 1):
+            if transaction is None:
+                config['port-%i' % i] = self.readBackend(devid, 'port/%i' % i)
+            else:
+                config['port-%i' % i] = self.readBackendTxn(transaction, devid,
+                                                             'port/%i' % i)
+        return config
+
+    def reconfigureDevice(self, devid, config):
+        """@see DevController.reconfigureDevice"""
+        cur_config = self.getDeviceConfiguration(devid)
+
+        numports = cur_config['num-ports']
+        for i in range(1, int(numports) + 1):
+            if config.has_key('port-%i' % i):
+                if not config['port-%i' % i] == cur_config['port-%i' % i]:
+                    if not cur_config['port-%i' % i] == "":
+                        vusb_util.unbind_usb_device(cur_config['port-%i' % i])
+                    self.writeBackend(devid, 'port/%i' % i, 
+                                      config['port-%i' % i])
+                    if not config['port-%i' % i] == "":
+                        vusb_util.bind_usb_device(config['port-%i' % i])
+
+        return self.readBackend(devid, 'uuid')
+
+    def waitForBackend(self, devid):
+        return (0, "ok - no hotplug")
+
+    def waitForBackend_destroy(self, backpath):
+        return 0
+
+    def migrate(self, deviceConfig, network, dst, step, domName):
+        raise VmError('Migration not permitted with assigned USB device.')
diff -r 20a0a2e75c52 -r 52f07c5779d8 tools/python/xen/xm/create.py
--- a/tools/python/xen/xm/create.py     Thu Dec 10 13:09:13 2009 +0900
+++ b/tools/python/xen/xm/create.py     Thu Dec 10 14:04:34 2009 +0900
@@ -350,6 +350,18 @@
           use="""Add a SCSI device to a domain. The physical device is PDEV,
           which is exported to the domain as VDEV(X:X:X:X).""")
 
+gopts.var('vusb', val="usbver=USBVER,numports=NUMPORTS," + \
+          "port_1=PORT1,port_2=PORT2,port_3=PORT3,port_4=PORT4" + \
+          "port_5=PORT5,port_6=PORT6,port_7=PORT7,port_8=PORT8" + \
+          "port_9=PORT9,port_10=PORT10,port_11=PORT11,port_12=PORT12" + \
+          "port_13=PORT13,port_14=PORT14,port_15=PORT15,port_16=PORT16",
+          fn=append_value, default=[],
+          use="""Add a Virtual USB Host Controller to a domain.
+          The USB Spec Version is usbver (1|2, default: 2).
+          usbver=1 means USB1.1, usbver=2 mens USB2.0.
+          The number of root ports is numports (1 to 16, default: 8).
+          This option may be repeated to add more than one host controller.""")
+
 gopts.var('ioports', val='FROM[-TO]',
           fn=append_value, default=[],
           use="""Add a legacy I/O range to a domain, using given params (in 
hex).
@@ -849,6 +861,38 @@
             device.append(['backend', config['backend']])
         config_devs.append(['device', device])
 
+def configure_vusbs(config_devs, vals):
+    """Create the config for virtual usb host controllers.
+    """
+    for f in vals.vusb:
+        d = comma_sep_kv_to_dict(f)
+        config = ['vusb']
+
+        usbver = 2
+        if d.has_key('usbver'):
+            usbver = int(d['usbver'])
+        if usbver == 1 or usbver == 2:
+            config.append(['usb-ver', str(usbver)])
+        else:
+            err('Invalid vusb option: ' + 'usbver')
+
+        numports = 8
+        if d.has_key('numports'):
+            numports = d['numports']
+        if int(numports) < 1 or int(numports) > 16:
+            err('Invalid vusb option: ' + 'numports')
+        config.append(['num-ports', str(numports)])
+
+        port_config = []
+        for i in range(1, int(numports) + 1):
+            if d.has_key('port_%i' % i):
+                port_config.append(['%i' % i, str(d['port_%i' % i])])
+            else:
+                port_config.append(['%i' % i, ""])
+        port_config.insert(0, 'port')
+        config.append(port_config)
+        config_devs.append(['device', config])        
+
 def configure_ioports(config_devs, vals):
     """Create the config for legacy i/o ranges.
     """
@@ -1103,6 +1147,7 @@
     configure_disks(config_devs, vals)
     configure_pci(config_devs, vals)
     configure_vscsis(config_devs, vals)
+    configure_vusbs(config_devs, vals)
     configure_ioports(config_devs, vals)
     configure_irq(config_devs, vals)
     configure_vifs(config_devs, vals)
diff -r 20a0a2e75c52 -r 52f07c5779d8 tools/python/xen/xm/main.py
--- a/tools/python/xen/xm/main.py       Thu Dec 10 13:09:13 2009 +0900
+++ b/tools/python/xen/xm/main.py       Thu Dec 10 14:04:34 2009 +0900
@@ -39,6 +39,7 @@
 from xen.util.blkif import blkdev_name_to_number
 from xen.util import vscsi_util
 from xen.util.pci import *
+from xen.util import vusb_util
 
 import warnings
 warnings.filterwarnings('ignore', category=FutureWarning)
@@ -211,6 +212,17 @@
                         'Detach a specified SCSI device.'),
     'scsi-list'    :  ('<Domain> [--long]',
                         'List all SCSI devices currently attached.'),
+    'usb-attach'  :  ('<Domain> <DevId> <PortNumber> <BusId>',
+                        'Attach a new USB physical bus to domain\'s virtual 
port.'),
+    'usb-detach'  :  ('<Domain> <DevId> <PortNumber>',
+                        'Detach a USB physical bus from domain\'s virtual 
port.'),
+    'usb-list'    :  ('<Domain>',
+                        'List domain\'s attachment state of all virtual port 
.'),
+    'usb-list-assignable-devices' : ('', 'List all the assignable usb 
devices'),
+    'usb-hc-create'  :  ('<Domain> <USBSpecVer> <NumberOfPorts>',
+                        'Create a domain\'s new virtual USB host controller.'),
+    'usb-hc-destroy'  :  ('<Domain> <DevId>',
+                        'Destroy a domain\'s virtual USB host controller.'),
 
     # tmem
     'tmem-list'     :  ('[-l|--long] [<Domain>|-a|--all]', 'List tmem pools.'),
@@ -429,6 +441,12 @@
     "scsi-attach",
     "scsi-detach",
     "scsi-list",
+    "usb-attach",
+    "usb-detach",
+    "usb-list",
+    "usb-list-assignable-devices",
+    "usb-hc-create",
+    "usb-hc-destroy",
     ]
 
 vnet_commands = [
@@ -2409,6 +2427,58 @@
                 print "%(idx)-3d %(backend-id)-3d %(state)-5d 
%(feature-host)-4d " % ni,
                 print "%(p-dev)-10s %(p-devname)-5s %(v-dev)-10s 
%(frontstate)-4s" % mi
 
+def xm_usb_list(args):
+    xenapi_unsupported()
+    arg_check(args, 'usb-list', 1)
+    dom = args[0]
+    devs = server.xend.domain.getDeviceSxprs(dom, 'vusb')
+    for x in devs:
+        print "%-3s %-3s %-5s %-7s  %-30s" \
+            % ('Idx', 'BE', 'state', 'usb-ver', 'BE-path')
+        ni = parse_dev_info(x[1])
+        ni['idx'] = int(x[0])
+        usbver = sxp.child_value(x[1], 'usb-ver')
+        if int(usbver) == 1:
+            ni['usb-ver'] = 'USB1.1'
+        else:
+            ni['usb-ver'] = 'USB2.0'
+        print "%(idx)-3d %(backend-id)-3d %(state)-5d %(usb-ver)-7s 
%(be-path)-30s  " % ni
+
+        ports = sxp.child(x[1], 'port')
+        for port in ports[1:]:
+            try:
+                num, bus = port
+                if bus != "" and vusb_util.usb_device_is_connected(bus):
+                        idvendor = vusb_util.get_usb_idvendor(bus)
+                        idproduct = vusb_util.get_usb_idproduct(bus)
+                        prodinfo = vusb_util.get_usbdevice_info(bus)
+                        print "port %i: %s [ID %-4s:%-4s %s]" \
+                            % (int(num), str(bus), idvendor, idproduct, 
prodinfo)
+                else:
+                    print "port %i: " % int(num) + str(bus)
+            except TypeError:
+                pass
+
+def xm_usb_list_assignable_devices(args):
+    xenapi_unsupported()
+    arg_check(args, 'usb-list-assignable-devices', 0)
+
+    usb_devs = vusb_util.get_usb_devices()
+    buses = vusb_util.get_assigned_buses()
+
+    for x in buses:
+        try:
+            usb_devs.remove(x)
+        except ValueError:
+            pass
+
+    for dev in usb_devs:
+        idvendor = vusb_util.get_usb_idvendor(dev)
+        idproduct = vusb_util.get_usb_idproduct(dev)
+        prodinfo = vusb_util.get_usbdevice_info(dev)
+        print "%-13s: ID %-4s:%-4s %s" \
+                % (dev, idvendor, idproduct, prodinfo)
+
 def parse_block_configuration(args):
     dom = args[0]
 
@@ -2757,6 +2827,64 @@
             scsi.append(['backend', args[3]])
         server.xend.domain.device_configure(dom, scsi)
 
+def xm_usb_attach(args):
+    xenapi_unsupported()
+    arg_check(args, 'usb-attach', 4)
+    dom = args[0]
+    dev = args[1]
+    port = args[2]
+    bus = args[3]
+
+    dev_exist = 0
+    num_ports = 0
+    devs = server.xend.domain.getDeviceSxprs(dom, 'vusb')
+    for x in devs:
+        if int(x[0]) == int(dev):
+            dev_exist = 1
+            num_ports = sxp.child_value(x[1], 'num-ports')
+
+    if dev_exist == 0:
+        print "Cannot find device '%s' in domain '%s'" % (dev,dom)
+        return False
+
+    if int(port) < 1 or int(port) > int(num_ports):
+        print "Invalid Port Number '%s'" % port
+        return False
+
+    bus_match = re.match(r"(^(?P<bus>[0-9]{1,2})[-,])" + \
+                         r"(?P<root_port>[0-9]{1,2})" + \
+                         r"(?P<port>([\.,]{1}[0-9]{1,2}){0,5})$", bus)
+    if bus_match is None:
+        print "Invalid Busid '%s'" % bus
+        return False
+
+    if vusb_util.bus_is_assigned(bus):
+        print "Cannot assign already attached bus '%s', detach first." % bus
+        return False
+
+    prev_bus = vusb_util.get_assigned_bus(domain_name_to_domid(dom), dev, port)
+    if not prev_bus == "": 
+        print "Cannot override already attached port '%s', detach first." % 
port
+        return False
+
+    usb = ['vusb', ['port', [port, str(bus)]]]
+    server.xend.domain.device_configure(dom, usb, dev)
+
+def xm_usb_hc_create(args):
+    xenapi_unsupported()
+    arg_check(args, 'usb-hc-create', 3)
+    dom = args[0]
+    ver = args[1]
+    num = args[2]
+    vusb_config = ['vusb']
+    vusb_config.append(['usb-ver', str(ver)])
+    vusb_config.append(['num-ports', str(num)])
+    port_config = ['port']
+    for i in range(1, int(num) + 1):
+        port_config.append(['%i' % i, ""])
+    vusb_config.append(port_config)
+    server.xend.domain.device_create(dom, vusb_config)
+
 def detach(args, deviceClass):
     rm_cfg = True
     dom = args[0]
@@ -2942,6 +3070,22 @@
     else:
         server.xend.domain.device_configure(dom, scsi)
 
+def xm_usb_detach(args):
+    xenapi_unsupported()
+    arg_check(args, 'usb-detach', 3)
+    dom = args[0]
+    dev = args[1]
+    port = args[2]
+    usb = ['vusb', ['port', [port, '']]]
+    server.xend.domain.device_configure(dom, usb, dev)
+
+def xm_usb_hc_destroy(args):
+    xenapi_unsupported()
+    arg_check(args, 'usb-hc-destroy', 2)
+    dom = args[0]
+    dev = args[1]
+    server.xend.domain.destroyDevice(dom, 'vusb', dev)
+
 def xm_vnet_list(args):
     xenapi_unsupported()
     try:
@@ -3372,6 +3516,13 @@
     "scsi-attach": xm_scsi_attach,
     "scsi-detach": xm_scsi_detach,
     "scsi-list": xm_scsi_list,
+    # vusb
+    "usb-attach": xm_usb_attach,
+    "usb-detach": xm_usb_detach,
+    "usb-list": xm_usb_list,
+    "usb-list-assignable-devices": xm_usb_list_assignable_devices,
+    "usb-hc-create": xm_usb_hc_create,
+    "usb-hc-destroy": xm_usb_hc_destroy,
     # tmem
     "tmem-thaw": xm_tmem_thaw,
     "tmem-freeze": xm_tmem_freeze,
diff -r d12425fad689 -r 8772e0bc4b9a tools/hotplug/Linux/xend.rules
--- a/tools/hotplug/Linux/xend.rules    Mon Dec 07 18:17:36 2009 +0900
+++ b/tools/hotplug/Linux/xend.rules    Thu Dec 10 14:03:25 2009 +0900
@@ -1,3 +1,4 @@
 SUBSYSTEM=="pci", RUN+="socket:/org/xen/xend/udev_event"
 SUBSYSTEM=="scsi", RUN+="socket:/org/xen/xend/udev_event"
+SUBSYSTEM=="usb", RUN+="socket:/org/xen/xend/udev_event"
 #SUBSYSTEM=="net", KERNEL!="vif[0-9]*.[0-9]*|tap[0-9]*.[0-9]*", 
RUN+="socket:/org/xen/xend/udev_event"
diff -r d12425fad689 -r 8772e0bc4b9a tools/python/xen/util/vusb_util.py
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/python/xen/util/vusb_util.py        Thu Dec 10 14:03:25 2009 +0900
@@ -0,0 +1,338 @@
+#============================================================================
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of version 2.1 of the GNU Lesser General Public
+# License as published by the Free Software Foundation.
+#
+# This library 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.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#============================================================================
+# Copyright (C) 2009, FUJITSU LABORATORIES LTD.
+#  Author: Noboru Iwamatsu <n_iwamatsu@xxxxxxxxxxxxxx>
+#============================================================================
+
+
+"""Support for VUSB Devices.
+"""
+import os
+import os.path
+import sys
+import re
+import string
+from xen.util import utils
+
+SYSFS_USB_DEVS_PATH = '/bus/usb/devices'
+SYSFS_USB_DEV_BDEVICECLASS_PATH = '/bDeviceClass'
+SYSFS_USB_DEV_BDEVICESUBCLASS_PATH = '/bDeviceSubClass'
+SYSFS_USB_DEV_DEVNUM_PATH = '/devnum'
+SYSFS_USB_DEV_IDVENDOR_PATH = '/idVendor'
+SYSFS_USB_DEV_IDPRODUCT_PATH = '/idProduct'
+SYSFS_USB_DEV_MANUFACTURER_PATH = '/manufacturer'
+SYSFS_USB_DEV_PRODUCT_PATH = '/product'
+SYSFS_USB_DEV_SERIAL_PATH = '/serial'
+SYSFS_USB_DEV_DRIVER_PATH = '/driver'
+SYSFS_USB_DRIVER_BIND_PATH = '/bind'
+SYSFS_USB_DRIVER_UNBIND_PATH = '/unbind'
+SYSFS_USBBACK_PATH = '/bus/usb/drivers/usbback'
+SYSFS_PORTIDS_PATH = '/port_ids'
+USBHUB_CLASS_CODE = '09'
+
+def get_usb_bDeviceClass(dev):
+    try:
+        sysfs_mnt = utils.find_sysfs_mount() 
+        sysfs_usb_dev_path = \
+            os.path.join(sysfs_mnt + SYSFS_USB_DEVS_PATH, dev)
+        if os.path.exists(sysfs_usb_dev_path + 
SYSFS_USB_DEV_BDEVICECLASS_PATH):
+            usb_deviceclass = \
+                os.popen('cat ' + sysfs_usb_dev_path + \
+                              SYSFS_USB_DEV_BDEVICECLASS_PATH).readline()
+            return usb_deviceclass.splitlines()[0]
+        else:
+            return ""
+    except:
+        return None
+
+def get_usb_bDeviceSubClass(dev):
+    try:
+        sysfs_mnt = utils.find_sysfs_mount() 
+        sysfs_usb_dev_path = \
+            os.path.join(sysfs_mnt + SYSFS_USB_DEVS_PATH, dev)
+        if os.path.exists(sysfs_usb_dev_path + 
SYSFS_USB_DEV_BDEVICESUBCLASS_PATH):
+            usb_devicesubclass = \
+                os.popen('cat ' + sysfs_usb_dev_path + \
+                              SYSFS_USB_DEV_BDEVICESUBCLASS_PATH).readline()
+            return usb_devicesubclass.splitlines()[0]
+        else:
+            return ""
+    except:
+        return None
+
+def get_usb_devnum(dev):
+    try:
+        sysfs_mnt = utils.find_sysfs_mount() 
+        sysfs_usb_dev_path = \
+            os.path.join(sysfs_mnt + SYSFS_USB_DEVS_PATH, dev)
+        if os.path.exists(sysfs_usb_dev_path + SYSFS_USB_DEV_DEVNUM_PATH):
+            usb_devicesubclass = \
+                os.popen('cat ' + sysfs_usb_dev_path + \
+                              SYSFS_USB_DEV_DEVNUM_PATH).readline()
+            return usb_devicesubclass.splitlines()[0]
+        else:
+            return ""
+    except:
+        return None
+
+def get_usb_idvendor(dev):
+    try:
+        sysfs_mnt = utils.find_sysfs_mount() 
+        sysfs_usb_dev_path = \
+            os.path.join(sysfs_mnt + SYSFS_USB_DEVS_PATH, dev)
+        if os.path.exists(sysfs_usb_dev_path + SYSFS_USB_DEV_IDVENDOR_PATH):
+            usb_idvendor = \
+                os.popen('cat ' + sysfs_usb_dev_path + \
+                              SYSFS_USB_DEV_IDVENDOR_PATH).readline()
+            return usb_idvendor.splitlines()[0]
+        else:
+            return ""
+    except:
+        return None
+
+def get_usb_idproduct(dev):
+    try:
+        sysfs_mnt = utils.find_sysfs_mount() 
+        sysfs_usb_dev_path = \
+            os.path.join(sysfs_mnt + SYSFS_USB_DEVS_PATH, dev)
+        if os.path.exists(sysfs_usb_dev_path + SYSFS_USB_DEV_IDPRODUCT_PATH):
+            usb_idproduct = \
+                os.popen('cat ' + sysfs_usb_dev_path + \
+                              SYSFS_USB_DEV_IDPRODUCT_PATH).readline()
+            return usb_idproduct.splitlines()[0]
+        else:
+            return ""
+    except:
+        return None
+
+def get_usb_manufacturer(dev):
+    try:
+        sysfs_mnt = utils.find_sysfs_mount() 
+        sysfs_usb_dev_path = \
+            os.path.join(sysfs_mnt + SYSFS_USB_DEVS_PATH, dev)
+
+        if os.path.exists(sysfs_usb_dev_path + 
SYSFS_USB_DEV_MANUFACTURER_PATH):
+            usb_manufacturer = \
+                os.popen('cat ' + sysfs_usb_dev_path + \
+                              SYSFS_USB_DEV_MANUFACTURER_PATH).readline()
+            return usb_manufacturer.splitlines()[0]
+        else:
+            return ""
+    except:
+        return None
+
+def get_usb_product(dev):
+    try:
+        sysfs_mnt = utils.find_sysfs_mount() 
+        sysfs_usb_dev_path = \
+            os.path.join(sysfs_mnt + SYSFS_USB_DEVS_PATH, dev)
+        if os.path.exists(sysfs_usb_dev_path + SYSFS_USB_DEV_PRODUCT_PATH):
+            usb_product = \
+                os.popen('cat ' + sysfs_usb_dev_path + \
+                              SYSFS_USB_DEV_PRODUCT_PATH).readline()
+            return usb_product.splitlines()[0]
+        else:
+            return ""
+    except:
+        return None
+
+def get_usb_serial(dev):
+    try:
+        sysfs_mnt = utils.find_sysfs_mount() 
+        sysfs_usb_dev_path = \
+            os.path.join(sysfs_mnt + SYSFS_USB_DEVS_PATH, dev)
+        if os.path.exists(sysfs_usb_dev_path + SYSFS_USB_DEV_SERIAL_PATH):
+            usb_serial = \
+                os.popen('cat ' + sysfs_usb_dev_path + \
+                              SYSFS_USB_DEV_SERIAL_PATH).readline()
+            return usb_serial.splitlines()[0]
+        else:
+            return ""
+    except:
+        return None
+
+def get_usbdevice_info_by_lsusb(dev):
+    try:
+        vend = get_usb_idvendor(dev)
+        prod = get_usb_idproduct(dev)
+        output = os.popen('lsusb -d ' + vend + ':' + prod).readline().split()
+        text = ""
+        if len(output) > 6:
+            for str in output[6:]:
+                if text != "":
+                    text= text + ' '
+                text = text + str
+            return text
+        else:
+            return ""
+    except:
+        return None
+
+def get_usbdevice_info(dev):
+    try:
+        manuf = get_usb_manufacturer(dev)
+        prod = get_usb_product(dev)
+        if manuf == "" or prod == "":
+            return get_usbdevice_info_by_lsusb(dev)
+        else:
+            return manuf + ' ' + prod
+    except:
+        return None
+
+def usb_device_is_hub(dev):
+    usb_classcode = get_usb_bDeviceClass(dev)
+    if (usb_classcode == USBHUB_CLASS_CODE):
+        return True
+    else:
+        return False
+
+def get_all_usb_names():
+    usb_names = []
+    try:
+        sysfs_mnt = utils.find_sysfs_mount() 
+        usb_names = os.popen('ls ' + sysfs_mnt + 
SYSFS_USB_DEVS_PATH).read().split()
+    except:
+        pass
+    return usb_names
+
+def get_usb_devices():
+    devs = []
+    for name in get_all_usb_names():
+        dev_match = re.match(r"(^(?P<bus>[0-9]{1,2})[-,])" + \
+                     r"(?P<root_port>[0-9]{1,2})" + \
+                     r"(?P<port>([\.,]{1}[0-9]{1,2}){0,5})$", name)
+        if dev_match is not None:
+            dev = dev_match.group('bus') + '-' \
+            + dev_match.group('root_port') \
+            + dev_match.group('port') 
+            if (usb_device_is_hub(dev)):
+                continue
+            else:
+                devs.append(dev)
+    return devs
+
+def get_usb_intfs(dev):
+    intfs = []
+    try:
+        search = re.compile(r'^' + dev + ':')
+    except:
+        raise UsbDeviceParseError("Invalid expression.")
+    for name in get_all_usb_names():
+        if search.match(name):
+            intfs.append(name)
+    return intfs
+
+def get_assigned_buses():
+    buses = []
+    try:
+        sysfs_mnt = utils.find_sysfs_mount()
+        if os.path.exists(sysfs_mnt + SYSFS_USBBACK_PATH + SYSFS_PORTIDS_PATH):
+            portids = \
+                os.popen('cat ' + sysfs_mnt + SYSFS_USBBACK_PATH + 
SYSFS_PORTIDS_PATH).read().splitlines()
+            for portid in portids:
+                buses.append(portid.split(':')[0])
+    except:
+        raise UsbDeviceParseError("Can't get assigned buses from port_ids.")
+    return buses
+
+def get_assigned_bus(domid, dev, port):
+    bus = ""
+    try:
+        sysfs_mnt = utils.find_sysfs_mount()
+        if os.path.exists(sysfs_mnt + SYSFS_USBBACK_PATH + SYSFS_PORTIDS_PATH):
+            portids = \
+                os.popen('cat ' + sysfs_mnt + SYSFS_USBBACK_PATH + 
SYSFS_PORTIDS_PATH).read().splitlines()
+        for portid in portids:
+            if portid.split(':')[1] == str(domid) and portid.split(':')[2] == 
str(dev) and portid.split(':')[3] == str(port):
+                bus = portid.split(':')[0]
+    except:
+        raise UsbDeviceParseError("Can't get assigned bus (%d:%d:%d)." % 
(domid, dev, port))
+    return bus
+
+def bus_is_assigned(bus):
+    assigned = False    
+    try:
+        sysfs_mnt = utils.find_sysfs_mount()
+        if os.path.exists(sysfs_mnt + SYSFS_USBBACK_PATH + SYSFS_PORTIDS_PATH):
+            portids = \
+                os.popen('cat ' + sysfs_mnt + SYSFS_USBBACK_PATH + 
SYSFS_PORTIDS_PATH).read().splitlines()
+        for portid in portids:
+            if portid.split(':')[0] == bus:
+                assigned = True
+    except:
+        raise UsbDeviceParseError("Can't get assignment status: (%s)." % bus)
+    return assigned
+
+def usb_intf_is_binded(intf):
+    if os.path.exists(SYSFS_USBBACK_PATH + '/' + intf):
+        return True
+    else:
+        return False
+
+def usb_device_is_connected(dev):
+    try:
+        sysfs_mnt = utils.find_sysfs_mount()
+        sysfs_dev_path = \
+                os.path.join(sysfs_mnt + SYSFS_USB_DEVS_PATH, dev)
+        if os.path.exists(sysfs_dev_path):
+            return True
+        else:
+            return False
+    except:
+        raise UsbDeviceParseError("Can't get connection status (%s)." % dev)
+
+def unbind_usb_device(dev):
+    try:
+        sysfs_mnt = utils.find_sysfs_mount()
+        for intf in get_usb_intfs(dev): 
+            sysfs_usb_intf_path = \
+                os.path.join(sysfs_mnt + SYSFS_USB_DEVS_PATH, intf)
+            if os.path.exists(sysfs_usb_intf_path + SYSFS_USB_DEV_DRIVER_PATH):
+                fd = os.open(sysfs_usb_intf_path + \
+                             SYSFS_USB_DEV_DRIVER_PATH + \
+                             SYSFS_USB_DRIVER_UNBIND_PATH, os.O_WRONLY)
+                os.write(fd, intf)
+                os.close(fd)
+    except:
+        raise UsbDeviceBindingError("can't unbind intf (%s). " % intf)
+
+def bind_usb_device(dev):
+    try:
+        sysfs_mnt = utils.find_sysfs_mount()
+        for intf in get_usb_intfs(dev): 
+            sysfs_usb_intf_path = \
+                os.path.join(sysfs_mnt + SYSFS_USB_DEVS_PATH, intf)
+            if os.path.exists(sysfs_usb_intf_path + SYSFS_USB_DEV_DRIVER_PATH):
+                unbind_usb_device(dev)
+
+            fd = os.open(sysfs_mnt + SYSFS_USBBACK_PATH + \
+                         SYSFS_USB_DRIVER_BIND_PATH, os.O_WRONLY)
+            os.write(fd, intf)
+            os.close(fd)
+    except:
+        raise UsbDeviceBindingError("can't bind intf (%s). " % intf)
+
+class UsbDeviceParseError(Exception):
+    def __init__(self,msg):
+        self.message = msg
+    def __str__(self):
+        return 'vusb: Error parsing USB device info: '+self.message
+
+class UsbDeviceBindingError(Exception):
+    def __init__(self,msg):
+        self.message = msg
+    def __str__(self):
+        return 'vusb: Failed to bind/unbind USB device: ' + \
+            self.message
diff -r d12425fad689 -r 8772e0bc4b9a tools/python/xen/xend/XendConfig.py
--- a/tools/python/xen/xend/XendConfig.py       Mon Dec 07 18:17:36 2009 +0900
+++ b/tools/python/xen/xend/XendConfig.py       Thu Dec 10 14:03:25 2009 +0900
@@ -1335,6 +1335,14 @@
                           (vscsi_devs, vscsi_mode))
                 return vscsi_devs_uuid
 
+            if dev_type == 'vusb':
+                vusb_devs_uuid = sxp.child_value(config, 'uuid',
+                                                uuid.createString())
+                vusb_dict = self.vusb_convert_sxp_to_dict(config)
+                vusb_dict['uuid'] = vusb_devs_uuid
+                target['devices'][vusb_devs_uuid] = (dev_type, vusb_dict)
+                return vusb_devs_uuid
+
             for opt_val in config[1:]:
                 try:
                     opt, val = opt_val
@@ -1763,6 +1771,68 @@
 
         return dev_config
 
+    def vusb_convert_sxp_to_dict(self, dev_sxp):
+        """Convert vusb device sxp to dict
+        @param dev_sxp: device configuration
+        @type  dev_sxp: SXP object (parsed config)
+        @return: dev_config
+        @rtype: dictionary
+        """
+        # Parsing USB devices SXP. 
+        #
+        # USB device's SXP looks like this:
+        #
+        # [device,
+        #   [vusb,
+        #     [usb-ver, 2],
+        #     [num-ports, 8],
+        #     [port,
+        #          [1, 1-1],
+        #          [2, 1-2],
+        #          [3, ''],
+        #          [4, ''],
+        #          [5, ''],
+        #          [6, ''],
+        #          [7, 6-2.1],        
+        #          [8, '']
+        #     ]
+        #   ],
+        #   [vusb,
+        #     [usb-ver, 1],
+        #     [num-ports, 2],
+        #     [port,
+        #          [1, 4-1],
+        #          [2, 4-2]
+        #     ]
+        #   ]  
+        # ]
+        #
+        # The dict looks like this
+        #
+        # { usb-ver: 2,
+        #   num-ports: 8,
+        #   port-1: 1-1,
+        #   port-2: 1-2,
+        #   port-3: "",
+        #   port-4: "",
+        #   port-5: "",
+        #   port-6: "",
+        #   port-7: "",
+        #   port-8: "" }
+
+        dev_config = {}
+        dev_config['usb-ver'] = sxp.child(dev_sxp, 'usb-ver')[1]
+        dev_config['num-ports'] = sxp.child(dev_sxp, 'num-ports')[1]
+        ports = sxp.child(dev_sxp, 'port')
+        for port in ports[1:]:
+            try:
+                num, bus = port
+                dev_config['port-%i' % int(num)] = str(bus)
+            except TypeError:
+                pass
+
+        return dev_config
+
     def console_add(self, protocol, location, other_config = {}):
         dev_uuid = uuid.createString()
         if protocol == 'vt100':
@@ -2005,6 +2075,18 @@
                         pci_dev_sxpr.append([opt, val])
                     sxpr.append(pci_dev_sxpr)
                 sxprs.append((dev_type, sxpr))
+            elif dev_type == 'vusb':
+                sxpr = ['vusb', ['uuid', dev_info['uuid']],
+                                ['usb-ver', dev_info['usb-ver']],
+                                ['num-ports', dev_info['num-ports']]]
+                port_sxpr = ['port']
+                for i in range(1, int(dev_info['num-ports']) + 1):
+                    if dev_info.has_key('port-%i' % i):
+                        port_sxpr.append([i, str(dev_info['port-%i' % i])])
+                    else:
+                        port_sxpr.append([i, ""])
+                sxpr.append(port_sxpr)
+                sxprs.append((dev_type, sxpr))
             else:
                 sxpr = self.device_sxpr(dev_type = dev_type,
                                         dev_info = dev_info,
diff -r d12425fad689 -r 8772e0bc4b9a tools/python/xen/xend/XendDevices.py
--- a/tools/python/xen/xend/XendDevices.py      Mon Dec 07 18:17:36 2009 +0900
+++ b/tools/python/xen/xend/XendDevices.py      Thu Dec 10 14:03:25 2009 +0900
@@ -19,7 +19,7 @@
 # A collection of DevControllers 
 #
 
-from xen.xend.server import blkif, netif, tpmif, pciif, iopif, irqif, vfbif, 
vscsiif
+from xen.xend.server import blkif, netif, tpmif, pciif, iopif, irqif, vfbif, 
vscsiif, vusbif
 from xen.xend.server.BlktapController import BlktapController
 from xen.xend.server.ConsoleController import ConsoleController
 
@@ -46,6 +46,7 @@
         'vkbd': vfbif.VkbdifController,
         'console': ConsoleController,
         'vscsi': vscsiif.VSCSIController,
+        'vusb': vusbif.VUSBController,
     }
 
     #@classmethod
diff -r d12425fad689 -r 8772e0bc4b9a tools/python/xen/xend/XendDomainInfo.py
--- a/tools/python/xen/xend/XendDomainInfo.py   Mon Dec 07 18:17:36 2009 +0900
+++ b/tools/python/xen/xend/XendDomainInfo.py   Thu Dec 10 14:03:25 2009 +0900
@@ -1022,6 +1022,27 @@
 
         return True
 
+    def vusb_device_configure(self, dev_sxp, devid):
+        """Configure a virtual root port.
+        """
+        dev_class = sxp.name(dev_sxp)
+        if dev_class != 'vusb':
+            return False
+
+        dev_config = {}
+        ports = sxp.child(dev_sxp, 'port')
+        for port in ports[1:]:
+            try:
+                num, bus = port
+                dev_config['port-%i' % int(num)] = str(bus)
+            except TypeError:
+                pass
+
+        dev_control = self.getDeviceController(dev_class)
+        dev_control.reconfigureDevice(devid, dev_config)
+
+        return True
+
     def device_configure(self, dev_sxp, devid = None):
         """Configure an existing device.
         
@@ -1043,6 +1064,9 @@
         if dev_class == 'vscsi':
             return self.vscsi_device_configure(dev_sxp)
 
+        if dev_class == 'vusb':
+            return self.vusb_device_configure(dev_sxp, devid)
+
         for opt_val in dev_sxp[1:]:
             try:
                 dev_config[opt_val[0]] = opt_val[1]
@@ -1275,6 +1299,13 @@
                 return dev_info
         return None
 
+    def _getDeviceInfo_vusb(self, devid):
+        for dev_type, dev_info in self.info.all_devices_sxpr():
+            if dev_type != 'vusb':
+                continue
+            return dev_info
+        return None
+
     def _get_assigned_pci_devices(self, devid = 0):
         if self.domid is not None:
             return get_assigned_pci_devices(self.domid)
diff -r d12425fad689 -r 8772e0bc4b9a tools/python/xen/xend/XendNode.py
--- a/tools/python/xen/xend/XendNode.py Mon Dec 07 18:17:36 2009 +0900
+++ b/tools/python/xen/xend/XendNode.py Thu Dec 10 14:03:25 2009 +0900
@@ -24,6 +24,7 @@
 from xen.util import Brctl
 from xen.util import pci as PciUtil
 from xen.util import vscsi_util
+from xen.util import vusb_util
 from xen.xend import XendAPIStore
 from xen.xend import osdep
 
@@ -411,6 +412,20 @@
                 self.save_PSCSIs()
                 return
 
+    def add_usbdev(self, busid):
+        # if the adding usb device should be owned by usbback
+        # and is probed by other usb drivers, seize it!
+        bus, intf = busid.split(':')
+        buses = vusb_util.get_assigned_buses()
+        if str(bus) in buses:
+            if not vusb_util.usb_intf_is_binded(busid):
+                log.debug("add_usb(): %s is binded to other driver" % busid)
+                vusb_util.unbind_usb_device(bus)
+                vusb_util.bind_usb_device(bus)
+        return
+
+    def remove_usbdev(self, busid):
+        log.debug("remove_usbdev(): Not implemented.")
 
 ##    def network_destroy(self, net_uuid):
  ##       del self.networks[net_uuid]
diff -r d12425fad689 -r 8772e0bc4b9a tools/python/xen/xend/server/udevevent.py
--- a/tools/python/xen/xend/server/udevevent.py Mon Dec 07 18:17:36 2009 +0900
+++ b/tools/python/xen/xend/server/udevevent.py Thu Dec 10 14:03:25 2009 +0900
@@ -60,6 +60,18 @@
                     log.info("Removing scsi device %s", hctl)
                     XendNode.instance().remove_PSCSI(hctl)
 
+            elif (udev_event.get('SUBSYSTEM', None) == 'usb'):
+                busid = udev_event.get('KERNEL', None)
+                if busid:
+                    if len(busid.split(':')) != 2:
+                        return
+                if (udev_event['ACTION'] == 'add'):
+                    log.info("Adding usb device %s", busid)
+                    XendNode.instance().add_usbdev(busid)
+                elif (udev_event['ACTION'] == 'remove'):
+                    log.info("Removing usb device %s", busid)
+                    XendNode.instance().remove_usbdev(busid)
+
             elif (udev_event.get('SUBSYSTEM', None) == 'net'):
                 interface = udev_event.get('INTERFACE', None)
                 if (udev_event['ACTION'] == 'add'):
diff -r d12425fad689 -r 8772e0bc4b9a tools/python/xen/xend/server/vusbif.py
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/python/xen/xend/server/vusbif.py    Thu Dec 10 14:03:25 2009 +0900
@@ -0,0 +1,126 @@
+#============================================================================
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of version 2.1 of the GNU Lesser General Public
+# License as published by the Free Software Foundation.
+#
+# This library 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.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#============================================================================
+# Copyright (C) 2009, FUJITSU LABORATORIES LTD.
+#  Author: Noboru Iwamatsu <n_iwamatsu@xxxxxxxxxxxxxx>
+#============================================================================
+
+"""Support for virtual USB host controllers.
+"""
+import re
+import string
+
+import types
+
+from xen.xend import sxp
+from xen.xend.XendError import VmError
+from xen.xend.XendLogging import log
+
+from xen.xend.server.DevController import DevController
+from xen.xend.server.DevConstants import xenbusState
+from xen.xend.xenstore.xstransact import xstransact
+
+from xen.util import vusb_util
+
+class VUSBController(DevController):
+    """VUSB Devices.
+    """
+    def __init__(self, vm):
+        """Create a VUSB Devices.
+        """
+        DevController.__init__(self, vm)
+
+    def sxprs(self):
+        """@see DevController.sxprs"""
+        devslist = []
+        for devid in self.deviceIDs():
+            vusb_config = []
+            backid = self.readFrontend(devid, 'backend-id')
+            vusb_config.append(['backend-id', backid])
+            state = self.readFrontend(devid, 'state')
+            vusb_config.append(['state', state])
+            backpath = self.readFrontend(devid, 'backend')
+            vusb_config.append(['backend', backpath]) 
+            usbver = self.readBackend(devid, 'usb-ver')
+            vusb_config.append(['usb-ver', usbver])
+            numports = self.readBackend(devid, 'num-ports') 
+            vusb_config.append(['num-ports', numports])             
+
+            portpath = "port/"
+            ports = ['port']
+            for i in range(1, int(numports) + 1):
+                bus = self.readBackend(devid, portpath + '%i' % i)
+                ports.append(['%i' % i, str(bus)])
+
+            vusb_config.append(ports)             
+            devslist.append([devid, vusb_config])
+
+        return devslist
+
+    def getDeviceDetails(self, config):
+        """@see DevController.getDeviceDetails"""
+        back = {}
+        devid = self.allocateDeviceID()
+        usbver = config.get('usb-ver', '')
+        numports = config.get('num-ports', '')
+        back['usb-ver'] = str(usbver)
+        back['num-ports'] = str(numports)
+        for i in range(1, int(numports) + 1):
+            back['port/%i' % i] = config['port-%i' % i]
+        return (devid, back, {})
+
+    def getDeviceConfiguration(self, devid, transaction = None):
+        """@see DevController.configuration"""
+        config = DevController.getDeviceConfiguration(self, devid, transaction)
+        if transaction is None:
+            hcinfo = self.readBackend(devid, 'usb-ver', 'num-ports')
+        else:
+            hcinfo = self.readBackendTxn(transaction, devid,
+                                          'usb-ver', 'num-ports')
+        (usbver, numports) = hcinfo
+        config['usb-ver'] = str(usbver)
+        config['num-ports'] = str(numports)
+        for i in range(1, int(numports) + 1):
+            if transaction is None:
+                config['port-%i' % i] = self.readBackend(devid, 'port/%i' % i)
+            else:
+                config['port-%i' % i] = self.readBackendTxn(transaction, devid,
+                                                             'port/%i' % i)
+        return config
+
+    def reconfigureDevice(self, devid, config):
+        """@see DevController.reconfigureDevice"""
+        cur_config = self.getDeviceConfiguration(devid)
+
+        numports = cur_config['num-ports']
+        for i in range(1, int(numports) + 1):
+            if config.has_key('port-%i' % i):
+                if not config['port-%i' % i] == cur_config['port-%i' % i]:
+                    if not cur_config['port-%i' % i] == "":
+                        vusb_util.unbind_usb_device(cur_config['port-%i' % i])
+                    self.writeBackend(devid, 'port/%i' % i, 
+                                      config['port-%i' % i])
+                    if not config['port-%i' % i] == "":
+                        vusb_util.bind_usb_device(config['port-%i' % i])
+
+        return self.readBackend(devid, 'uuid')
+
+    def waitForBackend(self, devid):
+        return (0, "ok - no hotplug")
+
+    def waitForBackend_destroy(self, backpath):
+        return 0
+
+    def migrate(self, deviceConfig, network, dst, step, domName):
+        raise VmError('Migration not permitted with assigned USB device.')
diff -r d12425fad689 -r 8772e0bc4b9a tools/python/xen/xm/create.py
--- a/tools/python/xen/xm/create.py     Mon Dec 07 18:17:36 2009 +0900
+++ b/tools/python/xen/xm/create.py     Thu Dec 10 14:03:25 2009 +0900
@@ -341,6 +341,18 @@
           use="""Add a SCSI device to a domain. The physical device is PDEV,
           which is exported to the domain as VDEV(X:X:X:X).""")
 
+gopts.var('vusb', val="usbver=USBVER,numports=NUMPORTS," + \
+          "port_1=PORT1,port_2=PORT2,port_3=PORT3,port_4=PORT4" + \
+          "port_5=PORT5,port_6=PORT6,port_7=PORT7,port_8=PORT8" + \
+          "port_9=PORT9,port_10=PORT10,port_11=PORT11,port_12=PORT12" + \
+          "port_13=PORT13,port_14=PORT14,port_15=PORT15,port_16=PORT16",
+          fn=append_value, default=[],
+          use="""Add a Virtual USB Host Controller to a domain.
+          The USB Spec Version is usbver (1|2, default: 2).
+          usbver=1 means USB1.1, usbver=2 mens USB2.0.
+          The number of root ports is numports (1 to 16, default: 8).
+          This option may be repeated to add more than one host controller.""")
+
 gopts.var('ioports', val='FROM[-TO]',
           fn=append_value, default=[],
           use="""Add a legacy I/O range to a domain, using given params (in 
hex).
@@ -797,6 +809,38 @@
             device.append(['backend', config['backend']])
         config_devs.append(['device', device])
 
+def configure_vusbs(config_devs, vals):
+    """Create the config for virtual usb host controllers.
+    """
+    for f in vals.vusb:
+        d = comma_sep_kv_to_dict(f)
+        config = ['vusb']
+
+        usbver = 2
+        if d.has_key('usbver'):
+            usbver = int(d['usbver'])
+        if usbver == 1 or usbver == 2:
+            config.append(['usb-ver', str(usbver)])
+        else:
+            err('Invalid vusb option: ' + 'usbver')
+
+        numports = 8
+        if d.has_key('numports'):
+            numports = d['numports']
+        if int(numports) < 1 or int(numports) > 16:
+            err('Invalid vusb option: ' + 'numports')
+        config.append(['num-ports', str(numports)])
+
+        port_config = []
+        for i in range(1, int(numports) + 1):
+            if d.has_key('port_%i' % i):
+                port_config.append(['%i' % i, str(d['port_%i' % i])])
+            else:
+                port_config.append(['%i' % i, ""])
+        port_config.insert(0, 'port')
+        config.append(port_config)
+        config_devs.append(['device', config])        
+
 def configure_ioports(config_devs, vals):
     """Create the config for legacy i/o ranges.
     """
@@ -998,6 +1042,7 @@
     configure_disks(config_devs, vals)
     configure_pci(config_devs, vals)
     configure_vscsis(config_devs, vals)
+    configure_vusbs(config_devs, vals)
     configure_ioports(config_devs, vals)
     configure_irq(config_devs, vals)
     configure_vifs(config_devs, vals)
diff -r d12425fad689 -r 8772e0bc4b9a tools/python/xen/xm/main.py
--- a/tools/python/xen/xm/main.py       Mon Dec 07 18:17:36 2009 +0900
+++ b/tools/python/xen/xm/main.py       Thu Dec 10 14:03:25 2009 +0900
@@ -39,6 +39,7 @@
 from xen.util.blkif import blkdev_name_to_number
 from xen.util import vscsi_util
 from xen.util.pci import *
+from xen.util import vusb_util
 
 import warnings
 warnings.filterwarnings('ignore', category=FutureWarning)
@@ -200,6 +201,17 @@
                         'Detach a specified SCSI device.'),
     'scsi-list'    :  ('<Domain> [--long]',
                         'List all SCSI devices currently attached.'),
+    'usb-attach'  :  ('<Domain> <DevId> <PortNumber> <BusId>',
+                        'Attach a new USB physical bus to domain\'s virtual 
port.'),
+    'usb-detach'  :  ('<Domain> <DevId> <PortNumber>',
+                        'Detach a USB physical bus from domain\'s virtual 
port.'),
+    'usb-list'    :  ('<Domain>',
+                        'List domain\'s attachment state of all virtual port 
.'),
+    'usb-list-assignable-devices' : ('', 'List all the assignable usb 
devices'),
+    'usb-hc-create'  :  ('<Domain> <USBSpecVer> <NumberOfPorts>',
+                        'Create a domain\'s new virtual USB host controller.'),
+    'usb-hc-destroy'  :  ('<Domain> <DevId>',
+                        'Destroy a domain\'s virtual USB host controller.'),
 
     # security
 
@@ -382,6 +394,12 @@
     "scsi-attach",
     "scsi-detach",
     "scsi-list",
+    "usb-attach",
+    "usb-detach",
+    "usb-list",
+    "usb-list-assignable-devices",
+    "usb-hc-create",
+    "usb-hc-destroy",
     ]
 
 vnet_commands = [
@@ -2304,6 +2322,58 @@
                 print "%(idx)-3d %(backend-id)-3d %(state)-5d 
%(feature-host)-4d " % ni,
                 print "%(p-dev)-10s %(p-devname)-5s %(v-dev)-10s 
%(frontstate)-4s" % mi
 
+def xm_usb_list(args):
+    xenapi_unsupported()
+    arg_check(args, 'usb-list', 1)
+    dom = args[0]
+    devs = server.xend.domain.getDeviceSxprs(dom, 'vusb')
+    for x in devs:
+        print "%-3s %-3s %-5s %-7s  %-30s" \
+            % ('Idx', 'BE', 'state', 'usb-ver', 'BE-path')
+        ni = parse_dev_info(x[1])
+        ni['idx'] = int(x[0])
+        usbver = sxp.child_value(x[1], 'usb-ver')
+        if int(usbver) == 1:
+            ni['usb-ver'] = 'USB1.1'
+        else:
+            ni['usb-ver'] = 'USB2.0'
+        print "%(idx)-3d %(backend-id)-3d %(state)-5d %(usb-ver)-7s 
%(be-path)-30s  " % ni
+
+        ports = sxp.child(x[1], 'port')
+        for port in ports[1:]:
+            try:
+                num, bus = port
+                if bus != "" and vusb_util.usb_device_is_connected(bus):
+                        idvendor = vusb_util.get_usb_idvendor(bus)
+                        idproduct = vusb_util.get_usb_idproduct(bus)
+                        prodinfo = vusb_util.get_usbdevice_info(bus)
+                        print "port %i: %s [ID %-4s:%-4s %s]" \
+                            % (int(num), str(bus), idvendor, idproduct, 
prodinfo)
+                else:
+                    print "port %i: " % int(num) + str(bus)
+            except TypeError:
+                pass
+
+def xm_usb_list_assignable_devices(args):
+    xenapi_unsupported()
+    arg_check(args, 'usb-list-assignable-devices', 0)
+
+    usb_devs = vusb_util.get_usb_devices()
+    buses = vusb_util.get_assigned_buses()
+
+    for x in buses:
+        try:
+            usb_devs.remove(x)
+        except ValueError:
+            pass
+
+    for dev in usb_devs:
+        idvendor = vusb_util.get_usb_idvendor(dev)
+        idproduct = vusb_util.get_usb_idproduct(dev)
+        prodinfo = vusb_util.get_usbdevice_info(dev)
+        print "%-13s: ID %-4s:%-4s %s" \
+                % (dev, idvendor, idproduct, prodinfo)
+
 def parse_block_configuration(args):
     dom = args[0]
 
@@ -2607,6 +2677,64 @@
             scsi.append(['backend', args[3]])
         server.xend.domain.device_configure(dom, scsi)
 
+def xm_usb_attach(args):
+    xenapi_unsupported()
+    arg_check(args, 'usb-attach', 4)
+    dom = args[0]
+    dev = args[1]
+    port = args[2]
+    bus = args[3]
+
+    dev_exist = 0
+    num_ports = 0
+    devs = server.xend.domain.getDeviceSxprs(dom, 'vusb')
+    for x in devs:
+        if int(x[0]) == int(dev):
+            dev_exist = 1
+            num_ports = sxp.child_value(x[1], 'num-ports')
+
+    if dev_exist == 0:
+        print "Cannot find device '%s' in domain '%s'" % (dev,dom)
+        return False
+
+    if int(port) < 1 or int(port) > int(num_ports):
+        print "Invalid Port Number '%s'" % port
+        return False
+
+    bus_match = re.match(r"(^(?P<bus>[0-9]{1,2})[-,])" + \
+                         r"(?P<root_port>[0-9]{1,2})" + \
+                         r"(?P<port>([\.,]{1}[0-9]{1,2}){0,5})$", bus)
+    if bus_match is None:
+        print "Invalid Busid '%s'" % bus
+        return False
+
+    if vusb_util.bus_is_assigned(bus):
+        print "Cannot assign already attached bus '%s', detach first." % bus
+        return False
+
+    prev_bus = vusb_util.get_assigned_bus(domain_name_to_domid(dom), dev, port)
+    if not prev_bus == "": 
+        print "Cannot override already attached port '%s', detach first." % 
port
+        return False
+
+    usb = ['vusb', ['port', [port, str(bus)]]]
+    server.xend.domain.device_configure(dom, usb, dev)
+
+def xm_usb_hc_create(args):
+    xenapi_unsupported()
+    arg_check(args, 'usb-hc-create', 3)
+    dom = args[0]
+    ver = args[1]
+    num = args[2]
+    vusb_config = ['vusb']
+    vusb_config.append(['usb-ver', str(ver)])
+    vusb_config.append(['num-ports', str(num)])
+    port_config = ['port']
+    for i in range(1, int(num) + 1):
+        port_config.append(['%i' % i, ""])
+    vusb_config.append(port_config)
+    server.xend.domain.device_create(dom, vusb_config)
+
 def detach(args, deviceClass):
     rm_cfg = True
     dom = args[0]
@@ -2718,6 +2846,22 @@
     else:
         server.xend.domain.device_configure(dom, scsi)
 
+def xm_usb_detach(args):
+    xenapi_unsupported()
+    arg_check(args, 'usb-detach', 3)
+    dom = args[0]
+    dev = args[1]
+    port = args[2]
+    usb = ['vusb', ['port', [port, '']]]
+    server.xend.domain.device_configure(dom, usb, dev)
+
+def xm_usb_hc_destroy(args):
+    xenapi_unsupported()
+    arg_check(args, 'usb-hc-destroy', 2)
+    dom = args[0]
+    dev = args[1]
+    server.xend.domain.destroyDevice(dom, 'vusb', dev)
+
 def xm_vnet_list(args):
     xenapi_unsupported()
     try:
@@ -2918,6 +3062,13 @@
     "scsi-attach": xm_scsi_attach,
     "scsi-detach": xm_scsi_detach,
     "scsi-list": xm_scsi_list,
+    # vusb
+    "usb-attach": xm_usb_attach,
+    "usb-detach": xm_usb_detach,
+    "usb-list": xm_usb_list,
+    "usb-list-assignable-devices": xm_usb_list_assignable_devices,
+    "usb-hc-create": xm_usb_hc_create,
+    "usb-hc-destroy": xm_usb_hc_destroy,
     #usb
     "usb-add": xm_usb_add,
     "usb-del": xm_usb_del,
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel

 


Rackspace

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