From nobody Fri May 1 08:24:44 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) client-ip=8.43.85.245; envelope-from=devel-bounces@lists.libvirt.org; helo=lists.libvirt.org; Authentication-Results: mx.zohomail.com; dkim=fail header.i=maximilian_martin@gmx.de; spf=pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=pass(p=reject dis=none) header.from=lists.libvirt.org ARC-Seal: i=1; a=rsa-sha256; t=1742287930; cv=none; d=zohomail.com; s=zohoarc; b=nCHPGDr1olDRZJfH4no6PmzRKBwHBRO7sJzEORc3a+yiUhOXz4qzZkiBFcR4cA1s1BHz1KmqcA0jstwOo5+DJ3i/qfLqET9jYa5uBBmd4S0oRcui9Zoklqs8U8MEcQtxcJnG5ikqFKzBHtyEkvDy8W17uknOCyERPI8DQGf6eqQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1742287930; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:Subject:Subject:To:To:Message-Id; bh=X/1TuozLILfqy4Ye+QcyV78Z6Nz5fEqfvzfos1rZJ2w=; b=fi5cvba3terrKB9GlNDRg/IBlCqkH0zs+7kxNhBXMhGABC0ObDmfHtQk0bd6jiPMSN1+NgtjRn8Vy8CVRpN587loJh6J2jsKXhl8RMX4weIxZPGMEnxBC2p7NwaZEXH5raYbQrXh+TUYvOJZ8kd+c/BpJVmgd8N5dPl8KPwHcJs= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail header.i=maximilian_martin@gmx.de; spf=pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=pass header.from= (p=reject dis=none) Return-Path: Received: from lists.libvirt.org (lists.libvirt.org [8.43.85.245]) by mx.zohomail.com with SMTPS id 1742287930950294.9810378623324; Tue, 18 Mar 2025 01:52:10 -0700 (PDT) Received: by lists.libvirt.org (Postfix, from userid 996) id 26148A65; Tue, 18 Mar 2025 04:52:10 -0400 (EDT) Received: from lists.libvirt.org (localhost [IPv6:::1]) by lists.libvirt.org (Postfix) with ESMTP id 4FF442215; Tue, 18 Mar 2025 04:50:44 -0400 (EDT) Received: by lists.libvirt.org (Postfix, from userid 996) id B2E312233; Mon, 17 Mar 2025 17:05:12 -0400 (EDT) Received: from mout.gmx.net (mout.gmx.net [212.227.15.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by lists.libvirt.org (Postfix) with ESMTPS id E321B178A for ; Mon, 17 Mar 2025 17:05:09 -0400 (EDT) Received: from cu-host.fritz.box ([185.17.205.19]) by mail.gmx.net (mrgmx004 [212.227.17.190]) with ESMTPSA (Nemesis) id 1N5VDE-1t6DDr1K2s-01034k; Mon, 17 Mar 2025 22:00:05 +0100 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on lists.libvirt.org X-Spam-Level: ** X-Spam-Status: No, score=2.1 required=5.0 tests=DKIM_INVALID,DKIM_SIGNED, MAILING_LIST_MULTI,RCVD_IN_DNSWL_LOW,RCVD_IN_MSPIKE_H2,RCVD_IN_SBL_CSS, RCVD_IN_VALIDITY_RPBL_BLOCKED,RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_NONE autolearn=no autolearn_force=no version=3.4.4 X-Greylist: delayed 302 seconds by postgrey-1.37 at lists.libvirt.org; Mon, 17 Mar 2025 17:05:09 EDT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmx.de; s=s31663417; t=1742245509; x=1742850309; i=maximilian_martin@gmx.de; bh=X/1TuozLILfqy4Ye+QcyV78Z6Nz5fEqfvzfos1rZJ2w=; h=X-UI-Sender-Class:From:To:Cc:Subject:Date:Message-Id: MIME-Version:Content-Transfer-Encoding:cc: content-transfer-encoding:content-type:date:from:message-id: mime-version:reply-to:subject:to; b=YU5EUI3uFASmefOJ/HEq17pV1uI/SgqT6PPFgYauFiPeaRz9MDZPf53EeI9U94fF zaofBcYrLvVlj3IugyO6V0Cj9b/umNh9/fKxgQNYkoEyiw7n7zADSmb1GLomwn/D7 s2U53f7z2C31D8P9sgyGI5QPMn96rkGwQqLGcOGcpLATZyHobj4mLhP6Wvr6nTJk/ rYFiPo6r6TL9xseUYYOpBMbM8RJ68eyZPB3+vVrr846zNnKyTF1LAVOFxzlyQpWt9 /28lR2p1BWlyqObFBjonCDC6MN1Z6zgorlXDmYXPsJh777Sss/A3NtsaS4aeRT0no xgLmmXP7DTtA3hP00g== X-UI-Sender-Class: 724b4f7f-cbec-4199-ad4e-598c01a50d3a To: devel@lists.libvirt.org Subject: [PATCH] USB hostdev: allow addressing by port Date: Mon, 17 Mar 2025 21:59:54 +0100 Message-Id: <20250317205954.1298-1-maximilian_martin@gmx.de> X-Mailer: git-send-email 2.39.5 MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Provags-ID: V03:K1:gP/miREd0zjfsnkzjtyzbVTvbs61mXW/2kJLYyZvFIWtT5Y+m1J mMpgqE8EhuCJ76RwSN1pCAkLmx8I5EDrjfR+PuKOAu9i04V7q3yTbfAzvVwEHVcMHEUVsWK ie1SXP/Bt0T5UDkA42r/nf/qlTqU7UrljExFCGLTfvqwGaxVooRny6bg048IZJ4tS+9H7gr eP8tOqGyAGi4cvl4tSD8g== UI-OutboundReport: notjunk:1;M01:P0:tRw8Ieme7QM=;xuies4MhiBRBI4t/ZZsxHjONRqh iW7AJWTGEXiwa+6tm1SEcavTwk4rYz4toRhQUt+de0CITZMqzb4CIdHMo61izuPuoHeLfMDZ4 aDJtg7RChdJqGjOn+Pis9OjkNLglvm4bYWUSVXFtcdZWotHfNat1DR0Zodx7F+yxCA3SC5wyh jNcZK2R5aT59xl8F4pkPyJkvFUw5qpBfaS32r/XBudmmfelaBWjvf6QUhOl/uxGxk6tk+N1IE 5FRvKlaYpvH/y9SZFdf9zKn4rqkG+gJPlWI3DBeT4mzJKYd1bW5SY2jpXc8sf2E1es2u+8NQt 82YS5P56DQfBYeSw4xcYojsNWL68ac8AoNAxyuNSSfYZpohZOpwF9L8N8wHY4RUd2tbD8Ro/m 177Kps3Y03rCKuzBtKuoKPMlfSRbnc572WArRkBqHkGCkgbiSzvixyiq5YpR7mqvpoF0/u3B8 FFT+76dFzcPrlGd3jiasUXdMNNJNYsnXqvQBi0kzquWxgNPfwbFyWcu14Wf3nPb+bXhGh5L34 W4vynyKXy+yzQYswiNu0BeBPCIjPfHB/3xqcARjrZo4MAeG8M1qUG+EyhGcbYd/Rmu99m9PU8 0xHWaYgxjOA/yB5j3dei1xMfgJHXCYd//rzaeC4UV6icDbzS7mhVezNmh3KWvvZcviDFmae1Q bdFbG9AWPBcEqbTPUWJ3g0yA7Nj3tpuraOTVrgo43VBjsRR60J2kT6LNBOTzw94+B9pdTJqIk bLoN7lbnb3u0YLEprz3fcmAFxqpsQkmlLsreu176d1zvIFuPh5aHtIY3uJ1u3BeCLKnxp+7/6 zChX5t1zr3mqAWaPGHm9hCO89yBnqpFUjFi4AIxpySbXrJXQ+d91GpHuEV3cv1vzQzh2DbMeo UJmK6A8fnR79OfAaDT4esyv5J9HZkdOSeDUrj9e8qj96QvMipa2diSrjeJrjx4eyfzwfDzKdk XQ1xuQvH3LFuL4BLibRxaColq1QL3E8gM8kfjRvyXDDHaffaw9A1eAqjHAroErg03xge2BYVy aCkI9Uh+rG5xxJzRcrJcaDUTVIZMPAM+r8dV0xyfldbRR4FCzLiNAlVf/VI9V+UjtF1xn+3WY 4Wu0acd4X2MJH7Pb79gZ9JFRmSF7H/os5Vj/cIw1REtYtON9bo0Ypg9AqQB7LWuUMQ8ad12ky hCboEMsnwNAYMxN3936WGyGOmB3MTXo7sAjOQuggTM3UjP8HhFiFjDHjxHbwvOOat4Yu/ONzE TIJ38RpdiNjR5SZ6i6XYrXGYnUHVXsdsF2h66PdRO/81h/IIcJpgf/7XLoeE3YHCKc11pPdlw XCcA0IEETVUk+3FVT/dqgOJmZ+rJQPmoSvS5XcN8ytIPN6zSuoj1Isv0XSd4OaIXJ+y7FRhIz xKID/OMvBObx/4U+MEiLWd6Hw9BRaEdLeBcehffr5yxWM3+3lHIQDkbC//acGOIgPRfscB0lg kNfiDc59a0wzmFo1nl4L5eIp9I90= X-MailFrom: maximilian_martin@gmx.de X-Mailman-Rule-Hits: nonmember-moderation X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-config-1; header-match-config-2; header-match-config-3; header-match-devel.lists.libvirt.org-0 Message-ID-Hash: MB6XSIBJGUOMTE4P7LUC7XPHVQOERGIS X-Message-ID-Hash: MB6XSIBJGUOMTE4P7LUC7XPHVQOERGIS X-Mailman-Approved-At: Tue, 18 Mar 2025 08:50:41 -0400 CC: Maximilian Martin X-Mailman-Version: 3.2.2 Precedence: list List-Id: Development discussions about the libvirt library & tools Archived-At: List-Archive: List-Help: List-Post: List-Subscribe: List-Unsubscribe: From: Maximilian Martin via Devel Reply-To: Maximilian Martin X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1742287932477019000 Content-Type: text/plain; charset="utf-8" From: Maximilian Martin Currently, only vendor/product and bus/device matching are supported for US= B host devices. Neither of these provide a stable and persistent way of assigning = a guest a specific host device. Vendor/product can be ambiguous. Device numbers cha= nge on every enumeration. This patch adds a bus/port matching, which allows a specific port on the ho= st to be specified using the dotted notation found in Linux's "devpath" sysfs attrib= ute. This patch is based on the previous work of Thomas Hebb: https://lists.libv= irt.org/archives/list/devel@lists.libvirt.org/message/7U3HFUW3DGDOSF4RIBRZJ= INKFDYCE2ZH/ Resolves: https://gitlab.com/libvirt/libvirt/-/issues/513 Signed-off-by: Maximilian Martin --- docs/formatdomain.rst | 29 ++-- src/conf/domain_conf.c | 70 +++++++- src/conf/domain_conf.h | 1 + src/conf/schemas/domaincommon.rng | 11 +- src/hypervisor/virhostdev.c | 131 +++++++++------ src/libvirt_private.syms | 2 - src/util/virusb.c | 159 ++++++------------ src/util/virusb.h | 32 ++-- tests/virusbtest.c | 149 +++++++++++----- .../sys_bus_usb/devices/1-1.5.3.1/devpath | 1 + .../sys_bus_usb/devices/1-1.5.3.3/devpath | 1 + .../sys_bus_usb/devices/1-1.5.3/devpath | 1 + .../sys_bus_usb/devices/1-1.5.4/devpath | 1 + .../sys_bus_usb/devices/1-1.5.5/devpath | 1 + .../sys_bus_usb/devices/1-1.5.6/devpath | 1 + .../sys_bus_usb/devices/1-1.5/devpath | 1 + .../sys_bus_usb/devices/1-1.6/devpath | 1 + .../sys_bus_usb/devices/1-1/devpath | 1 + .../sys_bus_usb/devices/2-1.2/devpath | 1 + .../sys_bus_usb/devices/2-1/devpath | 1 + .../sys_bus_usb/devices/usb1/devpath | 1 + .../sys_bus_usb/devices/usb2/devpath | 1 + .../sys_bus_usb/devices/usb3/devpath | 1 + .../sys_bus_usb/devices/usb4/devpath | 1 + 24 files changed, 355 insertions(+), 244 deletions(-) create mode 100644 tests/virusbtestdata/sys_bus_usb/devices/1-1.5.3.1/devp= ath create mode 100644 tests/virusbtestdata/sys_bus_usb/devices/1-1.5.3.3/devp= ath create mode 100644 tests/virusbtestdata/sys_bus_usb/devices/1-1.5.3/devpath create mode 100644 tests/virusbtestdata/sys_bus_usb/devices/1-1.5.4/devpath create mode 100644 tests/virusbtestdata/sys_bus_usb/devices/1-1.5.5/devpath create mode 100644 tests/virusbtestdata/sys_bus_usb/devices/1-1.5.6/devpath create mode 100644 tests/virusbtestdata/sys_bus_usb/devices/1-1.5/devpath create mode 100644 tests/virusbtestdata/sys_bus_usb/devices/1-1.6/devpath create mode 100644 tests/virusbtestdata/sys_bus_usb/devices/1-1/devpath create mode 100644 tests/virusbtestdata/sys_bus_usb/devices/2-1.2/devpath create mode 100644 tests/virusbtestdata/sys_bus_usb/devices/2-1/devpath create mode 100644 tests/virusbtestdata/sys_bus_usb/devices/usb1/devpath create mode 100644 tests/virusbtestdata/sys_bus_usb/devices/usb2/devpath create mode 100644 tests/virusbtestdata/sys_bus_usb/devices/usb3/devpath create mode 100644 tests/virusbtestdata/sys_bus_usb/devices/usb4/devpath diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst index 543b36cb2e..bc3c11613f 100644 --- a/docs/formatdomain.rst +++ b/docs/formatdomain.rst @@ -4696,19 +4696,22 @@ or: tweak the loading process further using the ``bar`` or ``file`` attribu= tes will be rejected. :since:`Since 4.3.0 (QEMU and KVM only)`. ``address`` - The ``address`` element for USB devices has a ``bus`` and ``device`` - attribute to specify the USB bus and device number the device appears a= t on - the host. The values of these attributes can be given in decimal, hexad= ecimal - (starting with 0x) or octal (starting with 0) form. For PCI devices the - element carries 4 attributes allowing to designate the device as can be= found - with the ``lspci`` or with ``virsh nodedev-list``. For SCSI devices a '= drive' - address type must be used. For mediated devices, which are software-only - devices defining an allocation of resources on the physical parent devi= ce, - the address type used must conform to the ``model`` attribute of element - ``hostdev``, e.g. any address type other than PCI for ``vfio-pci`` devi= ce API - or any address type other than CCW for ``vfio-ccw`` device API will res= ult in - an error. See the `Device Addresses`_ section for more details on the a= ddress - element. + The ``address`` element for USB devices has a ``bus`` attribute to spec= ify + the USB bus. In addition, either a ``device`` attribute or a ``port`` + attribute is required to identify the device on the host. While the dev= ice + number is assigned upon connection of the device, the port number is a + stable identifier of the physical host port. Bus and device number can = be + given in decimal, hexadecimal (starting with 0x) or octal (starting wit= h 0) + form. The port number is a dotted path (examples: ``2``, ``1.2.5``). Fo= r PCI + devices the element carries 4 attributes allowing to designate the devi= ce as + can be found with the ``lspci`` or with ``virsh nodedev-list``. For SCSI + devices a 'drive' address type must be used. For mediated devices, whic= h are + software-only devices defining an allocation of resources on the physic= al + parent device, the address type used must conform to the ``model`` attr= ibute + of element ``hostdev``, e.g. any address type other than PCI for ``vfio= -pci`` + device API or any address type other than CCW for ``vfio-ccw`` device A= PI + will result in an error. See the `Device Addresses`_ section for more d= etails + on the address element. ``driver`` PCI hostdev devices can have an optional ``driver`` subelement that specifies which host driver to bind to the device when preparing it diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index b94cf99236..bd9c651a07 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -2657,6 +2657,15 @@ virDomainHostdevSubsysSCSIClear(virDomainHostdevSubs= ysSCSI *scsisrc) } } +static void +virDomainHostdevSubsysUSBClear(virDomainHostdevSubsysUSB *usbsrc) +{ + if (!usbsrc) + return; + + VIR_FREE(usbsrc->port); +} + static void virDomainHostdevDefClear(virDomainHostdevDef *def) @@ -2700,6 +2709,8 @@ virDomainHostdevDefClear(virDomainHostdevDef *def) g_clear_pointer(&def->source.subsys.u.pci.origstates, virBitma= pFree); break; case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: + virDomainHostdevSubsysUSBClear(&def->source.subsys.u.usb); + break; case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV: case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST: break; @@ -5841,6 +5852,9 @@ virDomainHostdevSubsysUSBDefParseXML(xmlNodePtr node, xmlNodePtr productNode; xmlNodePtr addressNode; virTristateBool autoAddress; + bool found_device, found_port; + char *port; + int ret =3D -1; VIR_XPATH_NODE_AUTORESTORE(ctxt) ctxt->node =3D node; @@ -5891,13 +5905,45 @@ virDomainHostdevSubsysUSBDefParseXML(xmlNodePtr nod= e, } if ((addressNode =3D virXPathNode("./address", ctxt))) { - if (virXMLPropUInt(addressNode, "bus", 0, - VIR_XML_PROP_REQUIRED, &usbsrc->bus) < 0) + found_device =3D false; + found_port =3D false; + + ret =3D virXMLPropUInt(addressNode, "bus", 0, + VIR_XML_PROP_REQUIRED, &usbsrc->bus); + if (ret < 0) { + return -1; + } else if (ret =3D=3D 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("missing bus")); + return -1; + } + + ret =3D virXMLPropUInt(addressNode, "device", 0, + VIR_XML_PROP_NONE, &usbsrc->device); + if (ret < 0) return -1; + else if (ret > 0) + found_device =3D true; - if (virXMLPropUInt(addressNode, "device", 0, - VIR_XML_PROP_REQUIRED, &usbsrc->device) < 0) + port =3D virXMLPropString(addressNode, "port"); + if (port) { + if (*port) { + usbsrc->port =3D port; + found_port =3D true; + } else { + VIR_FREE(port); + } + } + + if (!found_device && !found_port) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("usb address needs either device id or port")); return -1; + } else if (found_device && found_port) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("found both device id and port in usb address (amb= iguous setting)")); + return -1; + } } return 0; @@ -14522,8 +14568,13 @@ virDomainHostdevMatchSubsysUSB(virDomainHostdevDef= *first, virDomainHostdevSubsysUSB *first_usbsrc =3D &first->source.subsys.u.us= b; virDomainHostdevSubsysUSB *second_usbsrc =3D &second->source.subsys.u.= usb; - if (first_usbsrc->bus && first_usbsrc->device) { - /* specified by bus location on host */ + if (first_usbsrc->bus && first_usbsrc->port) { + /* specified by bus and port on host */ + if (first_usbsrc->bus =3D=3D second_usbsrc->bus && + STREQ_NULLABLE(first_usbsrc->port, second_usbsrc->port)) + return 1; + } else if (first_usbsrc->bus && first_usbsrc->device) { + /* specified by bus and device id on host */ if (first_usbsrc->bus =3D=3D second_usbsrc->bus && first_usbsrc->device =3D=3D second_usbsrc->device) return 1; @@ -23957,10 +24008,15 @@ virDomainHostdevDefFormatSubsysUSB(virBuffer *buf, virBufferAsprintf(&sourceChildBuf, "\n", u= sbsrc->product); } - if (usbsrc->bus || usbsrc->device) + if (usbsrc->bus && usbsrc->port) { + virBufferAsprintf(&sourceChildBuf, "
\n", + includeTypeInAddr ? "type=3D'usb' " : "", + usbsrc->bus, usbsrc->port); + } else if (usbsrc->bus || usbsrc->device) { virBufferAsprintf(&sourceChildBuf, "
\n", includeTypeInAddr ? "type=3D'usb' " : "", usbsrc->bus, usbsrc->device); + } virXMLFormatElement(buf, "source", &sourceAttrBuf, &sourceChildBuf); } diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 3a97fd866c..e5f53c09ac 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -228,6 +228,7 @@ struct _virDomainHostdevSubsysUSB { on vendor/product */ unsigned bus; unsigned device; + char *port; unsigned vendor; unsigned product; diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincom= mon.rng index 3276569325..00d97f0cd8 100644 --- a/src/conf/schemas/domaincommon.rng +++ b/src/conf/schemas/domaincommon.rng @@ -6687,9 +6687,14 @@ - - - + + + + + + + + diff --git a/src/hypervisor/virhostdev.c b/src/hypervisor/virhostdev.c index 0a1d8500d4..9e77477a9b 100644 --- a/src/hypervisor/virhostdev.c +++ b/src/hypervisor/virhostdev.c @@ -1358,6 +1358,42 @@ virHostdevMarkUSBDevices(virHostdevManager *mgr, return -1; } +static int +virHostdevFindUSBDeviceWithFlags(virDomainHostdevDef *hostdev, + bool mandatory, + unsigned int flags, + virUSBDevice **usb) +{ + virDomainHostdevSubsysUSB *usbsrc =3D &hostdev->source.subsys.u.usb; + unsigned vendor =3D usbsrc->vendor; + unsigned product =3D usbsrc->product; + unsigned bus =3D usbsrc->bus; + char *port =3D usbsrc->port; + unsigned device =3D usbsrc->device; + virUSBDeviceList *devs; + int rc; + + rc =3D virUSBDeviceFind(vendor, product, bus, device, port, NULL, + mandatory, flags, &devs); + if (rc < 0) + return -1; + + if (rc =3D=3D 1) { + *usb =3D virUSBDeviceListGet(devs, 0); + virUSBDeviceListSteal(devs, *usb); + } + virObjectUnref(devs); + + if (rc > 1) { + virReportError(VIR_ERR_OPERATION_FAILED, + _("Multiple USB devices for %1$x:%2$x, use to specify one"), + vendor, product); + return -1; + } + + return rc; +} + int virHostdevFindUSBDevice(virDomainHostdevDef *hostdev, @@ -1366,77 +1402,64 @@ virHostdevFindUSBDevice(virDomainHostdevDef *hostde= v, { virDomainHostdevSubsysUSB *usbsrc =3D &hostdev->source.subsys.u.usb; unsigned vendor =3D usbsrc->vendor; - unsigned product =3D usbsrc->product; unsigned bus =3D usbsrc->bus; unsigned device =3D usbsrc->device; + char *port =3D usbsrc->port; bool autoAddress =3D usbsrc->autoAddress; + unsigned int flags =3D 0; int rc; *usb =3D NULL; - if (vendor && bus) { - rc =3D virUSBDeviceFind(vendor, product, bus, device, - NULL, - autoAddress ? false : mandatory, - usb); - if (rc < 0) { - return -1; - } else if (!autoAddress) { - goto out; - } else { - VIR_INFO("USB device %x:%x could not be found at previous" - " address (bus:%u device:%u)", - vendor, product, bus, device); - } + if (vendor) + flags |=3D USB_DEVICE_FIND_BY_VENDOR; + if (device) + flags |=3D USB_DEVICE_FIND_BY_DEVICE; + if (port) + flags |=3D USB_DEVICE_FIND_BY_PORT; + + /* Rule out invalid cases. */ + if (vendor && device && port) { + VIR_WARN("Cannot match USB device on vendor/product, bus/device, a= nd bus/port at once. Ignoring bus/device."); + flags &=3D ~((unsigned int) USB_DEVICE_FIND_BY_DEVICE); + } else if (device && port) { + VIR_WARN("Cannot match USB device on bus/device and bus/port at on= ce. Ignoring bus/device."); + flags &=3D ~((unsigned int) USB_DEVICE_FIND_BY_DEVICE); + } else if (!vendor && !device && !port) { + VIR_WARN("No matching fields for USB device found. Vendor/product,= bus/device, or bus/port required."); + return -1; } - /* When vendor is specified, its USB address is either unspecified or = the - * device could not be found at the USB device where it had been - * automatically found before. - */ - if (vendor) { - g_autoptr(virUSBDeviceList) devs =3D NULL; + /* First attempt, matching on all valid fields. */ + rc =3D virHostdevFindUSBDeviceWithFlags(hostdev, + autoAddress ? false : mandatory, + flags, usb); + if (rc < 0) + return -1; - rc =3D virUSBDeviceFindByVendor(vendor, product, NULL, mandatory, = &devs); - if (rc < 0) { - return -1; - } else if (rc =3D=3D 0) { - goto out; - } else if (rc > 1) { - if (autoAddress) { - virReportError(VIR_ERR_OPERATION_FAILED, - _("Multiple USB devices for %1$x:%2$x were = found, but none of them is at bus:%3$u device:%4$u"), - vendor, product, bus, device); - } else { - virReportError(VIR_ERR_OPERATION_FAILED, - _("Multiple USB devices for %1$x:%2$x, use =
to specify one"), - vendor, product); - } + if (rc !=3D 1 && autoAddress && device) { + VIR_INFO("USB device could not be found at previous address " + "(bus:%u device:%u)", bus, device); + + /* Second attempt, for when the device number has changed. */ + flags &=3D ~((unsigned int) USB_DEVICE_FIND_BY_DEVICE); + usbsrc->device =3D 0; + + rc =3D virHostdevFindUSBDeviceWithFlags(hostdev, mandatory, + flags, usb); + if (rc < 0) return -1; - } - *usb =3D virUSBDeviceListGet(devs, 0); - virUSBDeviceListSteal(devs, *usb); + usbsrc->autoAddress =3D true; + } + if (!*usb) { + hostdev->missing =3D true; + } else if (!usbsrc->bus || !usbsrc->device) { usbsrc->bus =3D virUSBDeviceGetBus(*usb); usbsrc->device =3D virUSBDeviceGetDevno(*usb); - usbsrc->autoAddress =3D true; - - if (autoAddress) { - VIR_INFO("USB device %x:%x found at bus:%u device:%u (moved" - " from bus:%u device:%u)", - vendor, product, - usbsrc->bus, usbsrc->device, - bus, device); - } - } else if (bus) { - if (virUSBDeviceFindByBus(bus, device, NULL, mandatory, usb) < 0) - return -1; } - out: - if (!*usb) - hostdev->missing =3D true; return 0; } diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index e63939e2b5..dbc0778fdb 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -3668,8 +3668,6 @@ virURIResolveAlias; # util/virusb.h virUSBDeviceFileIterate; virUSBDeviceFind; -virUSBDeviceFindByBus; -virUSBDeviceFindByVendor; virUSBDeviceFree; virUSBDeviceGetBus; virUSBDeviceGetDevno; diff --git a/src/util/virusb.c b/src/util/virusb.c index cf3461f80a..d193f8f3ba 100644 --- a/src/util/virusb.c +++ b/src/util/virusb.c @@ -61,12 +61,6 @@ struct _virUSBDeviceList { virUSBDevice **devs; }; -typedef enum { - USB_DEVICE_ALL =3D 0, - USB_DEVICE_FIND_BY_VENDOR =3D 1 << 0, - USB_DEVICE_FIND_BY_BUS =3D 1 << 1, -} virUSBDeviceFindFlags; - static virClass *virUSBDeviceListClass; static void virUSBDeviceListDispose(void *obj); @@ -102,11 +96,27 @@ static int virUSBSysReadFile(const char *f_name, const= char *d_name, return 0; } +static int virUSBSysReadFileStr(const char *f_name, const char *d_name, + char **value) +{ + char *buf =3D NULL; + g_autofree char *filename =3D NULL; + + filename =3D g_strdup_printf(USB_SYSFS "/devices/%s/%s", d_name, f_nam= e); + + if (virFileReadAll(filename, 1024, &buf) < 0) + return -1; + + *value =3D buf; + return 0; +} + static virUSBDeviceList * virUSBDeviceSearch(unsigned int vendor, unsigned int product, unsigned int bus, unsigned int devno, + const char *port, const char *vroot, unsigned int flags) { @@ -127,6 +137,8 @@ virUSBDeviceSearch(unsigned int vendor, while ((direrr =3D virDirRead(dir, &de, USB_SYSFS "/devices")) > 0) { unsigned int found_prod, found_vend, found_bus, found_devno; + char *found_port; + bool port_matches; char *tmpstr =3D de->d_name; if (strchr(de->d_name, ':')) @@ -154,16 +166,32 @@ virUSBDeviceSearch(unsigned int vendor, 10, &found_devno) < 0) goto cleanup; - if ((flags & USB_DEVICE_FIND_BY_VENDOR) && - (found_prod !=3D product || found_vend !=3D vendor)) - continue; + if (virUSBSysReadFileStr("devpath", de->d_name, + &found_port) < 0) { + goto cleanup; + } else { + found_port[strlen(found_port) - 1] =3D '\0'; /* remove newline= */ + port_matches =3D STREQ_NULLABLE(found_port, port); + VIR_FREE(found_port); + } - if (flags & USB_DEVICE_FIND_BY_BUS) { + if (flags & USB_DEVICE_FIND_BY_VENDOR) { + if (found_prod !=3D product || found_vend !=3D vendor) + continue; + } + + if (flags & USB_DEVICE_FIND_BY_DEVICE) { if (found_bus !=3D bus || found_devno !=3D devno) continue; found =3D true; } + if (flags & USB_DEVICE_FIND_BY_PORT) { + if (found_bus !=3D bus || !port_matches) + continue; + found =3D true; + } + usb =3D virUSBDeviceNew(found_bus, found_devno, vroot); if (!usb) @@ -186,36 +214,41 @@ virUSBDeviceSearch(unsigned int vendor, } int -virUSBDeviceFindByVendor(unsigned int vendor, - unsigned int product, - const char *vroot, - bool mandatory, - virUSBDeviceList **devices) +virUSBDeviceFind(unsigned int vendor, + unsigned int product, + unsigned int bus, + unsigned int devno, + const char *port, + const char *vroot, + bool mandatory, + unsigned int flags, + virUSBDeviceList **devices) { virUSBDeviceList *list; int count; - if (!(list =3D virUSBDeviceSearch(vendor, product, 0, 0, - vroot, - USB_DEVICE_FIND_BY_VENDOR))) + if (!(list =3D virUSBDeviceSearch(vendor, product, bus, devno, port, + vroot, flags))) return -1; - if (list->count =3D=3D 0) { + count =3D list->count; + if (count =3D=3D 0) { virObjectUnref(list); if (!mandatory) { - VIR_DEBUG("Did not find USB device %04x:%04x", - vendor, product); if (devices) *devices =3D NULL; return 0; } virReportError(VIR_ERR_INTERNAL_ERROR, - _("Did not find USB device %1$04x:%2$04x"), vendor,= product); + _("Did not find matching USB device (matching on%1$s%2$s%3$s o= thers are ignored): vid:%4$04x, pid:%5$04x, bus:%6$u, device:%7$u, port:%8$= s"), + flags & USB_DEVICE_FIND_BY_VENDOR ? " vid/pid," : "", + flags & USB_DEVICE_FIND_BY_DEVICE ? " bus/device," : "", + flags & USB_DEVICE_FIND_BY_PORT ? " bus/port," : "", + vendor, product, bus, devno, port ? port : "(null)"); return -1; } - count =3D list->count; if (devices) *devices =3D list; else @@ -224,86 +257,6 @@ virUSBDeviceFindByVendor(unsigned int vendor, return count; } -int -virUSBDeviceFindByBus(unsigned int bus, - unsigned int devno, - const char *vroot, - bool mandatory, - virUSBDevice **usb) -{ - virUSBDeviceList *list; - - if (!(list =3D virUSBDeviceSearch(0, 0, bus, devno, - vroot, - USB_DEVICE_FIND_BY_BUS))) - return -1; - - if (list->count =3D=3D 0) { - virObjectUnref(list); - if (!mandatory) { - VIR_DEBUG("Did not find USB device bus:%u device:%u", - bus, devno); - if (usb) - *usb =3D NULL; - return 0; - } - - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Did not find USB device bus:%1$u device:%2$u"), - bus, devno); - return -1; - } - - if (usb) { - *usb =3D virUSBDeviceListGet(list, 0); - virUSBDeviceListSteal(list, *usb); - } - virObjectUnref(list); - - return 0; -} - -int -virUSBDeviceFind(unsigned int vendor, - unsigned int product, - unsigned int bus, - unsigned int devno, - const char *vroot, - bool mandatory, - virUSBDevice **usb) -{ - virUSBDeviceList *list; - - unsigned int flags =3D USB_DEVICE_FIND_BY_VENDOR|USB_DEVICE_FIND_BY_BU= S; - if (!(list =3D virUSBDeviceSearch(vendor, product, bus, devno, - vroot, flags))) - return -1; - - if (list->count =3D=3D 0) { - virObjectUnref(list); - if (!mandatory) { - VIR_DEBUG("Did not find USB device %04x:%04x bus:%u device:%u", - vendor, product, bus, devno); - if (usb) - *usb =3D NULL; - return 0; - } - - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Did not find USB device %1$04x:%2$04x bus:%3$u d= evice:%4$u"), - vendor, product, bus, devno); - return -1; - } - - if (usb) { - *usb =3D virUSBDeviceListGet(list, 0); - virUSBDeviceListSteal(list, *usb); - } - virObjectUnref(list); - - return 0; -} - virUSBDevice * virUSBDeviceNew(unsigned int bus, unsigned int devno, diff --git a/src/util/virusb.h b/src/util/virusb.h index d2b3f69942..cfd1ad51cc 100644 --- a/src/util/virusb.h +++ b/src/util/virusb.h @@ -30,30 +30,26 @@ typedef struct _virUSBDeviceList virUSBDeviceList; G_DEFINE_AUTOPTR_CLEANUP_FUNC(virUSBDeviceList, virObjectUnref); +typedef enum { + USB_DEVICE_ALL =3D 0, + USB_DEVICE_FIND_BY_VENDOR =3D 1 << 0, + USB_DEVICE_FIND_BY_DEVICE =3D 1 << 1, + USB_DEVICE_FIND_BY_PORT =3D 1 << 2, +} virUSBDeviceFindFlags; virUSBDevice *virUSBDeviceNew(unsigned int bus, unsigned int devno, const char *vroot); -int virUSBDeviceFindByBus(unsigned int bus, - unsigned int devno, - const char *vroot, - bool mandatory, - virUSBDevice **usb); - -int virUSBDeviceFindByVendor(unsigned int vendor, - unsigned int product, - const char *vroot, - bool mandatory, - virUSBDeviceList **devices); - int virUSBDeviceFind(unsigned int vendor, - unsigned int product, - unsigned int bus, - unsigned int devno, - const char *vroot, - bool mandatory, - virUSBDevice **usb); + unsigned int product, + unsigned int bus, + unsigned int devno, + const char *port, + const char *vroot, + bool mandatory, + unsigned int flags, + virUSBDeviceList **devices); void virUSBDeviceFree(virUSBDevice *dev); int virUSBDeviceSetUsedBy(virUSBDevice *dev, diff --git a/tests/virusbtest.c b/tests/virusbtest.c index 870e136321..62b7b8bc29 100644 --- a/tests/virusbtest.c +++ b/tests/virusbtest.c @@ -26,9 +26,11 @@ #define VIR_FROM_THIS VIR_FROM_NONE typedef enum { - FIND_BY_ALL, FIND_BY_VENDOR, - FIND_BY_BUS + FIND_BY_DEVICE, + FIND_BY_PORT, + FIND_BY_VENDOR_AND_DEVICE, + FIND_BY_VENDOR_AND_PORT } testUSBFindFlags; struct findTestInfo { @@ -37,6 +39,7 @@ struct findTestInfo { unsigned int product; unsigned int bus; unsigned int devno; + const char *port; const char *vroot; bool mandatory; int how; @@ -70,25 +73,34 @@ static int testDeviceFind(const void *opaque) g_autoptr(virUSBDeviceList) devs =3D NULL; int rv =3D 0; size_t i, ndevs =3D 0; + unsigned int flags =3D 0; switch (info->how) { - case FIND_BY_ALL: - rv =3D virUSBDeviceFind(info->vendor, info->product, - info->bus, info->devno, - info->vroot, info->mandatory, &dev); - break; case FIND_BY_VENDOR: - rv =3D virUSBDeviceFindByVendor(info->vendor, info->product, - info->vroot, info->mandatory, &devs); + flags =3D USB_DEVICE_FIND_BY_VENDOR; + break; + case FIND_BY_DEVICE: + flags =3D USB_DEVICE_FIND_BY_DEVICE; + break; + case FIND_BY_PORT: + flags =3D USB_DEVICE_FIND_BY_PORT; break; - case FIND_BY_BUS: - rv =3D virUSBDeviceFindByBus(info->bus, info->devno, - info->vroot, info->mandatory, &dev); + case FIND_BY_VENDOR_AND_DEVICE: + flags =3D USB_DEVICE_FIND_BY_VENDOR | + USB_DEVICE_FIND_BY_DEVICE; + break; + case FIND_BY_VENDOR_AND_PORT: + flags =3D USB_DEVICE_FIND_BY_VENDOR | + USB_DEVICE_FIND_BY_PORT; break; } + rv =3D virUSBDeviceFind(info->vendor, info->product, + info->bus, info->devno, info->port, + info->vroot, info->mandatory, flags, &devs); + if (info->expectFailure) { - if (rv =3D=3D 0) { + if (rv >=3D 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", "unexpected success"); } else { @@ -99,9 +111,20 @@ static int testDeviceFind(const void *opaque) goto cleanup; } + if (info->how !=3D FIND_BY_VENDOR) { + if (rv =3D=3D 1) { + dev =3D virUSBDeviceListGet(devs, 0); + virUSBDeviceListSteal(devs, dev); + } else { + goto cleanup; + } + } + switch (info->how) { - case FIND_BY_ALL: - case FIND_BY_BUS: + case FIND_BY_DEVICE: + case FIND_BY_PORT: + case FIND_BY_VENDOR_AND_DEVICE: + case FIND_BY_VENDOR_AND_PORT: if (virUSBDeviceFileIterate(dev, testDeviceFileActor, NULL) < 0) goto cleanup; break; @@ -146,14 +169,17 @@ testUSBList(const void *opaque G_GNUC_UNUSED) virUSBDeviceList *list =3D NULL; virUSBDeviceList *devlist =3D NULL; virUSBDevice *dev =3D NULL; + virUSBDeviceList *devs =3D NULL; int ret =3D -1; + int rv; size_t i, ndevs; if (!(list =3D virUSBDeviceListNew())) goto cleanup; #define EXPECTED_NDEVS_ONE 3 - if (virUSBDeviceFindByVendor(0x1d6b, 0x0002, NULL, true, &devlist) < 0) + if (virUSBDeviceFind(0x1d6b, 0x0002, 0, 0, NULL, NULL, true, + USB_DEVICE_FIND_BY_VENDOR, &devlist) < 0) goto cleanup; ndevs =3D virUSBDeviceListCount(devlist); @@ -176,7 +202,8 @@ testUSBList(const void *opaque G_GNUC_UNUSED) goto cleanup; #define EXPECTED_NDEVS_TWO 3 - if (virUSBDeviceFindByVendor(0x18d1, 0x4e22, NULL, true, &devlist) < 0) + if (virUSBDeviceFind(0x18d1, 0x4e22, 0, 0, NULL, NULL, true, + USB_DEVICE_FIND_BY_VENDOR, &devlist) < 0) goto cleanup; ndevs =3D virUSBDeviceListCount(devlist); @@ -196,8 +223,16 @@ testUSBList(const void *opaque G_GNUC_UNUSED) EXPECTED_NDEVS_ONE + EXPECTED_NDEVS_TWO) < 0) goto cleanup; - if (virUSBDeviceFind(0x18d1, 0x4e22, 1, 20, NULL, true, &dev) < 0) + rv =3D virUSBDeviceFind(0x18d1, 0x4e22, 1, 20, NULL, NULL, true, + USB_DEVICE_FIND_BY_VENDOR | + USB_DEVICE_FIND_BY_DEVICE, &devs); + if (rv !=3D 1) { goto cleanup; + } else { + dev =3D virUSBDeviceListGet(devs, 0); + virUSBDeviceListSteal(devs, dev); + } + virObjectUnref(devs); if (!virUSBDeviceListFind(list, dev)) { virReportError(VIR_ERR_INTERNAL_ERROR, @@ -229,49 +264,75 @@ mymain(void) { int rv =3D 0; -#define DO_TEST_FIND_FULL(name, vend, prod, bus, devno, vroot, mand, how, = fail) \ +#define DO_TEST_FIND_FULL(name, vend, prod, bus, devno, \ + port, vroot, mand, how, fail) \ do { \ struct findTestInfo data =3D { name, vend, prod, bus, \ - devno, vroot, mand, how, fail \ + devno, port, vroot, mand, how, fail \ }; \ if (virTestRun("USBDeviceFind " name, testDeviceFind, &data) < 0) \ rv =3D -1; \ } while (0) -#define DO_TEST_FIND(name, vend, prod, bus, devno) \ - DO_TEST_FIND_FULL(name, vend, prod, bus, devno, NULL, true, \ - FIND_BY_ALL, false) -#define DO_TEST_FIND_FAIL(name, vend, prod, bus, devno) \ - DO_TEST_FIND_FULL(name, vend, prod, bus, devno, NULL, true, \ - FIND_BY_ALL, true) - -#define DO_TEST_FIND_BY_BUS(name, bus, devno) \ - DO_TEST_FIND_FULL(name, 101, 202, bus, devno, NULL, true, \ - FIND_BY_BUS, false) -#define DO_TEST_FIND_BY_BUS_FAIL(name, bus, devno) \ - DO_TEST_FIND_FULL(name, 101, 202, bus, devno, NULL, true, \ - FIND_BY_BUS, true) - #define DO_TEST_FIND_BY_VENDOR(name, vend, prod) \ - DO_TEST_FIND_FULL(name, vend, prod, 123, 456, NULL, true, \ + DO_TEST_FIND_FULL(name, vend, prod, 123, 456, NULL, NULL, true, \ FIND_BY_VENDOR, false) #define DO_TEST_FIND_BY_VENDOR_FAIL(name, vend, prod) \ - DO_TEST_FIND_FULL(name, vend, prod, 123, 456, NULL, true, \ + DO_TEST_FIND_FULL(name, vend, prod, 123, 456, NULL, NULL, true, \ FIND_BY_VENDOR, true) - DO_TEST_FIND("Nexus", 0x18d1, 0x4e22, 1, 20); - DO_TEST_FIND_FAIL("Nexus wrong devnum", 0x18d1, 0x4e22, 1, 25); - DO_TEST_FIND_FAIL("Bogus", 0xf00d, 0xbeef, 1024, 768); - - DO_TEST_FIND_BY_BUS("integrated camera", 1, 5); - DO_TEST_FIND_BY_BUS_FAIL("wrong bus/devno combination", 2, 20); - DO_TEST_FIND_BY_BUS_FAIL("missing bus", 5, 20); - DO_TEST_FIND_BY_BUS_FAIL("missing devnum", 1, 158); +#define DO_TEST_FIND_BY_DEVICE(name, bus, devno) \ + DO_TEST_FIND_FULL(name, 0x1010, 0x2020, bus, devno, NULL, NULL, true, \ + FIND_BY_DEVICE, false) +#define DO_TEST_FIND_BY_DEVICE_FAIL(name, bus, devno) \ + DO_TEST_FIND_FULL(name, 0x1010, 0x2020, bus, devno, NULL, NULL, true, \ + FIND_BY_DEVICE, true) + +#define DO_TEST_FIND_BY_PORT(name, bus, port) \ + DO_TEST_FIND_FULL(name, 0x1010, 0x2020, bus, 456, port, NULL, true, \ + FIND_BY_PORT, false) +#define DO_TEST_FIND_BY_PORT_FAIL(name, bus, port) \ + DO_TEST_FIND_FULL(name, 0x1010, 0x2020, bus, 456, port, NULL, true, \ + FIND_BY_PORT, true) + +#define DO_TEST_FIND_BY_VENDOR_AND_DEVICE(name, vend, prod, bus, devno) \ + DO_TEST_FIND_FULL(name, vend, prod, bus, devno, NULL, NULL, true, \ + FIND_BY_VENDOR_AND_DEVICE, false) +#define DO_TEST_FIND_BY_VENDOR_AND_DEVICE_FAIL(name, vend, prod, bus, devn= o) \ + DO_TEST_FIND_FULL(name, vend, prod, bus, devno, NULL, NULL, true, \ + FIND_BY_VENDOR_AND_DEVICE, true) + +#define DO_TEST_FIND_BY_VENDOR_AND_PORT(name, vend, prod, bus, port) \ + DO_TEST_FIND_FULL(name, vend, prod, bus, 456, port, NULL, true, \ + FIND_BY_VENDOR_AND_PORT, false) +#define DO_TEST_FIND_BY_VENDOR_AND_PORT_FAIL(name, vend, prod, bus, port) \ + DO_TEST_FIND_FULL(name, vend, prod, bus, 456, port, NULL, true, \ + FIND_BY_VENDOR_AND_PORT, true) + + DO_TEST_FIND_BY_DEVICE("integrated camera", 1, 5); + DO_TEST_FIND_BY_DEVICE_FAIL("wrong bus/devno combination", 2, 20); + DO_TEST_FIND_BY_DEVICE_FAIL("missing bus", 5, 20); + DO_TEST_FIND_BY_DEVICE_FAIL("missing devnum", 1, 158); DO_TEST_FIND_BY_VENDOR("Nexus (multiple results)", 0x18d1, 0x4e22); DO_TEST_FIND_BY_VENDOR_FAIL("Bogus vendor and product", 0xf00d, 0xbeef= ); DO_TEST_FIND_BY_VENDOR_FAIL("Valid vendor", 0x1d6b, 0xbeef); + DO_TEST_FIND_BY_PORT("Logitech mouse", 1, "1.5.3.3"); + DO_TEST_FIND_BY_PORT_FAIL("wrong bus/port combination", 2, "1.5.3.3"); + DO_TEST_FIND_BY_PORT_FAIL("missing bus", 5, "1.5.3.3"); + DO_TEST_FIND_BY_PORT_FAIL("missing port", 1, "8.2.5"); + + DO_TEST_FIND_BY_VENDOR_AND_DEVICE("Nexus", 0x18d1, 0x4e22, 1, 20); + DO_TEST_FIND_BY_VENDOR_AND_DEVICE_FAIL("Bogus vendor and product", 0xf= 00d, 0xbeef, 1, 25); + DO_TEST_FIND_BY_VENDOR_AND_DEVICE_FAIL("Nexus wrong devnum", 0x18d1, 0= x4e22, 1, 25); + DO_TEST_FIND_BY_VENDOR_AND_DEVICE_FAIL("Bogus", 0xf00d, 0xbeef, 1024, = 768); + + DO_TEST_FIND_BY_VENDOR_AND_PORT("Nexus", 0x046d, 0xc069, 1, "1.5.3.3"); + DO_TEST_FIND_BY_VENDOR_AND_PORT_FAIL("Bogus vendor and product", 0xf00= d, 0xbeef, 1, "1.5.3.3"); + DO_TEST_FIND_BY_VENDOR_AND_PORT_FAIL("Nexus wrong port", 0x18d1, 0x4e2= 2, 1, "8.2.5"); + DO_TEST_FIND_BY_VENDOR_AND_PORT_FAIL("Bogus", 0xf00d, 0xbeef, 1024, "1= .1.1.1"); + if (virTestRun("USB List test", testUSBList, NULL) < 0) rv =3D -1; diff --git a/tests/virusbtestdata/sys_bus_usb/devices/1-1.5.3.1/devpath b/t= ests/virusbtestdata/sys_bus_usb/devices/1-1.5.3.1/devpath new file mode 100644 index 0000000000..02a7fbef02 --- /dev/null +++ b/tests/virusbtestdata/sys_bus_usb/devices/1-1.5.3.1/devpath @@ -0,0 +1 @@ +1.5.3.1 diff --git a/tests/virusbtestdata/sys_bus_usb/devices/1-1.5.3.3/devpath b/t= ests/virusbtestdata/sys_bus_usb/devices/1-1.5.3.3/devpath new file mode 100644 index 0000000000..23ca863cd4 --- /dev/null +++ b/tests/virusbtestdata/sys_bus_usb/devices/1-1.5.3.3/devpath @@ -0,0 +1 @@ +1.5.3.3 diff --git a/tests/virusbtestdata/sys_bus_usb/devices/1-1.5.3/devpath b/tes= ts/virusbtestdata/sys_bus_usb/devices/1-1.5.3/devpath new file mode 100644 index 0000000000..8af85beb51 --- /dev/null +++ b/tests/virusbtestdata/sys_bus_usb/devices/1-1.5.3/devpath @@ -0,0 +1 @@ +1.5.3 diff --git a/tests/virusbtestdata/sys_bus_usb/devices/1-1.5.4/devpath b/tes= ts/virusbtestdata/sys_bus_usb/devices/1-1.5.4/devpath new file mode 100644 index 0000000000..94fe62c274 --- /dev/null +++ b/tests/virusbtestdata/sys_bus_usb/devices/1-1.5.4/devpath @@ -0,0 +1 @@ +1.5.4 diff --git a/tests/virusbtestdata/sys_bus_usb/devices/1-1.5.5/devpath b/tes= ts/virusbtestdata/sys_bus_usb/devices/1-1.5.5/devpath new file mode 100644 index 0000000000..9075be4951 --- /dev/null +++ b/tests/virusbtestdata/sys_bus_usb/devices/1-1.5.5/devpath @@ -0,0 +1 @@ +1.5.5 diff --git a/tests/virusbtestdata/sys_bus_usb/devices/1-1.5.6/devpath b/tes= ts/virusbtestdata/sys_bus_usb/devices/1-1.5.6/devpath new file mode 100644 index 0000000000..eac1e0ada6 --- /dev/null +++ b/tests/virusbtestdata/sys_bus_usb/devices/1-1.5.6/devpath @@ -0,0 +1 @@ +1.5.6 diff --git a/tests/virusbtestdata/sys_bus_usb/devices/1-1.5/devpath b/tests= /virusbtestdata/sys_bus_usb/devices/1-1.5/devpath new file mode 100644 index 0000000000..c239c60cba --- /dev/null +++ b/tests/virusbtestdata/sys_bus_usb/devices/1-1.5/devpath @@ -0,0 +1 @@ +1.5 diff --git a/tests/virusbtestdata/sys_bus_usb/devices/1-1.6/devpath b/tests= /virusbtestdata/sys_bus_usb/devices/1-1.6/devpath new file mode 100644 index 0000000000..810ee4e91e --- /dev/null +++ b/tests/virusbtestdata/sys_bus_usb/devices/1-1.6/devpath @@ -0,0 +1 @@ +1.6 diff --git a/tests/virusbtestdata/sys_bus_usb/devices/1-1/devpath b/tests/v= irusbtestdata/sys_bus_usb/devices/1-1/devpath new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/tests/virusbtestdata/sys_bus_usb/devices/1-1/devpath @@ -0,0 +1 @@ +1 diff --git a/tests/virusbtestdata/sys_bus_usb/devices/2-1.2/devpath b/tests= /virusbtestdata/sys_bus_usb/devices/2-1.2/devpath new file mode 100644 index 0000000000..5625e59da8 --- /dev/null +++ b/tests/virusbtestdata/sys_bus_usb/devices/2-1.2/devpath @@ -0,0 +1 @@ +1.2 diff --git a/tests/virusbtestdata/sys_bus_usb/devices/2-1/devpath b/tests/v= irusbtestdata/sys_bus_usb/devices/2-1/devpath new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/tests/virusbtestdata/sys_bus_usb/devices/2-1/devpath @@ -0,0 +1 @@ +1 diff --git a/tests/virusbtestdata/sys_bus_usb/devices/usb1/devpath b/tests/= virusbtestdata/sys_bus_usb/devices/usb1/devpath new file mode 100644 index 0000000000..573541ac97 --- /dev/null +++ b/tests/virusbtestdata/sys_bus_usb/devices/usb1/devpath @@ -0,0 +1 @@ +0 diff --git a/tests/virusbtestdata/sys_bus_usb/devices/usb2/devpath b/tests/= virusbtestdata/sys_bus_usb/devices/usb2/devpath new file mode 100644 index 0000000000..573541ac97 --- /dev/null +++ b/tests/virusbtestdata/sys_bus_usb/devices/usb2/devpath @@ -0,0 +1 @@ +0 diff --git a/tests/virusbtestdata/sys_bus_usb/devices/usb3/devpath b/tests/= virusbtestdata/sys_bus_usb/devices/usb3/devpath new file mode 100644 index 0000000000..573541ac97 --- /dev/null +++ b/tests/virusbtestdata/sys_bus_usb/devices/usb3/devpath @@ -0,0 +1 @@ +0 diff --git a/tests/virusbtestdata/sys_bus_usb/devices/usb4/devpath b/tests/= virusbtestdata/sys_bus_usb/devices/usb4/devpath new file mode 100644 index 0000000000..573541ac97 --- /dev/null +++ b/tests/virusbtestdata/sys_bus_usb/devices/usb4/devpath @@ -0,0 +1 @@ +0 -- 2.39.5