xref: /openbmc/qemu/hw/audio/hda-codec.c (revision d49805ae)
1 /*
2  * Copyright (C) 2010 Red Hat, Inc.
3  *
4  * written by Gerd Hoffmann <kraxel@redhat.com>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 or
9  * (at your option) version 3 of the License.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include "hw/hw.h"
21 #include "hw/pci/pci.h"
22 #include "intel-hda.h"
23 #include "intel-hda-defs.h"
24 #include "audio/audio.h"
25 
26 /* -------------------------------------------------------------------------- */
27 
28 typedef struct desc_param {
29     uint32_t id;
30     uint32_t val;
31 } desc_param;
32 
33 typedef struct desc_node {
34     uint32_t nid;
35     const char *name;
36     const desc_param *params;
37     uint32_t nparams;
38     uint32_t config;
39     uint32_t pinctl;
40     uint32_t *conn;
41     uint32_t stindex;
42 } desc_node;
43 
44 typedef struct desc_codec {
45     const char *name;
46     uint32_t iid;
47     const desc_node *nodes;
48     uint32_t nnodes;
49 } desc_codec;
50 
51 static const desc_param* hda_codec_find_param(const desc_node *node, uint32_t id)
52 {
53     int i;
54 
55     for (i = 0; i < node->nparams; i++) {
56         if (node->params[i].id == id) {
57             return &node->params[i];
58         }
59     }
60     return NULL;
61 }
62 
63 static const desc_node* hda_codec_find_node(const desc_codec *codec, uint32_t nid)
64 {
65     int i;
66 
67     for (i = 0; i < codec->nnodes; i++) {
68         if (codec->nodes[i].nid == nid) {
69             return &codec->nodes[i];
70         }
71     }
72     return NULL;
73 }
74 
75 static void hda_codec_parse_fmt(uint32_t format, struct audsettings *as)
76 {
77     if (format & AC_FMT_TYPE_NON_PCM) {
78         return;
79     }
80 
81     as->freq = (format & AC_FMT_BASE_44K) ? 44100 : 48000;
82 
83     switch ((format & AC_FMT_MULT_MASK) >> AC_FMT_MULT_SHIFT) {
84     case 1: as->freq *= 2; break;
85     case 2: as->freq *= 3; break;
86     case 3: as->freq *= 4; break;
87     }
88 
89     switch ((format & AC_FMT_DIV_MASK) >> AC_FMT_DIV_SHIFT) {
90     case 1: as->freq /= 2; break;
91     case 2: as->freq /= 3; break;
92     case 3: as->freq /= 4; break;
93     case 4: as->freq /= 5; break;
94     case 5: as->freq /= 6; break;
95     case 6: as->freq /= 7; break;
96     case 7: as->freq /= 8; break;
97     }
98 
99     switch (format & AC_FMT_BITS_MASK) {
100     case AC_FMT_BITS_8:  as->fmt = AUD_FMT_S8;  break;
101     case AC_FMT_BITS_16: as->fmt = AUD_FMT_S16; break;
102     case AC_FMT_BITS_32: as->fmt = AUD_FMT_S32; break;
103     }
104 
105     as->nchannels = ((format & AC_FMT_CHAN_MASK) >> AC_FMT_CHAN_SHIFT) + 1;
106 }
107 
108 /* -------------------------------------------------------------------------- */
109 /*
110  * HDA codec descriptions
111  */
112 
113 /* some defines */
114 
115 #define QEMU_HDA_ID_VENDOR  0x1af4
116 #define QEMU_HDA_PCM_FORMATS (AC_SUPPCM_BITS_16 |       \
117                               0x1fc /* 16 -> 96 kHz */)
118 #define QEMU_HDA_AMP_NONE    (0)
119 #define QEMU_HDA_AMP_STEPS   0x4a
120 
121 #define   PARAM mixemu
122 #define   HDA_MIXER
123 #include "hda-codec-common.h"
124 
125 #define   PARAM nomixemu
126 #include  "hda-codec-common.h"
127 
128 /* -------------------------------------------------------------------------- */
129 
130 static const char *fmt2name[] = {
131     [ AUD_FMT_U8  ] = "PCM-U8",
132     [ AUD_FMT_S8  ] = "PCM-S8",
133     [ AUD_FMT_U16 ] = "PCM-U16",
134     [ AUD_FMT_S16 ] = "PCM-S16",
135     [ AUD_FMT_U32 ] = "PCM-U32",
136     [ AUD_FMT_S32 ] = "PCM-S32",
137 };
138 
139 typedef struct HDAAudioState HDAAudioState;
140 typedef struct HDAAudioStream HDAAudioStream;
141 
142 struct HDAAudioStream {
143     HDAAudioState *state;
144     const desc_node *node;
145     bool output, running;
146     uint32_t stream;
147     uint32_t channel;
148     uint32_t format;
149     uint32_t gain_left, gain_right;
150     bool mute_left, mute_right;
151     struct audsettings as;
152     union {
153         SWVoiceIn *in;
154         SWVoiceOut *out;
155     } voice;
156     uint8_t buf[HDA_BUFFER_SIZE];
157     uint32_t bpos;
158 };
159 
160 #define TYPE_HDA_AUDIO "hda-audio"
161 #define HDA_AUDIO(obj) OBJECT_CHECK(HDAAudioState, (obj), TYPE_HDA_AUDIO)
162 
163 struct HDAAudioState {
164     HDACodecDevice hda;
165     const char *name;
166 
167     QEMUSoundCard card;
168     const desc_codec *desc;
169     HDAAudioStream st[4];
170     bool running_compat[16];
171     bool running_real[2 * 16];
172 
173     /* properties */
174     uint32_t debug;
175     bool     mixer;
176 };
177 
178 static void hda_audio_input_cb(void *opaque, int avail)
179 {
180     HDAAudioStream *st = opaque;
181     int recv = 0;
182     int len;
183     bool rc;
184 
185     while (avail - recv >= sizeof(st->buf)) {
186         if (st->bpos != sizeof(st->buf)) {
187             len = AUD_read(st->voice.in, st->buf + st->bpos,
188                            sizeof(st->buf) - st->bpos);
189             st->bpos += len;
190             recv += len;
191             if (st->bpos != sizeof(st->buf)) {
192                 break;
193             }
194         }
195         rc = hda_codec_xfer(&st->state->hda, st->stream, false,
196                             st->buf, sizeof(st->buf));
197         if (!rc) {
198             break;
199         }
200         st->bpos = 0;
201     }
202 }
203 
204 static void hda_audio_output_cb(void *opaque, int avail)
205 {
206     HDAAudioStream *st = opaque;
207     int sent = 0;
208     int len;
209     bool rc;
210 
211     while (avail - sent >= sizeof(st->buf)) {
212         if (st->bpos == sizeof(st->buf)) {
213             rc = hda_codec_xfer(&st->state->hda, st->stream, true,
214                                 st->buf, sizeof(st->buf));
215             if (!rc) {
216                 break;
217             }
218             st->bpos = 0;
219         }
220         len = AUD_write(st->voice.out, st->buf + st->bpos,
221                         sizeof(st->buf) - st->bpos);
222         st->bpos += len;
223         sent += len;
224         if (st->bpos != sizeof(st->buf)) {
225             break;
226         }
227     }
228 }
229 
230 static void hda_audio_set_running(HDAAudioStream *st, bool running)
231 {
232     if (st->node == NULL) {
233         return;
234     }
235     if (st->running == running) {
236         return;
237     }
238     st->running = running;
239     dprint(st->state, 1, "%s: %s (stream %d)\n", st->node->name,
240            st->running ? "on" : "off", st->stream);
241     if (st->output) {
242         AUD_set_active_out(st->voice.out, st->running);
243     } else {
244         AUD_set_active_in(st->voice.in, st->running);
245     }
246 }
247 
248 static void hda_audio_set_amp(HDAAudioStream *st)
249 {
250     bool muted;
251     uint32_t left, right;
252 
253     if (st->node == NULL) {
254         return;
255     }
256 
257     muted = st->mute_left && st->mute_right;
258     left  = st->mute_left  ? 0 : st->gain_left;
259     right = st->mute_right ? 0 : st->gain_right;
260 
261     left = left * 255 / QEMU_HDA_AMP_STEPS;
262     right = right * 255 / QEMU_HDA_AMP_STEPS;
263 
264     if (!st->state->mixer) {
265         return;
266     }
267     if (st->output) {
268         AUD_set_volume_out(st->voice.out, muted, left, right);
269     } else {
270         AUD_set_volume_in(st->voice.in, muted, left, right);
271     }
272 }
273 
274 static void hda_audio_setup(HDAAudioStream *st)
275 {
276     if (st->node == NULL) {
277         return;
278     }
279 
280     dprint(st->state, 1, "%s: format: %d x %s @ %d Hz\n",
281            st->node->name, st->as.nchannels,
282            fmt2name[st->as.fmt], st->as.freq);
283 
284     if (st->output) {
285         st->voice.out = AUD_open_out(&st->state->card, st->voice.out,
286                                      st->node->name, st,
287                                      hda_audio_output_cb, &st->as);
288     } else {
289         st->voice.in = AUD_open_in(&st->state->card, st->voice.in,
290                                    st->node->name, st,
291                                    hda_audio_input_cb, &st->as);
292     }
293 }
294 
295 static void hda_audio_command(HDACodecDevice *hda, uint32_t nid, uint32_t data)
296 {
297     HDAAudioState *a = HDA_AUDIO(hda);
298     HDAAudioStream *st;
299     const desc_node *node = NULL;
300     const desc_param *param;
301     uint32_t verb, payload, response, count, shift;
302 
303     if ((data & 0x70000) == 0x70000) {
304         /* 12/8 id/payload */
305         verb = (data >> 8) & 0xfff;
306         payload = data & 0x00ff;
307     } else {
308         /* 4/16 id/payload */
309         verb = (data >> 8) & 0xf00;
310         payload = data & 0xffff;
311     }
312 
313     node = hda_codec_find_node(a->desc, nid);
314     if (node == NULL) {
315         goto fail;
316     }
317     dprint(a, 2, "%s: nid %d (%s), verb 0x%x, payload 0x%x\n",
318            __FUNCTION__, nid, node->name, verb, payload);
319 
320     switch (verb) {
321     /* all nodes */
322     case AC_VERB_PARAMETERS:
323         param = hda_codec_find_param(node, payload);
324         if (param == NULL) {
325             goto fail;
326         }
327         hda_codec_response(hda, true, param->val);
328         break;
329     case AC_VERB_GET_SUBSYSTEM_ID:
330         hda_codec_response(hda, true, a->desc->iid);
331         break;
332 
333     /* all functions */
334     case AC_VERB_GET_CONNECT_LIST:
335         param = hda_codec_find_param(node, AC_PAR_CONNLIST_LEN);
336         count = param ? param->val : 0;
337         response = 0;
338         shift = 0;
339         while (payload < count && shift < 32) {
340             response |= node->conn[payload] << shift;
341             payload++;
342             shift += 8;
343         }
344         hda_codec_response(hda, true, response);
345         break;
346 
347     /* pin widget */
348     case AC_VERB_GET_CONFIG_DEFAULT:
349         hda_codec_response(hda, true, node->config);
350         break;
351     case AC_VERB_GET_PIN_WIDGET_CONTROL:
352         hda_codec_response(hda, true, node->pinctl);
353         break;
354     case AC_VERB_SET_PIN_WIDGET_CONTROL:
355         if (node->pinctl != payload) {
356             dprint(a, 1, "unhandled pin control bit\n");
357         }
358         hda_codec_response(hda, true, 0);
359         break;
360 
361     /* audio in/out widget */
362     case AC_VERB_SET_CHANNEL_STREAMID:
363         st = a->st + node->stindex;
364         if (st->node == NULL) {
365             goto fail;
366         }
367         hda_audio_set_running(st, false);
368         st->stream = (payload >> 4) & 0x0f;
369         st->channel = payload & 0x0f;
370         dprint(a, 2, "%s: stream %d, channel %d\n",
371                st->node->name, st->stream, st->channel);
372         hda_audio_set_running(st, a->running_real[st->output * 16 + st->stream]);
373         hda_codec_response(hda, true, 0);
374         break;
375     case AC_VERB_GET_CONV:
376         st = a->st + node->stindex;
377         if (st->node == NULL) {
378             goto fail;
379         }
380         response = st->stream << 4 | st->channel;
381         hda_codec_response(hda, true, response);
382         break;
383     case AC_VERB_SET_STREAM_FORMAT:
384         st = a->st + node->stindex;
385         if (st->node == NULL) {
386             goto fail;
387         }
388         st->format = payload;
389         hda_codec_parse_fmt(st->format, &st->as);
390         hda_audio_setup(st);
391         hda_codec_response(hda, true, 0);
392         break;
393     case AC_VERB_GET_STREAM_FORMAT:
394         st = a->st + node->stindex;
395         if (st->node == NULL) {
396             goto fail;
397         }
398         hda_codec_response(hda, true, st->format);
399         break;
400     case AC_VERB_GET_AMP_GAIN_MUTE:
401         st = a->st + node->stindex;
402         if (st->node == NULL) {
403             goto fail;
404         }
405         if (payload & AC_AMP_GET_LEFT) {
406             response = st->gain_left | (st->mute_left ? AC_AMP_MUTE : 0);
407         } else {
408             response = st->gain_right | (st->mute_right ? AC_AMP_MUTE : 0);
409         }
410         hda_codec_response(hda, true, response);
411         break;
412     case AC_VERB_SET_AMP_GAIN_MUTE:
413         st = a->st + node->stindex;
414         if (st->node == NULL) {
415             goto fail;
416         }
417         dprint(a, 1, "amp (%s): %s%s%s%s index %d  gain %3d %s\n",
418                st->node->name,
419                (payload & AC_AMP_SET_OUTPUT) ? "o" : "-",
420                (payload & AC_AMP_SET_INPUT)  ? "i" : "-",
421                (payload & AC_AMP_SET_LEFT)   ? "l" : "-",
422                (payload & AC_AMP_SET_RIGHT)  ? "r" : "-",
423                (payload & AC_AMP_SET_INDEX) >> AC_AMP_SET_INDEX_SHIFT,
424                (payload & AC_AMP_GAIN),
425                (payload & AC_AMP_MUTE) ? "muted" : "");
426         if (payload & AC_AMP_SET_LEFT) {
427             st->gain_left = payload & AC_AMP_GAIN;
428             st->mute_left = payload & AC_AMP_MUTE;
429         }
430         if (payload & AC_AMP_SET_RIGHT) {
431             st->gain_right = payload & AC_AMP_GAIN;
432             st->mute_right = payload & AC_AMP_MUTE;
433         }
434         hda_audio_set_amp(st);
435         hda_codec_response(hda, true, 0);
436         break;
437 
438     /* not supported */
439     case AC_VERB_SET_POWER_STATE:
440     case AC_VERB_GET_POWER_STATE:
441     case AC_VERB_GET_SDI_SELECT:
442         hda_codec_response(hda, true, 0);
443         break;
444     default:
445         goto fail;
446     }
447     return;
448 
449 fail:
450     dprint(a, 1, "%s: not handled: nid %d (%s), verb 0x%x, payload 0x%x\n",
451            __FUNCTION__, nid, node ? node->name : "?", verb, payload);
452     hda_codec_response(hda, true, 0);
453 }
454 
455 static void hda_audio_stream(HDACodecDevice *hda, uint32_t stnr, bool running, bool output)
456 {
457     HDAAudioState *a = HDA_AUDIO(hda);
458     int s;
459 
460     a->running_compat[stnr] = running;
461     a->running_real[output * 16 + stnr] = running;
462     for (s = 0; s < ARRAY_SIZE(a->st); s++) {
463         if (a->st[s].node == NULL) {
464             continue;
465         }
466         if (a->st[s].output != output) {
467             continue;
468         }
469         if (a->st[s].stream != stnr) {
470             continue;
471         }
472         hda_audio_set_running(&a->st[s], running);
473     }
474 }
475 
476 static int hda_audio_init(HDACodecDevice *hda, const struct desc_codec *desc)
477 {
478     HDAAudioState *a = HDA_AUDIO(hda);
479     HDAAudioStream *st;
480     const desc_node *node;
481     const desc_param *param;
482     uint32_t i, type;
483 
484     a->desc = desc;
485     a->name = object_get_typename(OBJECT(a));
486     dprint(a, 1, "%s: cad %d\n", __FUNCTION__, a->hda.cad);
487 
488     AUD_register_card("hda", &a->card);
489     for (i = 0; i < a->desc->nnodes; i++) {
490         node = a->desc->nodes + i;
491         param = hda_codec_find_param(node, AC_PAR_AUDIO_WIDGET_CAP);
492         if (NULL == param)
493             continue;
494         type = (param->val & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
495         switch (type) {
496         case AC_WID_AUD_OUT:
497         case AC_WID_AUD_IN:
498             assert(node->stindex < ARRAY_SIZE(a->st));
499             st = a->st + node->stindex;
500             st->state = a;
501             st->node = node;
502             if (type == AC_WID_AUD_OUT) {
503                 /* unmute output by default */
504                 st->gain_left = QEMU_HDA_AMP_STEPS;
505                 st->gain_right = QEMU_HDA_AMP_STEPS;
506                 st->bpos = sizeof(st->buf);
507                 st->output = true;
508             } else {
509                 st->output = false;
510             }
511             st->format = AC_FMT_TYPE_PCM | AC_FMT_BITS_16 |
512                 (1 << AC_FMT_CHAN_SHIFT);
513             hda_codec_parse_fmt(st->format, &st->as);
514             hda_audio_setup(st);
515             break;
516         }
517     }
518     return 0;
519 }
520 
521 static int hda_audio_exit(HDACodecDevice *hda)
522 {
523     HDAAudioState *a = HDA_AUDIO(hda);
524     HDAAudioStream *st;
525     int i;
526 
527     dprint(a, 1, "%s\n", __FUNCTION__);
528     for (i = 0; i < ARRAY_SIZE(a->st); i++) {
529         st = a->st + i;
530         if (st->node == NULL) {
531             continue;
532         }
533         if (st->output) {
534             AUD_close_out(&a->card, st->voice.out);
535         } else {
536             AUD_close_in(&a->card, st->voice.in);
537         }
538     }
539     AUD_remove_card(&a->card);
540     return 0;
541 }
542 
543 static int hda_audio_post_load(void *opaque, int version)
544 {
545     HDAAudioState *a = opaque;
546     HDAAudioStream *st;
547     int i;
548 
549     dprint(a, 1, "%s\n", __FUNCTION__);
550     if (version == 1) {
551         /* assume running_compat[] is for output streams */
552         for (i = 0; i < ARRAY_SIZE(a->running_compat); i++)
553             a->running_real[16 + i] = a->running_compat[i];
554     }
555 
556     for (i = 0; i < ARRAY_SIZE(a->st); i++) {
557         st = a->st + i;
558         if (st->node == NULL)
559             continue;
560         hda_codec_parse_fmt(st->format, &st->as);
561         hda_audio_setup(st);
562         hda_audio_set_amp(st);
563         hda_audio_set_running(st, a->running_real[st->output * 16 + st->stream]);
564     }
565     return 0;
566 }
567 
568 static void hda_audio_reset(DeviceState *dev)
569 {
570     HDAAudioState *a = HDA_AUDIO(dev);
571     HDAAudioStream *st;
572     int i;
573 
574     dprint(a, 1, "%s\n", __func__);
575     for (i = 0; i < ARRAY_SIZE(a->st); i++) {
576         st = a->st + i;
577         if (st->node != NULL) {
578             hda_audio_set_running(st, false);
579         }
580     }
581 }
582 
583 static const VMStateDescription vmstate_hda_audio_stream = {
584     .name = "hda-audio-stream",
585     .version_id = 1,
586     .fields = (VMStateField[]) {
587         VMSTATE_UINT32(stream, HDAAudioStream),
588         VMSTATE_UINT32(channel, HDAAudioStream),
589         VMSTATE_UINT32(format, HDAAudioStream),
590         VMSTATE_UINT32(gain_left, HDAAudioStream),
591         VMSTATE_UINT32(gain_right, HDAAudioStream),
592         VMSTATE_BOOL(mute_left, HDAAudioStream),
593         VMSTATE_BOOL(mute_right, HDAAudioStream),
594         VMSTATE_UINT32(bpos, HDAAudioStream),
595         VMSTATE_BUFFER(buf, HDAAudioStream),
596         VMSTATE_END_OF_LIST()
597     }
598 };
599 
600 static const VMStateDescription vmstate_hda_audio = {
601     .name = "hda-audio",
602     .version_id = 2,
603     .post_load = hda_audio_post_load,
604     .fields = (VMStateField[]) {
605         VMSTATE_STRUCT_ARRAY(st, HDAAudioState, 4, 0,
606                              vmstate_hda_audio_stream,
607                              HDAAudioStream),
608         VMSTATE_BOOL_ARRAY(running_compat, HDAAudioState, 16),
609         VMSTATE_BOOL_ARRAY_V(running_real, HDAAudioState, 2 * 16, 2),
610         VMSTATE_END_OF_LIST()
611     }
612 };
613 
614 static Property hda_audio_properties[] = {
615     DEFINE_PROP_UINT32("debug", HDAAudioState, debug,   0),
616     DEFINE_PROP_BOOL("mixer", HDAAudioState, mixer,  true),
617     DEFINE_PROP_END_OF_LIST(),
618 };
619 
620 static int hda_audio_init_output(HDACodecDevice *hda)
621 {
622     HDAAudioState *a = HDA_AUDIO(hda);
623 
624     if (!a->mixer) {
625         return hda_audio_init(hda, &output_nomixemu);
626     } else {
627         return hda_audio_init(hda, &output_mixemu);
628     }
629 }
630 
631 static int hda_audio_init_duplex(HDACodecDevice *hda)
632 {
633     HDAAudioState *a = HDA_AUDIO(hda);
634 
635     if (!a->mixer) {
636         return hda_audio_init(hda, &duplex_nomixemu);
637     } else {
638         return hda_audio_init(hda, &duplex_mixemu);
639     }
640 }
641 
642 static int hda_audio_init_micro(HDACodecDevice *hda)
643 {
644     HDAAudioState *a = HDA_AUDIO(hda);
645 
646     if (!a->mixer) {
647         return hda_audio_init(hda, &micro_nomixemu);
648     } else {
649         return hda_audio_init(hda, &micro_mixemu);
650     }
651 }
652 
653 static void hda_audio_base_class_init(ObjectClass *klass, void *data)
654 {
655     DeviceClass *dc = DEVICE_CLASS(klass);
656     HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass);
657 
658     k->exit = hda_audio_exit;
659     k->command = hda_audio_command;
660     k->stream = hda_audio_stream;
661     set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
662     dc->reset = hda_audio_reset;
663     dc->vmsd = &vmstate_hda_audio;
664     dc->props = hda_audio_properties;
665 }
666 
667 static const TypeInfo hda_audio_info = {
668     .name          = TYPE_HDA_AUDIO,
669     .parent        = TYPE_HDA_CODEC_DEVICE,
670     .class_init    = hda_audio_base_class_init,
671     .abstract      = true,
672 };
673 
674 static void hda_audio_output_class_init(ObjectClass *klass, void *data)
675 {
676     DeviceClass *dc = DEVICE_CLASS(klass);
677     HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass);
678 
679     k->init = hda_audio_init_output;
680     dc->desc = "HDA Audio Codec, output-only (line-out)";
681 }
682 
683 static const TypeInfo hda_audio_output_info = {
684     .name          = "hda-output",
685     .parent        = TYPE_HDA_AUDIO,
686     .instance_size = sizeof(HDAAudioState),
687     .class_init    = hda_audio_output_class_init,
688 };
689 
690 static void hda_audio_duplex_class_init(ObjectClass *klass, void *data)
691 {
692     DeviceClass *dc = DEVICE_CLASS(klass);
693     HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass);
694 
695     k->init = hda_audio_init_duplex;
696     dc->desc = "HDA Audio Codec, duplex (line-out, line-in)";
697 }
698 
699 static const TypeInfo hda_audio_duplex_info = {
700     .name          = "hda-duplex",
701     .parent        = TYPE_HDA_AUDIO,
702     .instance_size = sizeof(HDAAudioState),
703     .class_init    = hda_audio_duplex_class_init,
704 };
705 
706 static void hda_audio_micro_class_init(ObjectClass *klass, void *data)
707 {
708     DeviceClass *dc = DEVICE_CLASS(klass);
709     HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass);
710 
711     k->init = hda_audio_init_micro;
712     dc->desc = "HDA Audio Codec, duplex (speaker, microphone)";
713 }
714 
715 static const TypeInfo hda_audio_micro_info = {
716     .name          = "hda-micro",
717     .parent        = TYPE_HDA_AUDIO,
718     .instance_size = sizeof(HDAAudioState),
719     .class_init    = hda_audio_micro_class_init,
720 };
721 
722 static void hda_audio_register_types(void)
723 {
724     type_register_static(&hda_audio_info);
725     type_register_static(&hda_audio_output_info);
726     type_register_static(&hda_audio_duplex_info);
727     type_register_static(&hda_audio_micro_info);
728 }
729 
730 type_init(hda_audio_register_types)
731