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