aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGerd Hoffmann <kraxel@redhat.com>2012-04-26 09:15:03 +0200
committermalc <av1474@comtv.ru>2012-04-26 12:54:17 +0400
commit201100656986735250ed4cd47be6b8a31c771763 (patch)
tree61c1292008d64cfea1c2f3f949b38d1476a15e0d
parentd0c2bbb9f04925eeda9948586aa382ccf68e26e7 (diff)
hda: add hda-micro codec
It's identical to the hda-duplex codec, except that it advertises the input as microphone instead of line-in and the output as speaker instead of line-out. Some guest apps (microsoft netmeeting being one) are picky when it comes to selecting the recording source and don't accept line-in, so give them what they expect. Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> Signed-off-by: malc <av1474@comtv.ru>
-rw-r--r--hw/hda-audio.c143
1 files changed, 141 insertions, 2 deletions
diff --git a/hw/hda-audio.c b/hw/hda-audio.c
index 411be082ac..4e69c3c35c 100644
--- a/hw/hda-audio.c
+++ b/hw/hda-audio.c
@@ -115,6 +115,7 @@ static void hda_codec_parse_fmt(uint32_t format, struct audsettings *as)
#define QEMU_HDA_ID_VENDOR 0x1af4
#define QEMU_HDA_ID_OUTPUT ((QEMU_HDA_ID_VENDOR << 16) | 0x10)
#define QEMU_HDA_ID_DUPLEX ((QEMU_HDA_ID_VENDOR << 16) | 0x20)
+#define QEMU_HDA_ID_MICRO ((QEMU_HDA_ID_VENDOR << 16) | 0x30)
#define QEMU_HDA_PCM_FORMATS (AC_SUPPCM_BITS_16 | \
0x1fc /* 16 -> 96 kHz */)
@@ -427,6 +428,117 @@ static const desc_codec duplex = {
.nnodes = ARRAY_SIZE(duplex_nodes),
};
+/* micro: root node */
+static const desc_param micro_params_root[] = {
+ {
+ .id = AC_PAR_VENDOR_ID,
+ .val = QEMU_HDA_ID_MICRO,
+ },{
+ .id = AC_PAR_SUBSYSTEM_ID,
+ .val = QEMU_HDA_ID_MICRO,
+ },{
+ .id = AC_PAR_REV_ID,
+ .val = 0x00100101,
+ },{
+ .id = AC_PAR_NODE_COUNT,
+ .val = 0x00010001,
+ },
+};
+
+/* micro: audio function */
+static const desc_param micro_params_audio_func[] = {
+ {
+ .id = AC_PAR_FUNCTION_TYPE,
+ .val = AC_GRP_AUDIO_FUNCTION,
+ },{
+ .id = AC_PAR_SUBSYSTEM_ID,
+ .val = QEMU_HDA_ID_MICRO,
+ },{
+ .id = AC_PAR_NODE_COUNT,
+ .val = 0x00020004,
+ },{
+ .id = AC_PAR_PCM,
+ .val = QEMU_HDA_PCM_FORMATS,
+ },{
+ .id = AC_PAR_STREAM,
+ .val = AC_SUPFMT_PCM,
+ },{
+ .id = AC_PAR_AMP_IN_CAP,
+ .val = QEMU_HDA_AMP_NONE,
+ },{
+ .id = AC_PAR_AMP_OUT_CAP,
+ .val = QEMU_HDA_AMP_NONE,
+ },{
+ .id = AC_PAR_GPIO_CAP,
+ .val = 0,
+ },{
+ .id = AC_PAR_AUDIO_FG_CAP,
+ .val = 0x00000808,
+ },{
+ .id = AC_PAR_POWER_STATE,
+ .val = 0,
+ },
+};
+
+/* micro: nodes */
+static const desc_node micro_nodes[] = {
+ {
+ .nid = AC_NODE_ROOT,
+ .name = "root",
+ .params = micro_params_root,
+ .nparams = ARRAY_SIZE(micro_params_root),
+ },{
+ .nid = 1,
+ .name = "func",
+ .params = micro_params_audio_func,
+ .nparams = ARRAY_SIZE(micro_params_audio_func),
+ },{
+ .nid = 2,
+ .name = "dac",
+ .params = common_params_audio_dac,
+ .nparams = ARRAY_SIZE(common_params_audio_dac),
+ .stindex = 0,
+ },{
+ .nid = 3,
+ .name = "out",
+ .params = common_params_audio_lineout,
+ .nparams = ARRAY_SIZE(common_params_audio_lineout),
+ .config = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) |
+ (AC_JACK_SPEAKER << AC_DEFCFG_DEVICE_SHIFT) |
+ (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) |
+ (AC_JACK_COLOR_GREEN << AC_DEFCFG_COLOR_SHIFT) |
+ 0x10),
+ .pinctl = AC_PINCTL_OUT_EN,
+ .conn = (uint32_t[]) { 2 },
+ },{
+ .nid = 4,
+ .name = "adc",
+ .params = common_params_audio_adc,
+ .nparams = ARRAY_SIZE(common_params_audio_adc),
+ .stindex = 1,
+ .conn = (uint32_t[]) { 5 },
+ },{
+ .nid = 5,
+ .name = "in",
+ .params = common_params_audio_linein,
+ .nparams = ARRAY_SIZE(common_params_audio_linein),
+ .config = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) |
+ (AC_JACK_MIC_IN << AC_DEFCFG_DEVICE_SHIFT) |
+ (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) |
+ (AC_JACK_COLOR_RED << AC_DEFCFG_COLOR_SHIFT) |
+ 0x20),
+ .pinctl = AC_PINCTL_IN_EN,
+ }
+};
+
+/* micro: codec */
+static const desc_codec micro = {
+ .name = "micro",
+ .iid = QEMU_HDA_ID_MICRO,
+ .nodes = micro_nodes,
+ .nnodes = ARRAY_SIZE(micro_nodes),
+};
+
/* -------------------------------------------------------------------------- */
static const char *fmt2name[] = {
@@ -906,6 +1018,11 @@ static int hda_audio_init_duplex(HDACodecDevice *hda)
return hda_audio_init(hda, &duplex);
}
+static int hda_audio_init_micro(HDACodecDevice *hda)
+{
+ return hda_audio_init(hda, &micro);
+}
+
static void hda_audio_output_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -915,7 +1032,7 @@ static void hda_audio_output_class_init(ObjectClass *klass, void *data)
k->exit = hda_audio_exit;
k->command = hda_audio_command;
k->stream = hda_audio_stream;
- dc->desc = "HDA Audio Codec, output-only";
+ dc->desc = "HDA Audio Codec, output-only (line-out)";
dc->vmsd = &vmstate_hda_audio;
dc->props = hda_audio_properties;
}
@@ -936,7 +1053,7 @@ static void hda_audio_duplex_class_init(ObjectClass *klass, void *data)
k->exit = hda_audio_exit;
k->command = hda_audio_command;
k->stream = hda_audio_stream;
- dc->desc = "HDA Audio Codec, duplex";
+ dc->desc = "HDA Audio Codec, duplex (line-out, line-in)";
dc->vmsd = &vmstate_hda_audio;
dc->props = hda_audio_properties;
}
@@ -948,10 +1065,32 @@ static TypeInfo hda_audio_duplex_info = {
.class_init = hda_audio_duplex_class_init,
};
+static void hda_audio_micro_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass);
+
+ k->init = hda_audio_init_micro;
+ k->exit = hda_audio_exit;
+ k->command = hda_audio_command;
+ k->stream = hda_audio_stream;
+ dc->desc = "HDA Audio Codec, duplex (speaker, microphone)";
+ dc->vmsd = &vmstate_hda_audio;
+ dc->props = hda_audio_properties;
+}
+
+static TypeInfo hda_audio_micro_info = {
+ .name = "hda-micro",
+ .parent = TYPE_HDA_CODEC_DEVICE,
+ .instance_size = sizeof(HDAAudioState),
+ .class_init = hda_audio_micro_class_init,
+};
+
static void hda_audio_register_types(void)
{
type_register_static(&hda_audio_output_info);
type_register_static(&hda_audio_duplex_info);
+ type_register_static(&hda_audio_micro_info);
}
type_init(hda_audio_register_types)