qemu: sound: Support intel 'ich6' model

In QEMU, the card itself is a PCI device, but it requires a codec
(either -device hda-output or -device hda-duplex) to actually output
sound. Specifying <sound model='ich6'/> gives us -device intel-hda
-device hda-duplex I think it's important that a simple <sound model='ich6'/>
sets up a useful codec, to have consistent behavior with all other sound cards.

This is basically Dan's proposal of

    <sound model='ich6'>
        <codec type='output' slot='0'/>
        <codec type='duplex' slot='3'/>
    </sound>

without the codec bits implemented.

The important thing is to keep a consistent API here, we don't want some
<sound> devs require tweaking codecs but not others. Steps I see to
accomplishing this:

    - every <sound> device has a <codec type='default'/> (unless codecs are
        manually specified)
    - <codec type='none'/> is required to specify 'no codecs'
    - new audio settings like mic=on|off could then be exposed in
        <sound> or <codec> in a consistent manner for all sound models

v2:
    Use model='ich6'

v3:
    Use feature detection, from eblake
    Set codec id, bus, and cad values

v4:
    intel-hda isn't supported if -device isn't available

v5:
    Comment spelling fixes
This commit is contained in:
Cole Robinson 2011-01-13 09:15:11 -05:00
parent 4a267912bf
commit 6cabc0b0d0
10 changed files with 70 additions and 7 deletions

View File

@ -1880,8 +1880,9 @@ qemu-kvm -net nic,model=? /dev/null
The <code>sound</code> element has one mandatory attribute, The <code>sound</code> element has one mandatory attribute,
<code>model</code>, which specifies what real sound device is emulated. <code>model</code>, which specifies what real sound device is emulated.
Valid values are specific to the underlying hypervisor, though typical Valid values are specific to the underlying hypervisor, though typical
choices are 'es1370', 'sb16', and 'ac97' choices are 'es1370', 'sb16', 'ac97', and 'ich6'
(<span class="since">'ac97' only since 0.6.0</span>) (<span class="since">
'ac97' only since 0.6.0, 'ich6' only since 0.8.8</span>)
</dd> </dd>
</dl> </dl>

View File

@ -1530,6 +1530,7 @@
<value>es1370</value> <value>es1370</value>
<value>pcspk</value> <value>pcspk</value>
<value>ac97</value> <value>ac97</value>
<value>ich6</value>
</choice> </choice>
</attribute> </attribute>
<optional> <optional>

View File

