mirror of
https://github.com/qemu/qemu.git
synced 2024-11-25 03:43:37 +08:00
hda: do not mix output and input stream states, RHBZ #740493
Windows 7 may use the same stream number for input and output. Current code will confuse streams. Changes since v1: - keep running_compat[] for migration version 1 - add running_real[] for migration version 2 Signed-off-by: Marc-Andr? Lureau <marcandre.lureau@redhat.com> Signed-off-by: malc <av1474@comtv.ru>
This commit is contained in:
parent
36ac4ad3d0
commit
ba43d28916
@ -466,7 +466,8 @@ struct HDAAudioState {
|
||||
QEMUSoundCard card;
|
||||
const desc_codec *desc;
|
||||
HDAAudioStream st[4];
|
||||
bool running[16];
|
||||
bool running_compat[16];
|
||||
bool running_real[2 * 16];
|
||||
|
||||
/* properties */
|
||||
uint32_t debug;
|
||||
@ -663,7 +664,7 @@ static void hda_audio_command(HDACodecDevice *hda, uint32_t nid, uint32_t data)
|
||||
st->channel = payload & 0x0f;
|
||||
dprint(a, 2, "%s: stream %d, channel %d\n",
|
||||
st->node->name, st->stream, st->channel);
|
||||
hda_audio_set_running(st, a->running[st->stream]);
|
||||
hda_audio_set_running(st, a->running_real[st->output * 16 + st->stream]);
|
||||
hda_codec_response(hda, true, 0);
|
||||
break;
|
||||
case AC_VERB_GET_CONV:
|
||||
@ -746,16 +747,20 @@ fail:
|
||||
hda_codec_response(hda, true, 0);
|
||||
}
|
||||
|
||||
static void hda_audio_stream(HDACodecDevice *hda, uint32_t stnr, bool running)
|
||||
static void hda_audio_stream(HDACodecDevice *hda, uint32_t stnr, bool running, bool output)
|
||||
{
|
||||
HDAAudioState *a = DO_UPCAST(HDAAudioState, hda, hda);
|
||||
int s;
|
||||
|
||||
a->running[stnr] = running;
|
||||
a->running_compat[stnr] = running;
|
||||
a->running_real[output * 16 + stnr] = running;
|
||||
for (s = 0; s < ARRAY_SIZE(a->st); s++) {
|
||||
if (a->st[s].node == NULL) {
|
||||
continue;
|
||||
}
|
||||
if (a->st[s].output != output) {
|
||||
continue;
|
||||
}
|
||||
if (a->st[s].stream != stnr) {
|
||||
continue;
|
||||
}
|
||||
@ -837,6 +842,12 @@ static int hda_audio_post_load(void *opaque, int version)
|
||||
int i;
|
||||
|
||||
dprint(a, 1, "%s\n", __FUNCTION__);
|
||||
if (version == 1) {
|
||||
/* assume running_compat[] is for output streams */
|
||||
for (i = 0; i < ARRAY_SIZE(a->running_compat); i++)
|
||||
a->running_real[16 + i] = a->running_compat[i];
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(a->st); i++) {
|
||||
st = a->st + i;
|
||||
if (st->node == NULL)
|
||||
@ -844,7 +855,7 @@ static int hda_audio_post_load(void *opaque, int version)
|
||||
hda_codec_parse_fmt(st->format, &st->as);
|
||||
hda_audio_setup(st);
|
||||
hda_audio_set_amp(st);
|
||||
hda_audio_set_running(st, a->running[st->stream]);
|
||||
hda_audio_set_running(st, a->running_real[st->output * 16 + st->stream]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -868,13 +879,14 @@ static const VMStateDescription vmstate_hda_audio_stream = {
|
||||
|
||||
static const VMStateDescription vmstate_hda_audio = {
|
||||
.name = "hda-audio",
|
||||
.version_id = 1,
|
||||
.version_id = 2,
|
||||
.post_load = hda_audio_post_load,
|
||||
.fields = (VMStateField []) {
|
||||
VMSTATE_STRUCT_ARRAY(st, HDAAudioState, 4, 0,
|
||||
vmstate_hda_audio_stream,
|
||||
HDAAudioStream),
|
||||
VMSTATE_BOOL_ARRAY(running, HDAAudioState, 16),
|
||||
VMSTATE_BOOL_ARRAY(running_compat, HDAAudioState, 16),
|
||||
VMSTATE_BOOL_ARRAY_V(running_real, HDAAudioState, 2 * 16, 2),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
@ -485,7 +485,7 @@ static void intel_hda_parse_bdl(IntelHDAState *d, IntelHDAStream *st)
|
||||
st->bp = 0;
|
||||
}
|
||||
|
||||
static void intel_hda_notify_codecs(IntelHDAState *d, uint32_t stream, bool running)
|
||||
static void intel_hda_notify_codecs(IntelHDAState *d, uint32_t stream, bool running, bool output)
|
||||
{
|
||||
DeviceState *qdev;
|
||||
HDACodecDevice *cdev;
|
||||
@ -493,7 +493,7 @@ static void intel_hda_notify_codecs(IntelHDAState *d, uint32_t stream, bool runn
|
||||
QLIST_FOREACH(qdev, &d->codecs.qbus.children, sibling) {
|
||||
cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
|
||||
if (cdev->info->stream) {
|
||||
cdev->info->stream(cdev, stream, running);
|
||||
cdev->info->stream(cdev, stream, running, output);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -567,6 +567,7 @@ static void intel_hda_set_ics(IntelHDAState *d, const IntelHDAReg *reg, uint32_t
|
||||
|
||||
static void intel_hda_set_st_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
|
||||
{
|
||||
bool output = reg->stream >= 4;
|
||||
IntelHDAStream *st = d->st + reg->stream;
|
||||
|
||||
if (st->ctl & 0x01) {
|
||||
@ -582,11 +583,11 @@ static void intel_hda_set_st_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint3
|
||||
dprint(d, 1, "st #%d: start %d (ring buf %d bytes)\n",
|
||||
reg->stream, stnr, st->cbl);
|
||||
intel_hda_parse_bdl(d, st);
|
||||
intel_hda_notify_codecs(d, stnr, true);
|
||||
intel_hda_notify_codecs(d, stnr, true, output);
|
||||
} else {
|
||||
/* stop */
|
||||
dprint(d, 1, "st #%d: stop %d\n", reg->stream, stnr);
|
||||
intel_hda_notify_codecs(d, stnr, false);
|
||||
intel_hda_notify_codecs(d, stnr, false, output);
|
||||
}
|
||||
}
|
||||
intel_hda_update_irq(d);
|
||||
|
@ -34,7 +34,7 @@ struct HDACodecDeviceInfo {
|
||||
int (*init)(HDACodecDevice *dev);
|
||||
int (*exit)(HDACodecDevice *dev);
|
||||
void (*command)(HDACodecDevice *dev, uint32_t nid, uint32_t data);
|
||||
void (*stream)(HDACodecDevice *dev, uint32_t stnr, bool running);
|
||||
void (*stream)(HDACodecDevice *dev, uint32_t stnr, bool running, bool output);
|
||||
};
|
||||
|
||||
void hda_codec_bus_init(DeviceState *dev, HDACodecBus *bus,
|
||||
|
Loading…
Reference in New Issue
Block a user