[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] PVUSB: xm/xend support
# HG changeset patch # User Keir Fraser <keir.fraser@xxxxxxxxxx> # Date 1260521537 0 # Node ID 2e5032921b077a4e89fc26343060c026547cca98 # Parent 1f5f36e11114d63c2a1c755106cb697666a92207 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@xxxxxxxxxxxxxx> --- tools/hotplug/Linux/xend.rules | 1 tools/python/xen/util/vusb_util.py | 338 ++++++++++++++++++++++++++++++ tools/python/xen/xend/XendConfig.py | 82 +++++++ tools/python/xen/xend/XendDevices.py | 3 tools/python/xen/xend/XendDomainInfo.py | 31 ++ tools/python/xen/xend/XendNode.py | 15 + tools/python/xen/xend/server/udevevent.py | 12 + tools/python/xen/xend/server/vusbif.py | 126 +++++++++++ tools/python/xen/xm/create.py | 45 +++ tools/python/xen/xm/main.py | 151 +++++++++++++ 10 files changed, 803 insertions(+), 1 deletion(-) diff -r 1f5f36e11114 -r 2e5032921b07 tools/hotplug/Linux/xend.rules --- a/tools/hotplug/Linux/xend.rules Fri Dec 11 08:51:21 2009 +0000 +++ b/tools/hotplug/Linux/xend.rules Fri Dec 11 08:52:17 2009 +0000 @@ -1,3 +1,4 @@ SUBSYSTEM=="pci", RUN+="socket:/org/xen/ 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 1f5f36e11114 -r 2e5032921b07 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 Fri Dec 11 08:52:17 2009 +0000 @@ -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 1f5f36e11114 -r 2e5032921b07 tools/python/xen/xend/XendConfig.py --- a/tools/python/xen/xend/XendConfig.py Fri Dec 11 08:51:21 2009 +0000 +++ b/tools/python/xen/xend/XendConfig.py Fri Dec 11 08:52:17 2009 +0000 @@ -1400,6 +1400,14 @@ class XendConfig(dict): (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 @@ class XendConfig(dict): 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': @@ -2001,6 +2071,18 @@ class XendConfig(dict): sxpr.append(['backend', dev_info['backend']]) 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, diff -r 1f5f36e11114 -r 2e5032921b07 tools/python/xen/xend/XendDevices.py --- a/tools/python/xen/xend/XendDevices.py Fri Dec 11 08:51:21 2009 +0000 +++ b/tools/python/xen/xend/XendDevices.py Fri Dec 11 08:52:17 2009 +0000 @@ -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 @@ class XendDevices: 'vkbd': vfbif.VkbdifController, 'console': ConsoleController, 'vscsi': vscsiif.VSCSIController, + 'vusb': vusbif.VUSBController, } #@classmethod diff -r 1f5f36e11114 -r 2e5032921b07 tools/python/xen/xend/XendDomainInfo.py --- a/tools/python/xen/xend/XendDomainInfo.py Fri Dec 11 08:51:21 2009 +0000 +++ b/tools/python/xen/xend/XendDomainInfo.py Fri Dec 11 08:52:17 2009 +0000 @@ -1102,6 +1102,27 @@ class XendDomainInfo: 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. @@ -1122,6 +1143,9 @@ class XendDomainInfo: 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: @@ -1376,6 +1400,13 @@ class XendDomainInfo: devs = sxp.children(dev_info, 'dev') if devid == int(sxp.child_value(devs[0], 'devid')): 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): diff -r 1f5f36e11114 -r 2e5032921b07 tools/python/xen/xend/XendNode.py --- a/tools/python/xen/xend/XendNode.py Fri Dec 11 08:51:21 2009 +0000 +++ b/tools/python/xen/xend/XendNode.py Fri Dec 11 08:52:17 2009 +0000 @@ -24,6 +24,7 @@ from xen.util import Brctl 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 @@ class XendNode: 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 1f5f36e11114 -r 2e5032921b07 tools/python/xen/xend/server/udevevent.py --- a/tools/python/xen/xend/server/udevevent.py Fri Dec 11 08:51:21 2009 +0000 +++ b/tools/python/xen/xend/server/udevevent.py Fri Dec 11 08:52:17 2009 +0000 @@ -60,6 +60,18 @@ class UdevEventProtocol(protocol.Protoco 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 1f5f36e11114 -r 2e5032921b07 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 Fri Dec 11 08:52:17 2009 +0000 @@ -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 1f5f36e11114 -r 2e5032921b07 tools/python/xen/xm/create.py --- a/tools/python/xen/xm/create.py Fri Dec 11 08:51:21 2009 +0000 +++ b/tools/python/xen/xm/create.py Fri Dec 11 08:52:17 2009 +0000 @@ -349,6 +349,18 @@ gopts.var('vscsi', val='PDEV,VDEV[,DOM]' fn=append_value, default=[], 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=[], @@ -849,6 +861,38 @@ def configure_vscsis(config_devs, vals): 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 @@ def make_config(vals): 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 1f5f36e11114 -r 2e5032921b07 tools/python/xen/xm/main.py --- a/tools/python/xen/xm/main.py Fri Dec 11 08:51:21 2009 +0000 +++ b/tools/python/xen/xm/main.py Fri Dec 11 08:52:17 2009 +0000 @@ -39,6 +39,7 @@ from xen.util.blkif import blkdev_name_t 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 @@ SUBCOMMAND_HELP = { '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 @@ device_commands = [ "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 @@ def xm_scsi_list(args): 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 @@ def xm_scsi_attach(args): 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] @@ -2941,6 +3069,22 @@ def xm_scsi_detach(args): 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() @@ -3372,6 +3516,13 @@ commands = { "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, _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |