[PATCH v2 2/4] conf: allow to map sound device to host device

Roman Bogorodskiy bogorodskiy at gmail.com
Tue Jul 28 14:58:41 UTC 2020


Introduce a new device element "<audio>" which allows
to map guest sound device specified using the "<sound>"
element to specific audio backend.

Example:

  <sound model='ich6'>
     <audio id='audio0'/>
  </sound>
  <audio id='audio' type='oss'>
     <input dev='/dev/dsp0'/>
     <output dev='/dev/dsp0'/>
  </audio>

This block maps to OSS audio backend on the host using
/dev/dsp0 device for both input (recording)
and output (playback).

OSS is the only backend supported so far.

Signed-off-by: Roman Bogorodskiy <bogorodskiy at gmail.com>
---
 docs/schemas/domaincommon.rng  |  36 ++++++++
 src/conf/domain_capabilities.c |   4 +
 src/conf/domain_conf.c         | 156 ++++++++++++++++++++++++++++++++-
 src/conf/domain_conf.h         |  24 +++++
 src/conf/virconftypes.h        |   3 +
 src/libvirt_private.syms       |   2 +
 src/qemu/qemu_command.c        |   1 +
 src/qemu/qemu_domain.c         |   1 +
 src/qemu/qemu_domain_address.c |   2 +
 src/qemu/qemu_driver.c         |   5 ++
 src/qemu/qemu_hotplug.c        |   3 +
 src/qemu/qemu_validate.c       |   1 +
 12 files changed, 236 insertions(+), 2 deletions(-)

diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index a810f569c6..b0a5e08ba0 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -4366,12 +4366,47 @@
         <optional>
           <ref name="address"/>
         </optional>
+        <optional>
+          <element name="audio">
+            <attribute name="id">
+              <data type="string"/>
+            </attribute>
+          </element>
+        </optional>
         <zeroOrMore>
           <ref name="codec"/>
         </zeroOrMore>
       </interleave>
     </element>
   </define>
+  <define name="audio">
+    <element name="audio">
+      <attribute name="id">
+        <data type="string"/>
+      </attribute>
+      <attribute name="type">
+        <choice>
+          <value>oss</value>
+        </choice>
+      </attribute>
+      <interleave>
+        <optional>
+          <element name="input">
+            <attribute name="dev">
+              <ref name="deviceName"/>
+            </attribute>
+          </element>
+        </optional>
+        <optional>
+          <element name="output">
+            <attribute name="dev">
+              <ref name="deviceName"/>
+            </attribute>
+          </element>
+        </optional>
+      </interleave>
+    </element>
+  </define>
   <define name="watchdog">
     <element name="watchdog">
       <attribute name="model">
@@ -5286,6 +5321,7 @@
             <ref name="interface"/>
             <ref name="input"/>
             <ref name="sound"/>
+            <ref name="audio"/>
             <ref name="hostdev"/>
             <ref name="graphic"/>
             <ref name="video"/>
diff --git a/src/conf/domain_capabilities.c b/src/conf/domain_capabilities.c
index 837b004334..165a792cdf 100644
--- a/src/conf/domain_capabilities.c
+++ b/src/conf/domain_capabilities.c
@@ -692,6 +692,10 @@ virDomainCapsDeviceDefValidate(const virDomainCaps *caps,
         ret = virDomainCapsDeviceVideoDefValidate(caps, dev->data.video);
         break;
 
+    case VIR_DOMAIN_DEVICE_AUDIO:
+        /* TODO: add validation */
+        break;
+
     case VIR_DOMAIN_DEVICE_DISK:
     case VIR_DOMAIN_DEVICE_REDIRDEV:
     case VIR_DOMAIN_DEVICE_NET:
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 7ecd2818b9..50a5c3387d 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -323,6 +323,7 @@ VIR_ENUM_IMPL(virDomainDevice,
               "memory",
               "iommu",
               "vsock",
+              "audio",
 );
 
 VIR_ENUM_IMPL(virDomainDiskDevice,
@@ -728,6 +729,11 @@ VIR_ENUM_IMPL(virDomainSoundModel,
               "usb",
 );
 
+VIR_ENUM_IMPL(virDomainAudioType,
+              VIR_DOMAIN_AUDIO_TYPE_LAST,
+              "oss",
+);
+
 VIR_ENUM_IMPL(virDomainKeyWrapCipherName,
               VIR_DOMAIN_KEY_WRAP_CIPHER_NAME_LAST,
               "aes",
@@ -2850,6 +2856,21 @@ void virDomainSoundDefFree(virDomainSoundDefPtr def)
         virDomainSoundCodecDefFree(def->codecs[i]);
     VIR_FREE(def->codecs);
 
+    VIR_FREE(def->audioId);
+
+    VIR_FREE(def);
+}
+
+void virDomainAudioDefFree(virDomainAudioDefPtr def)
+{
+    if (!def)
+        return;
+
+    VIR_FREE(def->id);
+
+    VIR_FREE(def->inputDev);
+    VIR_FREE(def->outputDev);
+
     VIR_FREE(def);
 }
 
@@ -3206,6 +3227,9 @@ void virDomainDeviceDefFree(virDomainDeviceDefPtr def)
     case VIR_DOMAIN_DEVICE_VSOCK:
         virDomainVsockDefFree(def->data.vsock);
         break;
+    case VIR_DOMAIN_DEVICE_AUDIO:
+        virDomainAudioDefFree(def->data.audio);
+        break;
     case VIR_DOMAIN_DEVICE_LAST:
     case VIR_DOMAIN_DEVICE_NONE:
         break;
@@ -3466,6 +3490,10 @@ void virDomainDefFree(virDomainDefPtr def)
         virDomainSoundDefFree(def->sounds[i]);
     VIR_FREE(def->sounds);
 
+    for (i = 0; i < def->naudios; i++)
+        virDomainAudioDefFree(def->audios[i]);
+    VIR_FREE(def->audios);
+
     for (i = 0; i < def->nvideos; i++)
         virDomainVideoDefFree(def->videos[i]);
     VIR_FREE(def->videos);
@@ -4054,6 +4082,7 @@ virDomainDeviceGetInfo(virDomainDeviceDefPtr device)
     case VIR_DOMAIN_DEVICE_LEASE:
     case VIR_DOMAIN_DEVICE_GRAPHICS:
     case VIR_DOMAIN_DEVICE_IOMMU:
+    case VIR_DOMAIN_DEVICE_AUDIO:
     case VIR_DOMAIN_DEVICE_LAST:
     case VIR_DOMAIN_DEVICE_NONE:
         break;
@@ -4148,6 +4177,9 @@ virDomainDeviceSetData(virDomainDeviceDefPtr device,
     case VIR_DOMAIN_DEVICE_LEASE:
         device->data.lease = devicedata;
         break;
+    case VIR_DOMAIN_DEVICE_AUDIO:
+        device->data.audio = devicedata;
+        break;
     case VIR_DOMAIN_DEVICE_NONE:
     case VIR_DOMAIN_DEVICE_LAST:
         break;
@@ -4414,6 +4446,7 @@ virDomainDeviceInfoIterateInternal(virDomainDefPtr def,
     case VIR_DOMAIN_DEVICE_MEMORY:
     case VIR_DOMAIN_DEVICE_IOMMU:
     case VIR_DOMAIN_DEVICE_VSOCK:
+    case VIR_DOMAIN_DEVICE_AUDIO:
         break;
     }
 #endif
@@ -5406,6 +5439,7 @@ virDomainDeviceDefPostParseCommon(virDomainDeviceDefPtr dev,
     case VIR_DOMAIN_DEVICE_PANIC:
     case VIR_DOMAIN_DEVICE_MEMORY:
     case VIR_DOMAIN_DEVICE_IOMMU:
+    case VIR_DOMAIN_DEVICE_AUDIO:
         ret = 0;
         break;
 
@@ -6795,6 +6829,8 @@ virDomainDeviceDefValidateInternal(const virDomainDeviceDef *dev,
     case VIR_DOMAIN_DEVICE_SHMEM:
         return virDomainShmemDefValidate(dev->data.shmem);
 
+    case VIR_DOMAIN_DEVICE_AUDIO:
+        /* TODO: validate? */
     case VIR_DOMAIN_DEVICE_LEASE:
     case VIR_DOMAIN_DEVICE_FS:
     case VIR_DOMAIN_DEVICE_SOUND:
@@ -14984,10 +15020,10 @@ virDomainSoundDefParseXML(virDomainXMLOptionPtr xmlopt,
     virDomainSoundDefPtr def;
     VIR_XPATH_NODE_AUTORESTORE(ctxt);
     g_autofree char *model = NULL;
+    xmlNodePtr audioNode;
 
     if (VIR_ALLOC(def) < 0)
         return NULL;
-
     ctxt->node = node;
 
     model = virXMLPropString(node, "model");
@@ -15024,6 +15060,10 @@ virDomainSoundDefParseXML(virDomainXMLOptionPtr xmlopt,
         }
     }
 
+    audioNode = virXPathNode("./audio", ctxt);
+    if (audioNode)
+        def->audioId = virXMLPropString(audioNode, "id");
+
     if (virDomainDeviceInfoParseXML(xmlopt, node, &def->info, flags) < 0)
         goto error;
 
@@ -15075,6 +15115,51 @@ virDomainSoundDefFind(const virDomainDef *def,
 }
 
 
+static virDomainAudioDefPtr
+virDomainAudioDefParseXML(virDomainXMLOptionPtr xmlopt G_GNUC_UNUSED,
+                          xmlNodePtr node G_GNUC_UNUSED,
+                          xmlXPathContextPtr ctxt G_GNUC_UNUSED)
+{
+    virDomainAudioDefPtr def;
+    VIR_XPATH_NODE_AUTORESTORE(ctxt);
+    g_autofree char *type = NULL;
+
+    if (VIR_ALLOC(def) < 0)
+        return NULL;
+    ctxt->node = node;
+
+    type = virXMLPropString(node, "type");
+    if ((def->type = virDomainAudioTypeTypeFromString(type)) < 0) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("unknown audio type '%s'"), type);
+        goto error;
+    }
+
+    def->id = virXMLPropString(node, "id");
+
+    if (def->type == VIR_DOMAIN_AUDIO_TYPE_OSS) {
+        xmlNodePtr inputDevNode, outputDevNode;
+
+        inputDevNode = virXPathNode("./input", ctxt);
+        outputDevNode = virXPathNode("./output", ctxt);
+
+        if (!inputDevNode || !outputDevNode) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                           _("Audio type OSS requires to have <input> "
+                             "and <output> specified"));
+            goto error;
+        }
+
+        def->inputDev = virXMLPropString(inputDevNode, "dev");
+        def->outputDev = virXMLPropString(outputDevNode, "dev");
+    }
+
+    return def;
+
+ error:
+    virDomainAudioDefFree(def);
+    return NULL;
+}
 static virDomainWatchdogDefPtr
 virDomainWatchdogDefParseXML(virDomainXMLOptionPtr xmlopt,
                              xmlNodePtr node,
@@ -17014,6 +17099,10 @@ virDomainDeviceDefParse(const char *xmlStr,
                                                           ctxt, flags)))
             return NULL;
         break;
+    case VIR_DOMAIN_DEVICE_AUDIO:
+        if (!(dev->data.audio = virDomainAudioDefParseXML(xmlopt, node, ctxt)))
+            return NULL;
+        break;
     case VIR_DOMAIN_DEVICE_WATCHDOG:
         if (!(dev->data.watchdog = virDomainWatchdogDefParseXML(xmlopt,
                                                                 node, flags)))
@@ -21910,6 +21999,22 @@ virDomainDefParseXML(xmlDocPtr xml,
     }
     VIR_FREE(nodes);
 
+    /* analysis of the audio devices */
+    if ((n = virXPathNodeSet("./devices/audio", ctxt, &nodes)) < 0)
+        goto error;
+    if (n && VIR_ALLOC_N(def->audios, n) < 0)
+        goto error;
+    for (i = 0; i < n; i++) {
+        virDomainAudioDefPtr audio = virDomainAudioDefParseXML(xmlopt,
+                                                               nodes[i],
+                                                               ctxt);
+        if (!audio)
+            goto error;
+
+        def->audios[def->naudios++] = audio;
+    }
+    VIR_FREE(nodes);
+
     /* analysis of the video devices */
     if ((n = virXPathNodeSet("./devices/video", ctxt, &nodes)) < 0)
         goto error;
@@ -22424,7 +22529,6 @@ virDomainDefParse(const char *xmlStr,
     virDomainDefPtr def = NULL;
     int keepBlanksDefault = xmlKeepBlanksDefault(0);
     xmlNodePtr root;
-
     if (!(xml = virXMLParse(filename, xmlStr, _("(domain_definition)"))))
         goto cleanup;
 
@@ -24523,6 +24627,7 @@ virDomainDefCheckABIStabilityFlags(virDomainDefPtr src,
     case VIR_DOMAIN_DEVICE_MEMORY:
     case VIR_DOMAIN_DEVICE_IOMMU:
     case VIR_DOMAIN_DEVICE_VSOCK:
+    case VIR_DOMAIN_DEVICE_AUDIO:
         break;
     }
 #endif
@@ -27284,6 +27389,9 @@ virDomainSoundDefFormat(virBufferPtr buf,
     for (i = 0; i < def->ncodecs; i++)
         virDomainSoundCodecDefFormat(&childBuf, def->codecs[i]);
 
+    if (def->audioId)
+        virBufferAsprintf(&childBuf, "<audio id='%s'/>\n", def->audioId);
+
     if (virDomainDeviceInfoFormat(&childBuf, &def->info, flags) < 0)
         return -1;
 
@@ -27300,6 +27408,42 @@ virDomainSoundDefFormat(virBufferPtr buf,
 }
 
 
+static int
+virDomainAudioDefFormat(virBufferPtr buf,
+                        virDomainAudioDefPtr def)
+{
+    g_auto(virBuffer) childBuf = VIR_BUFFER_INIT_CHILD(buf);
+    const char *type = virDomainAudioTypeTypeToString(def->type);
+
+    if (!type) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("unexpected audio type %d"), def->type);
+        return -1;
+    }
+
+    virBufferAsprintf(buf, "<audio id='%s' type='%s'", def->id, type);
+
+    switch (def->type) {
+    case VIR_DOMAIN_AUDIO_TYPE_OSS:
+        if (def->inputDev)
+            virBufferAsprintf(&childBuf, "<input dev='%s'/>\n", def->inputDev);
+        if (def->outputDev)
+            virBufferAsprintf(&childBuf, "<output dev='%s'/>\n", def->outputDev);
+        break;
+    }
+
+    if (virBufferUse(&childBuf)) {
+        virBufferAddLit(buf, ">\n");
+        virBufferAddBuffer(buf, &childBuf);
+        virBufferAddLit(buf, "</audio>\n");
+    } else {
+        virBufferAddLit(buf, "/>\n");
+    }
+
+    return 0;
+}
+
+
 static int
 virDomainMemballoonDefFormat(virBufferPtr buf,
                              virDomainMemballoonDefPtr def,
@@ -29975,6 +30119,11 @@ virDomainDefFormatInternalSetRootName(virDomainDefPtr def,
             return -1;
     }
 
+    for (n = 0; n < def->naudios; n++) {
+        if (virDomainAudioDefFormat(buf, def->audios[n]) < 0)
+            return -1;
+    }
+
     for (n = 0; n < def->nvideos; n++) {
         if (virDomainVideoDefFormat(buf, def->videos[n], flags) < 0)
             return -1;
@@ -31147,6 +31296,9 @@ virDomainDeviceDefCopy(virDomainDeviceDefPtr src,
     case VIR_DOMAIN_DEVICE_VSOCK:
         rc = virDomainVsockDefFormat(&buf, src->data.vsock);
         break;
+    case VIR_DOMAIN_DEVICE_AUDIO:
+        rc = virDomainAudioDefFormat(&buf, src->data.audio);
+        break;
 
     case VIR_DOMAIN_DEVICE_NONE:
     case VIR_DOMAIN_DEVICE_SMARTCARD:
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 241149af24..fefd428ccd 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -85,6 +85,7 @@ typedef enum {
     VIR_DOMAIN_DEVICE_MEMORY,
     VIR_DOMAIN_DEVICE_IOMMU,
     VIR_DOMAIN_DEVICE_VSOCK,
+    VIR_DOMAIN_DEVICE_AUDIO,
 
     VIR_DOMAIN_DEVICE_LAST
 } virDomainDeviceType;
@@ -116,6 +117,7 @@ struct _virDomainDeviceDef {
         virDomainMemoryDefPtr memory;
         virDomainIOMMUDefPtr iommu;
         virDomainVsockDefPtr vsock;
+        virDomainAudioDefPtr audio;
     } data;
 };
 
@@ -1415,6 +1417,23 @@ struct _virDomainSoundDef {
 
     size_t ncodecs;
     virDomainSoundCodecDefPtr *codecs;
+
+    char *audioId;
+};
+
+typedef enum {
+    VIR_DOMAIN_AUDIO_TYPE_OSS,
+
+    VIR_DOMAIN_AUDIO_TYPE_LAST
+} virDomainAudioType;
+
+struct _virDomainAudioDef {
+    int type;
+
+    char *id;
+
+    /* OSS specific configuration */
+    char *inputDev, *outputDev;
 };
 
 typedef enum {
@@ -2591,6 +2610,9 @@ struct _virDomainDef {
     size_t nsounds;
     virDomainSoundDefPtr *sounds;
 
+    size_t naudios;
+    virDomainAudioDefPtr *audios;
+
     size_t nvideos;
     virDomainVideoDefPtr *videos;
 
@@ -3021,6 +3043,7 @@ ssize_t virDomainSoundDefFind(const virDomainDef *def,
                               const virDomainSoundDef *sound);
 void virDomainSoundDefFree(virDomainSoundDefPtr def);
 virDomainSoundDefPtr virDomainSoundDefRemove(virDomainDefPtr def, size_t idx);
+void virDomainAudioDefFree(virDomainAudioDefPtr def);
 void virDomainMemballoonDefFree(virDomainMemballoonDefPtr def);
 void virDomainNVRAMDefFree(virDomainNVRAMDefPtr def);
 void virDomainWatchdogDefFree(virDomainWatchdogDefPtr def);
@@ -3580,6 +3603,7 @@ VIR_ENUM_DECL(virDomainChrTcpProtocol);
 VIR_ENUM_DECL(virDomainChrSpicevmc);
 VIR_ENUM_DECL(virDomainSoundCodec);
 VIR_ENUM_DECL(virDomainSoundModel);
+VIR_ENUM_DECL(virDomainAudioType);
 VIR_ENUM_DECL(virDomainKeyWrapCipherName);
 VIR_ENUM_DECL(virDomainMemballoonModel);
 VIR_ENUM_DECL(virDomainSmbiosMode);
diff --git a/src/conf/virconftypes.h b/src/conf/virconftypes.h
index 1c62cde251..9042a2b34f 100644
--- a/src/conf/virconftypes.h
+++ b/src/conf/virconftypes.h
@@ -309,6 +309,9 @@ typedef virDomainSoundCodecDef *virDomainSoundCodecDefPtr;
 typedef struct _virDomainSoundDef virDomainSoundDef;
 typedef virDomainSoundDef *virDomainSoundDefPtr;
 
+typedef struct _virDomainAudioDef virDomainAudioDef;
+typedef virDomainAudioDef *virDomainAudioDefPtr;
+
 typedef struct _virDomainTPMDef virDomainTPMDef;
 typedef virDomainTPMDef *virDomainTPMDefPtr;
 
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 73b72c9e10..98e041bd53 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -224,6 +224,8 @@ virDiskNameToBusDeviceIndex;
 virDiskNameToIndex;
 virDomainActualNetDefFree;
 virDomainActualNetDefValidate;
+virDomainAudioTypeTypeFromString;
+virDomainAudioTypeTypeToString;
 virDomainBlockedReasonTypeFromString;
 virDomainBlockedReasonTypeToString;
 virDomainBlockIoTuneInfoCopy;
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 839c93bfb4..f5c31c8a9f 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -522,6 +522,7 @@ qemuBuildVirtioDevStr(virBufferPtr buf,
         case VIR_DOMAIN_DEVICE_PANIC:
         case VIR_DOMAIN_DEVICE_MEMORY:
         case VIR_DOMAIN_DEVICE_IOMMU:
+        case VIR_DOMAIN_DEVICE_AUDIO:
         case VIR_DOMAIN_DEVICE_LAST:
         default:
             return 0;
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 7530edac53..d92bf71c8b 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -5255,6 +5255,7 @@ qemuDomainDeviceDefPostParse(virDomainDeviceDefPtr dev,
     case VIR_DOMAIN_DEVICE_RNG:
     case VIR_DOMAIN_DEVICE_MEMORY:
     case VIR_DOMAIN_DEVICE_IOMMU:
+    case VIR_DOMAIN_DEVICE_AUDIO:
         ret = 0;
         break;
 
diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c
index 058cbda2a2..97d21aaf8c 100644
--- a/src/qemu/qemu_domain_address.c
+++ b/src/qemu/qemu_domain_address.c
@@ -531,6 +531,7 @@ qemuDomainDeviceSupportZPCI(virDomainDeviceDefPtr device)
     case VIR_DOMAIN_DEVICE_MEMORY:
     case VIR_DOMAIN_DEVICE_IOMMU:
     case VIR_DOMAIN_DEVICE_VSOCK:
+    case VIR_DOMAIN_DEVICE_AUDIO:
         break;
 
     case VIR_DOMAIN_DEVICE_NONE:
@@ -1046,6 +1047,7 @@ qemuDomainDeviceCalculatePCIConnectFlags(virDomainDeviceDefPtr dev,
     case VIR_DOMAIN_DEVICE_LEASE:
     case VIR_DOMAIN_DEVICE_GRAPHICS:
     case VIR_DOMAIN_DEVICE_IOMMU:
+    case VIR_DOMAIN_DEVICE_AUDIO:
     case VIR_DOMAIN_DEVICE_LAST:
     case VIR_DOMAIN_DEVICE_NONE:
         return 0;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index d185666ed8..4d09391062 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -7953,6 +7953,7 @@ qemuDomainAttachDeviceLive(virDomainObjPtr vm,
     case VIR_DOMAIN_DEVICE_TPM:
     case VIR_DOMAIN_DEVICE_PANIC:
     case VIR_DOMAIN_DEVICE_IOMMU:
+    case VIR_DOMAIN_DEVICE_AUDIO:
     case VIR_DOMAIN_DEVICE_LAST:
         virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                        _("live attach of device '%s' is not supported"),
@@ -8087,6 +8088,7 @@ qemuDomainUpdateDeviceLive(virDomainObjPtr vm,
     case VIR_DOMAIN_DEVICE_PANIC:
     case VIR_DOMAIN_DEVICE_IOMMU:
     case VIR_DOMAIN_DEVICE_VSOCK:
+    case VIR_DOMAIN_DEVICE_AUDIO:
     case VIR_DOMAIN_DEVICE_LAST:
         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                        _("live update of device '%s' is not supported"),
@@ -8306,6 +8308,7 @@ qemuDomainAttachDeviceConfig(virDomainDefPtr vmdef,
     case VIR_DOMAIN_DEVICE_TPM:
     case VIR_DOMAIN_DEVICE_PANIC:
     case VIR_DOMAIN_DEVICE_IOMMU:
+    case VIR_DOMAIN_DEVICE_AUDIO:
     case VIR_DOMAIN_DEVICE_LAST:
          virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                         _("persistent attach of device '%s' is not supported"),
@@ -8508,6 +8511,7 @@ qemuDomainDetachDeviceConfig(virDomainDefPtr vmdef,
     case VIR_DOMAIN_DEVICE_TPM:
     case VIR_DOMAIN_DEVICE_PANIC:
     case VIR_DOMAIN_DEVICE_IOMMU:
+    case VIR_DOMAIN_DEVICE_AUDIO:
     case VIR_DOMAIN_DEVICE_LAST:
         virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                        _("persistent detach of device '%s' is not supported"),
@@ -8615,6 +8619,7 @@ qemuDomainUpdateDeviceConfig(virDomainDefPtr vmdef,
     case VIR_DOMAIN_DEVICE_PANIC:
     case VIR_DOMAIN_DEVICE_IOMMU:
     case VIR_DOMAIN_DEVICE_VSOCK:
+    case VIR_DOMAIN_DEVICE_AUDIO:
     case VIR_DOMAIN_DEVICE_LAST:
         virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                        _("persistent update of device '%s' is not supported"),
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 26912334d2..008533bd8c 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -4944,6 +4944,7 @@ qemuDomainRemoveAuditDevice(virDomainObjPtr vm,
     case VIR_DOMAIN_DEVICE_TPM:
     case VIR_DOMAIN_DEVICE_PANIC:
     case VIR_DOMAIN_DEVICE_IOMMU:
+    case VIR_DOMAIN_DEVICE_AUDIO:
     case VIR_DOMAIN_DEVICE_LAST:
         /* libvirt doesn't yet support detaching these devices */
         break;
@@ -5042,6 +5043,7 @@ qemuDomainRemoveDevice(virQEMUDriverPtr driver,
     case VIR_DOMAIN_DEVICE_TPM:
     case VIR_DOMAIN_DEVICE_PANIC:
     case VIR_DOMAIN_DEVICE_IOMMU:
+    case VIR_DOMAIN_DEVICE_AUDIO:
     case VIR_DOMAIN_DEVICE_LAST:
         virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                        _("don't know how to remove a %s device"),
@@ -5813,6 +5815,7 @@ qemuDomainDetachDeviceLive(virDomainObjPtr vm,
     case VIR_DOMAIN_DEVICE_TPM:
     case VIR_DOMAIN_DEVICE_PANIC:
     case VIR_DOMAIN_DEVICE_IOMMU:
+    case VIR_DOMAIN_DEVICE_AUDIO:
     case VIR_DOMAIN_DEVICE_LAST:
         virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                        _("live detach of device '%s' is not supported"),
diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c
index 488f258d00..97c227e034 100644
--- a/src/qemu/qemu_validate.c
+++ b/src/qemu/qemu_validate.c
@@ -4144,6 +4144,7 @@ qemuValidateDomainDeviceDef(const virDomainDeviceDef *dev,
     case VIR_DOMAIN_DEVICE_LEASE:
     case VIR_DOMAIN_DEVICE_SHMEM:
     case VIR_DOMAIN_DEVICE_PANIC:
+    case VIR_DOMAIN_DEVICE_AUDIO:
     case VIR_DOMAIN_DEVICE_NONE:
     case VIR_DOMAIN_DEVICE_LAST:
         break;
-- 
2.27.0




More information about the libvir-list mailing list