mirror of https://gitee.com/openkylin/libvirt.git
USB devices gain a new USB address child element
Expand the domain and the QEmu driver code Adds a couple of tests
This commit is contained in:
parent
33d11150b7
commit
22c0d433ab
|
@ -2030,6 +2030,14 @@
|
|||
</attribute>
|
||||
</element>
|
||||
</define>
|
||||
<define name="usbportaddress">
|
||||
<attribute name="bus">
|
||||
<ref name="usbAddr"/>
|
||||
</attribute>
|
||||
<attribute name="port">
|
||||
<ref name="usbAddr"/>
|
||||
</attribute>
|
||||
</define>
|
||||
<define name="pciaddress">
|
||||
<optional>
|
||||
<attribute name="domain">
|
||||
|
@ -2361,6 +2369,12 @@
|
|||
</attribute>
|
||||
<ref name="ccidaddress"/>
|
||||
</group>
|
||||
<group>
|
||||
<attribute name="type">
|
||||
<value>usb</value>
|
||||
</attribute>
|
||||
<ref name="usbportaddress"/>
|
||||
</group>
|
||||
</choice>
|
||||
</element>
|
||||
</define>
|
||||
|
|
|
@ -133,7 +133,8 @@ VIR_ENUM_IMPL(virDomainDeviceAddress, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST,
|
|||
"pci",
|
||||
"drive",
|
||||
"virtio-serial",
|
||||
"ccid")
|
||||
"ccid",
|
||||
"usb")
|
||||
|
||||
VIR_ENUM_IMPL(virDomainDisk, VIR_DOMAIN_DISK_TYPE_LAST,
|
||||
"block",
|
||||
|
@ -1399,6 +1400,9 @@ int virDomainDeviceAddressIsValid(virDomainDeviceInfoPtr info,
|
|||
|
||||
case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE:
|
||||
return virDomainDeviceDriveAddressIsValid(&info->addr.drive);
|
||||
|
||||
case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB:
|
||||
return virDomainDeviceUSBAddressIsValid(&info->addr.usb);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -1420,6 +1424,13 @@ int virDomainDeviceDriveAddressIsValid(virDomainDeviceDriveAddressPtr addr ATTRI
|
|||
return 1; /* 0 is valid for all fields, so any successfully parsed addr is valid */
|
||||
}
|
||||
|
||||
int virDomainDeviceUSBAddressIsValid(virDomainDeviceUSBAddressPtr addr)
|
||||
{
|
||||
if (addr->port >= 128) /* FIXME: is this correct */
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int virDomainDeviceVirtioSerialAddressIsValid(
|
||||
virDomainDeviceVirtioSerialAddressPtr addr ATTRIBUTE_UNUSED)
|
||||
|
@ -1788,6 +1799,40 @@ cleanup:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
virDomainDeviceUSBAddressParseXML(xmlNodePtr node,
|
||||
virDomainDeviceUSBAddressPtr addr)
|
||||
{
|
||||
char *port, *bus;
|
||||
int ret = -1;
|
||||
|
||||
memset(addr, 0, sizeof(*addr));
|
||||
|
||||
port = virXMLPropString(node, "port");
|
||||
bus = virXMLPropString(node, "bus");
|
||||
|
||||
if (port &&
|
||||
virStrToLong_ui(port, NULL, 10, &addr->port) < 0) {
|
||||
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||
_("Cannot parse <address> 'port' attribute"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (bus &&
|
||||
virStrToLong_ui(bus, NULL, 10, &addr->bus) < 0) {
|
||||
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||
_("Cannot parse <address> 'bus' attribute"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
VIR_FREE(bus);
|
||||
VIR_FREE(port);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Parse the XML definition for a device address
|
||||
* @param node XML nodeset to parse for device address definition
|
||||
*/
|
||||
|
@ -1861,6 +1906,11 @@ virDomainDeviceInfoParseXML(xmlNodePtr node,
|
|||
goto cleanup;
|
||||
break;
|
||||
|
||||
case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB:
|
||||
if (virDomainDeviceUSBAddressParseXML(address, &info->addr.usb) < 0)
|
||||
goto cleanup;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Should not happen */
|
||||
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
|
@ -3807,7 +3857,7 @@ error:
|
|||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Parse the XML definition for a network interface */
|
||||
/* Parse the XML definition for an input device */
|
||||
static virDomainInputDefPtr
|
||||
virDomainInputDefParseXML(const char *ostype,
|
||||
xmlNodePtr node,
|
||||
|
@ -3885,6 +3935,14 @@ virDomainInputDefParseXML(const char *ostype,
|
|||
if (virDomainDeviceInfoParseXML(node, &def->info, flags) < 0)
|
||||
goto error;
|
||||
|
||||
if (def->bus == VIR_DOMAIN_INPUT_BUS_USB &&
|
||||
def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
|
||||
def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB) {
|
||||
virDomainReportError(VIR_ERR_XML_ERROR, "%s",
|
||||
_("Invalid address for a USB device"));
|
||||
goto error;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
VIR_FREE(type);
|
||||
VIR_FREE(bus);
|
||||
|
|
|
@ -69,6 +69,7 @@ enum virDomainDeviceAddressType {
|
|||
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE,
|
||||
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL,
|
||||
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCID,
|
||||
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB,
|
||||
|
||||
VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST
|
||||
};
|
||||
|
@ -105,6 +106,13 @@ struct _virDomainDeviceCcidAddress {
|
|||
unsigned int slot;
|
||||
};
|
||||
|
||||
typedef struct _virDomainDeviceUSBAddress virDomainDeviceUSBAddress;
|
||||
typedef virDomainDeviceUSBAddress *virDomainDeviceUSBAddressPtr;
|
||||
struct _virDomainDeviceUSBAddress {
|
||||
unsigned int bus;
|
||||
unsigned int port;
|
||||
};
|
||||
|
||||
typedef struct _virDomainDeviceInfo virDomainDeviceInfo;
|
||||
typedef virDomainDeviceInfo *virDomainDeviceInfoPtr;
|
||||
struct _virDomainDeviceInfo {
|
||||
|
@ -115,6 +123,7 @@ struct _virDomainDeviceInfo {
|
|||
virDomainDeviceDriveAddress drive;
|
||||
virDomainDeviceVirtioSerialAddress vioserial;
|
||||
virDomainDeviceCcidAddress ccid;
|
||||
virDomainDeviceUSBAddress usb;
|
||||
} addr;
|
||||
};
|
||||
|
||||
|
@ -1440,6 +1449,7 @@ int virDomainDeviceAddressIsValid(virDomainDeviceInfoPtr info,
|
|||
int virDomainDevicePCIAddressIsValid(virDomainDevicePCIAddressPtr addr);
|
||||
int virDomainDeviceDriveAddressIsValid(virDomainDeviceDriveAddressPtr addr);
|
||||
int virDomainDeviceVirtioSerialAddressIsValid(virDomainDeviceVirtioSerialAddressPtr addr);
|
||||
int virDomainDeviceUSBAddressIsValid(virDomainDeviceUSBAddressPtr addr);
|
||||
void virDomainDeviceInfoClear(virDomainDeviceInfoPtr info);
|
||||
void virDomainDefClearPCIAddresses(virDomainDefPtr def);
|
||||
void virDomainDefClearDeviceAliases(virDomainDefPtr def);
|
||||
|
|
|
@ -1325,7 +1325,11 @@ qemuBuildDeviceAddressStr(virBufferPtr buf,
|
|||
info->addr.pci.slot, info->addr.pci.function);
|
||||
else
|
||||
virBufferAsprintf(buf, ",addr=0x%x", info->addr.pci.slot);
|
||||
} else if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB) {
|
||||
virBufferAsprintf(buf, ",bus=usb%d.0", info->addr.usb.bus);
|
||||
virBufferAsprintf(buf, ",port=%d", info->addr.usb.port);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2098,7 +2102,8 @@ error:
|
|||
|
||||
|
||||
char *
|
||||
qemuBuildUSBInputDevStr(virDomainInputDefPtr dev)
|
||||
qemuBuildUSBInputDevStr(virDomainInputDefPtr dev,
|
||||
virBitmapPtr qemuCaps)
|
||||
{
|
||||
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
||||
|
||||
|
@ -2106,6 +2111,9 @@ qemuBuildUSBInputDevStr(virDomainInputDefPtr dev)
|
|||
dev->type == VIR_DOMAIN_INPUT_TYPE_MOUSE ?
|
||||
"usb-mouse" : "usb-tablet", dev->info.alias);
|
||||
|
||||
if (qemuBuildDeviceAddressStr(&buf, &dev->info, qemuCaps) < 0)
|
||||
goto error;
|
||||
|
||||
if (virBufferError(&buf)) {
|
||||
virReportOOMError();
|
||||
goto error;
|
||||
|
@ -2294,9 +2302,10 @@ qemuBuildPCIHostdevPCIDevStr(virDomainHostdevDefPtr dev)
|
|||
|
||||
|
||||
char *
|
||||
qemuBuildUSBHostdevDevStr(virDomainHostdevDefPtr dev)
|
||||
qemuBuildUSBHostdevDevStr(virDomainHostdevDefPtr dev,
|
||||
virBitmapPtr qemuCaps)
|
||||
{
|
||||
char *ret = NULL;
|
||||
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
||||
|
||||
if (!dev->source.subsys.u.usb.bus &&
|
||||
!dev->source.subsys.u.usb.device) {
|
||||
|
@ -2305,13 +2314,24 @@ qemuBuildUSBHostdevDevStr(virDomainHostdevDefPtr dev)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (virAsprintf(&ret, "usb-host,hostbus=%d,hostaddr=%d,id=%s",
|
||||
dev->source.subsys.u.usb.bus,
|
||||
dev->source.subsys.u.usb.device,
|
||||
dev->info.alias) < 0)
|
||||
virReportOOMError();
|
||||
virBufferAsprintf(&buf, "usb-host,hostbus=%d,hostaddr=%d,id=%s",
|
||||
dev->source.subsys.u.usb.bus,
|
||||
dev->source.subsys.u.usb.device,
|
||||
dev->info.alias);
|
||||
|
||||
return ret;
|
||||
if (qemuBuildDeviceAddressStr(&buf, &dev->info, qemuCaps) < 0)
|
||||
goto error;
|
||||
|
||||
if (virBufferError(&buf)) {
|
||||
virReportOOMError();
|
||||
goto error;
|
||||
}
|
||||
|
||||
return virBufferContentAndReset(&buf);
|
||||
|
||||
error:
|
||||
virBufferFreeAndReset(&buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
@ -4232,7 +4252,7 @@ qemuBuildCommandLine(virConnectPtr conn,
|
|||
if (qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) {
|
||||
char *optstr;
|
||||
virCommandAddArg(cmd, "-device");
|
||||
if (!(optstr = qemuBuildUSBInputDevStr(input)))
|
||||
if (!(optstr = qemuBuildUSBInputDevStr(input, qemuCaps)))
|
||||
goto error;
|
||||
virCommandAddArg(cmd, optstr);
|
||||
VIR_FREE(optstr);
|
||||
|
@ -4750,7 +4770,7 @@ qemuBuildCommandLine(virConnectPtr conn,
|
|||
|
||||
if (qemuCapsGet(qemuCaps, QEMU_CAPS_DEVICE)) {
|
||||
virCommandAddArg(cmd, "-device");
|
||||
if (!(devstr = qemuBuildUSBHostdevDevStr(hostdev)))
|
||||
if (!(devstr = qemuBuildUSBHostdevDevStr(hostdev, qemuCaps)))
|
||||
goto error;
|
||||
virCommandAddArg(cmd, devstr);
|
||||
VIR_FREE(devstr);
|
||||
|
|
|
@ -98,7 +98,8 @@ char * qemuBuildWatchdogDevStr(virDomainWatchdogDefPtr dev,
|
|||
char * qemuBuildMemballoonDevStr(virDomainMemballoonDefPtr dev,
|
||||
virBitmapPtr qemuCaps);
|
||||
|
||||
char * qemuBuildUSBInputDevStr(virDomainInputDefPtr dev);
|
||||
char * qemuBuildUSBInputDevStr(virDomainInputDefPtr dev,
|
||||
virBitmapPtr qemuCaps);
|
||||
|
||||
char * qemuBuildSoundDevStr(virDomainSoundDefPtr sound,
|
||||
virBitmapPtr qemuCaps);
|
||||
|
@ -115,7 +116,8 @@ int qemuOpenPCIConfig(virDomainHostdevDefPtr dev);
|
|||
/* Legacy, pre device support */
|
||||
char * qemuBuildUSBHostdevUsbDevStr(virDomainHostdevDefPtr dev);
|
||||
/* Current, best practice */
|
||||
char * qemuBuildUSBHostdevDevStr(virDomainHostdevDefPtr dev);
|
||||
char * qemuBuildUSBHostdevDevStr(virDomainHostdevDefPtr dev,
|
||||
virBitmapPtr qemuCaps);
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -922,7 +922,7 @@ int qemuDomainAttachHostUsbDevice(struct qemud_driver *driver,
|
|||
if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
|
||||
if (qemuAssignDeviceHostdevAlias(vm->def, hostdev, -1) < 0)
|
||||
goto error;
|
||||
if (!(devstr = qemuBuildUSBHostdevDevStr(hostdev)))
|
||||
if (!(devstr = qemuBuildUSBHostdevDevStr(hostdev, priv->qemuCaps)))
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M pc -m 214 -smp 1 -nographic -nodefconfig -nodefaults -monitor unix:/tmp/test-monitor,server,nowait -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -usb -device usb-mouse,id=input0,bus=usb0.0,port=4 -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3
|
|
@ -0,0 +1,27 @@
|
|||
<domain type='qemu'>
|
||||
<name>QEMUGuest1</name>
|
||||
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
|
||||
<memory>219136</memory>
|
||||
<currentMemory>219136</currentMemory>
|
||||
<vcpu>1</vcpu>
|
||||
<os>
|
||||
<type arch='i686' machine='pc'>hvm</type>
|
||||
<boot dev='hd'/>
|
||||
</os>
|
||||
<clock offset='utc'/>
|
||||
<on_poweroff>destroy</on_poweroff>
|
||||
<on_reboot>restart</on_reboot>
|
||||
<on_crash>destroy</on_crash>
|
||||
<devices>
|
||||
<emulator>/usr/bin/qemu</emulator>
|
||||
<disk type='block' device='disk'>
|
||||
<source dev='/dev/HostVG/QEMUGuest1'/>
|
||||
<target dev='hda' bus='ide'/>
|
||||
<address type='drive' controller='0' bus='0' unit='0'/>
|
||||
</disk>
|
||||
<controller type='ide' index='0'/>
|
||||
<input type='mouse' bus='usb'>
|
||||
<address type='usb' bus='0' port='4'/>
|
||||
</input>
|
||||
</devices>
|
||||
</domain>
|
|
@ -496,6 +496,8 @@ mymain(void)
|
|||
DO_TEST("usb-ich9-ehci-addr", false,
|
||||
QEMU_CAPS_CHARDEV, QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG,
|
||||
QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_ICH9_USB_EHCI1);
|
||||
DO_TEST("input-usbmouse-addr", false,
|
||||
QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG);
|
||||
|
||||
DO_TEST("smbios", false, QEMU_CAPS_SMBIOS_TYPE);
|
||||
|
||||
|
|
Loading…
Reference in New Issue