@ -231,7 +231,8 @@ VIR_ENUM_IMPL(virDomainSoundModel, VIR_DOMAIN_SOUND_MODEL_LAST,
"sb16", "sb16",
"es1370", "es1370",
"pcspk", "pcspk",
"ac97") "ac97",
"ich6")
VIR_ENUM_IMPL(virDomainMemballoonModel, VIR_DOMAIN_MEMBALLOON_MODEL_LAST, VIR_ENUM_IMPL(virDomainMemballoonModel, VIR_DOMAIN_MEMBALLOON_MODEL_LAST,
"virtio", "virtio",

View File

@ -480,6 +480,7 @@ enum virDomainSoundModel {
VIR_DOMAIN_SOUND_MODEL_ES1370, VIR_DOMAIN_SOUND_MODEL_ES1370,
VIR_DOMAIN_SOUND_MODEL_PCSPK, VIR_DOMAIN_SOUND_MODEL_PCSPK,
VIR_DOMAIN_SOUND_MODEL_AC97, VIR_DOMAIN_SOUND_MODEL_AC97,
VIR_DOMAIN_SOUND_MODEL_ICH6,
VIR_DOMAIN_SOUND_MODEL_LAST VIR_DOMAIN_SOUND_MODEL_LAST
}; };

View File

@ -1079,6 +1079,11 @@ cleanup:
int int
qemuCapsParseDeviceStr(const char *str, unsigned long long *flags) qemuCapsParseDeviceStr(const char *str, unsigned long long *flags)
{ {
/* Which devices exist. */
if (strstr(str, "name \"hda-duplex\""))
*flags |= QEMUD_CMD_FLAG_HDA_DUPLEX;
/* Features of given devices. */
if (strstr(str, "pci-assign.configfd")) if (strstr(str, "pci-assign.configfd"))
*flags |= QEMUD_CMD_FLAG_PCI_CONFIGFD; *flags |= QEMUD_CMD_FLAG_PCI_CONFIGFD;
if (strstr(str, "virtio-blk-pci.bootindex")) if (strstr(str, "virtio-blk-pci.bootindex"))

View File

@ -84,6 +84,7 @@ enum qemuCapsFlags {
QEMUD_CMD_FLAG_VGA_NONE = (1LL << 47), /* The 'none' arg for '-vga' */ QEMUD_CMD_FLAG_VGA_NONE = (1LL << 47), /* The 'none' arg for '-vga' */
QEMUD_CMD_FLAG_MIGRATE_QEMU_FD = (1LL << 48), /* -incoming fd:n */ QEMUD_CMD_FLAG_MIGRATE_QEMU_FD = (1LL << 48), /* -incoming fd:n */
QEMUD_CMD_FLAG_BOOTINDEX = (1LL << 49), /* -device bootindex property */ QEMUD_CMD_FLAG_BOOTINDEX = (1LL << 49), /* -device bootindex property */
QEMUD_CMD_FLAG_HDA_DUPLEX = (1LL << 50), /* -device hda-duplex */
}; };
virCapsPtr qemuCapsInit(virCapsPtr old_caps); virCapsPtr qemuCapsInit(virCapsPtr old_caps);

View File

@ -1774,11 +1774,13 @@ qemuBuildSoundDevStr(virDomainSoundDefPtr sound)
goto error; goto error;
} }
/* Hack for 2 wierdly unusal devices name in QEMU */ /* Hack for weirdly unusual devices name in QEMU */
if (STREQ(model, "es1370")) if (STREQ(model, "es1370"))
model = "ES1370"; model = "ES1370";
else if (STREQ(model, "ac97")) else if (STREQ(model, "ac97"))
model = "AC97"; model = "AC97";
else if (STREQ(model, "ich6"))
model = "intel-hda";
virBufferVSprintf(&buf, "%s", model); virBufferVSprintf(&buf, "%s", model);
virBufferVSprintf(&buf, ",id=%s", sound->info.alias); virBufferVSprintf(&buf, ",id=%s", sound->info.alias);
@ -1797,6 +1799,29 @@ error:
return NULL; return NULL;
} }
static char *
qemuBuildSoundCodecStr(virDomainSoundDefPtr sound,
const char *codec)
{
virBuffer buf = VIR_BUFFER_INITIALIZER;
int cad = 0;
virBufferVSprintf(&buf, "%s", codec);
virBufferVSprintf(&buf, ",id=%s-codec%d", sound->info.alias, cad);
virBufferVSprintf(&buf, ",bus=%s.0", sound->info.alias);
virBufferVSprintf(&buf, ",cad=%d", cad);
if (virBufferError(&buf)) {
virReportOOMError();
goto error;
}
return virBufferContentAndReset(&buf);
error:
virBufferFreeAndReset(&buf);
return NULL;
}
static char * static char *
qemuBuildVideoDevStr(virDomainVideoDefPtr video) qemuBuildVideoDevStr(virDomainVideoDefPtr video)
@ -3817,11 +3842,29 @@ qemuBuildCommandLine(virConnectPtr conn,
virCommandAddArgList(cmd, "-soundhw", "pcspk", NULL); virCommandAddArgList(cmd, "-soundhw", "pcspk", NULL);
} else { } else {
virCommandAddArg(cmd, "-device"); virCommandAddArg(cmd, "-device");
if (!(str = qemuBuildSoundDevStr(sound))) if (!(str = qemuBuildSoundDevStr(sound)))
goto error; goto error;
virCommandAddArg(cmd, str); virCommandAddArg(cmd, str);
if (sound->model == VIR_DOMAIN_SOUND_MODEL_ICH6) {
char *codecstr = NULL;
if (!(qemuCmdFlags & QEMUD_CMD_FLAG_HDA_DUPLEX)) {
qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("this QEMU binary lacks hda support"));
goto error;
}
virCommandAddArg(cmd, "-device");
if (!(codecstr = qemuBuildSoundCodecStr(sound,
"hda-duplex"))) {
goto error;
}
virCommandAddArg(cmd, codecstr);
VIR_FREE(codecstr);
}
VIR_FREE(str); VIR_FREE(str);
} }
} }
@ -3840,6 +3883,13 @@ qemuBuildCommandLine(virConnectPtr conn,
"%s", _("invalid sound model")); "%s", _("invalid sound model"));
goto error; goto error;
} }
if (sound->model == VIR_DOMAIN_SOUND_MODEL_ICH6) {
qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("this QEMU binary lacks hda support"));
goto error;
}
strncat(modstr, model, size); strncat(modstr, model, size);
size -= strlen(model); size -= strlen(model);
if (i < (def->nsounds - 1)) if (i < (def->nsounds - 1))
@ -5675,6 +5725,8 @@ virDomainDefPtr qemuParseCommandLine(virCapsPtr caps,
type = VIR_DOMAIN_SOUND_MODEL_ES1370; type = VIR_DOMAIN_SOUND_MODEL_ES1370;
} else if (STRPREFIX(start, "ac97")) { } else if (STRPREFIX(start, "ac97")) {
type = VIR_DOMAIN_SOUND_MODEL_AC97; type = VIR_DOMAIN_SOUND_MODEL_AC97;
} else if (STRPREFIX(start, "hda")) {
type = VIR_DOMAIN_SOUND_MODEL_ICH6;
} }
if (type != -1) { if (type != -1) {

View File

@ -1 +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 -soundhw pcspk -device ES1370,id=sound1,bus=pci.0,addr=0x2 -device sb16,id=sound2 -device AC97,id=sound3,bus=pci.0,addr=0x3 -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x4 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 -soundhw pcspk -device ES1370,id=sound1,bus=pci.0,addr=0x2 -device sb16,id=sound2 -device AC97,id=sound3,bus=pci.0,addr=0x3 -device intel-hda,id=sound4,bus=pci.0,addr=0x4 -device hda-duplex,id=sound4-codec0,bus=sound4.0,cad=0 -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x5

View File

@ -22,6 +22,7 @@
<sound model='es1370'/> <sound model='es1370'/>
<sound model='sb16'/> <sound model='sb16'/>
<sound model='ac97'/> <sound model='ac97'/>
<sound model='ich6'/>
<memballoon model='virtio'/> <memballoon model='virtio'/>
</devices> </devices>
</domain> </domain>

View File

@ -418,7 +418,7 @@ mymain(int argc, char **argv)
QEMUD_CMD_FLAG_NODEFCONFIG, false); QEMUD_CMD_FLAG_NODEFCONFIG, false);
DO_TEST("sound", 0, false); DO_TEST("sound", 0, false);
DO_TEST("sound-device", QEMUD_CMD_FLAG_DEVICE | DO_TEST("sound-device", QEMUD_CMD_FLAG_DEVICE |
QEMUD_CMD_FLAG_NODEFCONFIG, false); QEMUD_CMD_FLAG_NODEFCONFIG | QEMUD_CMD_FLAG_HDA_DUPLEX, false);
DO_TEST("fs9p", QEMUD_CMD_FLAG_DEVICE | DO_TEST("fs9p", QEMUD_CMD_FLAG_DEVICE |
QEMUD_CMD_FLAG_NODEFCONFIG | QEMUD_CMD_FLAG_FSDEV, false); QEMUD_CMD_FLAG_NODEFCONFIG | QEMUD_CMD_FLAG_FSDEV, false);