From 201100656986735250ed4cd47be6b8a31c771763 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 26 Apr 2012 09:15:03 +0200 Subject: 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 Signed-off-by: malc --- hw/hda-audio.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file 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, µ); +} + 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) -- cgit v1.2.3