Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging
[qemu.git] / hw / audio / hda-codec.c
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 int 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 return 0;
543 }
544
545 static int hda_audio_post_load(void *opaque, int version)
546 {
547 HDAAudioState *a = opaque;
548 HDAAudioStream *st;
549 int i;
550
551 dprint(a, 1, "%s\n", __FUNCTION__);
552 if (version == 1) {
553 /* assume running_compat[] is for output streams */
554 for (i = 0; i < ARRAY_SIZE(a->running_compat); i++)
555 a->running_real[16 + i] = a->running_compat[i];
556 }
557
558 for (i = 0; i < ARRAY_SIZE(a->st); i++) {
559 st = a->st + i;
560 if (st->node == NULL)
561 continue;
562 hda_codec_parse_fmt(st->format, &st->as);
563 hda_audio_setup(st);
564 hda_audio_set_amp(st);
565 hda_audio_set_running(st, a->running_real[st->output * 16 + st->stream]);
566 }
567 return 0;
568 }
569
570 static void hda_audio_reset(DeviceState *dev)
571 {
572 HDAAudioState *a = HDA_AUDIO(dev);
573 HDAAudioStream *st;
574 int i;
575
576 dprint(a, 1, "%s\n", __func__);
577 for (i = 0; i < ARRAY_SIZE(a->st); i++) {
578 st = a->st + i;
579 if (st->node != NULL) {
580 hda_audio_set_running(st, false);
581 }
582 }
583 }
584
585 static const VMStateDescription vmstate_hda_audio_stream = {
586 .name = "hda-audio-stream",
587 .version_id = 1,
588 .fields = (VMStateField[]) {
589 VMSTATE_UINT32(stream, HDAAudioStream),
590 VMSTATE_UINT32(channel, HDAAudioStream),
591 VMSTATE_UINT32(format, HDAAudioStream),
592 VMSTATE_UINT32(gain_left, HDAAudioStream),
593 VMSTATE_UINT32(gain_right, HDAAudioStream),
594 VMSTATE_BOOL(mute_left, HDAAudioStream),
595 VMSTATE_BOOL(mute_right, HDAAudioStream),
596 VMSTATE_UINT32(bpos, HDAAudioStream),
597 VMSTATE_BUFFER(buf, HDAAudioStream),
598 VMSTATE_END_OF_LIST()
599 }
600 };
601
602 static const VMStateDescription vmstate_hda_audio = {
603 .name = "hda-audio",
604 .version_id = 2,
605 .post_load = hda_audio_post_load,
606 .fields = (VMStateField[]) {
607 VMSTATE_STRUCT_ARRAY(st, HDAAudioState, 4, 0,
608 vmstate_hda_audio_stream,
609 HDAAudioStream),
610 VMSTATE_BOOL_ARRAY(running_compat, HDAAudioState, 16),
611 VMSTATE_BOOL_ARRAY_V(running_real, HDAAudioState, 2 * 16, 2),
612 VMSTATE_END_OF_LIST()
613 }
614 };
615
616 static Property hda_audio_properties[] = {
617 DEFINE_PROP_UINT32("debug", HDAAudioState, debug, 0),
618 DEFINE_PROP_BOOL("mixer", HDAAudioState, mixer, true),
619 DEFINE_PROP_END_OF_LIST(),
620 };
621
622 static int hda_audio_init_output(HDACodecDevice *hda)
623 {
624 HDAAudioState *a = HDA_AUDIO(hda);
625
626 if (!a->mixer) {
627 return hda_audio_init(hda, &output_nomixemu);
628 } else {
629 return hda_audio_init(hda, &output_mixemu);
630 }
631 }
632
633 static int hda_audio_init_duplex(HDACodecDevice *hda)
634 {
635 HDAAudioState *a = HDA_AUDIO(hda);
636
637 if (!a->mixer) {
638 return hda_audio_init(hda, &duplex_nomixemu);
639 } else {
640 return hda_audio_init(hda, &duplex_mixemu);
641 }
642 }
643
644 static int hda_audio_init_micro(HDACodecDevice *hda)
645 {
646 HDAAudioState *a = HDA_AUDIO(hda);
647
648 if (!a->mixer) {
649 return hda_audio_init(hda, &micro_nomixemu);
650 } else {
651 return hda_audio_init(hda, &micro_mixemu);
652 }
653 }
654
655 static void hda_audio_base_class_init(ObjectClass *klass, void *data)
656 {
657 DeviceClass *dc = DEVICE_CLASS(klass);
658 HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass);
659
660 k->exit = hda_audio_exit;
661 k->command = hda_audio_command;
662 k->stream = hda_audio_stream;
663 set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
664 dc->reset = hda_audio_reset;
665 dc->vmsd = &vmstate_hda_audio;
666 dc->props = hda_audio_properties;
667 }
668
669 static const TypeInfo hda_audio_info = {
670 .name = TYPE_HDA_AUDIO,
671 .parent = TYPE_HDA_CODEC_DEVICE,
672 .class_init = hda_audio_base_class_init,
673 .abstract = true,
674 };
675
676 static void hda_audio_output_class_init(ObjectClass *klass, void *data)
677 {
678 DeviceClass *dc = DEVICE_CLASS(klass);
679 HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass);
680
681 k->init = hda_audio_init_output;
682 dc->desc = "HDA Audio Codec, output-only (line-out)";
683 }
684
685 static const TypeInfo hda_audio_output_info = {
686 .name = "hda-output",
687 .parent = TYPE_HDA_AUDIO,
688 .instance_size = sizeof(HDAAudioState),
689 .class_init = hda_audio_output_class_init,
690 };
691
692 static void hda_audio_duplex_class_init(ObjectClass *klass, void *data)
693 {
694 DeviceClass *dc = DEVICE_CLASS(klass);
695 HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass);
696
697 k->init = hda_audio_init_duplex;
698 dc->desc = "HDA Audio Codec, duplex (line-out, line-in)";
699 }
700
701 static const TypeInfo hda_audio_duplex_info = {
702 .name = "hda-duplex",
703 .parent = TYPE_HDA_AUDIO,
704 .instance_size = sizeof(HDAAudioState),
705 .class_init = hda_audio_duplex_class_init,
706 };
707
708 static void hda_audio_micro_class_init(ObjectClass *klass, void *data)
709 {
710 DeviceClass *dc = DEVICE_CLASS(klass);
711 HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass);
712
713 k->init = hda_audio_init_micro;
714 dc->desc = "HDA Audio Codec, duplex (speaker, microphone)";
715 }
716
717 static const TypeInfo hda_audio_micro_info = {
718 .name = "hda-micro",
719 .parent = TYPE_HDA_AUDIO,
720 .instance_size = sizeof(HDAAudioState),
721 .class_init = hda_audio_micro_class_init,
722 };
723
724 static void hda_audio_register_types(void)
725 {
726 type_register_static(&hda_audio_info);
727 type_register_static(&hda_audio_output_info);
728 type_register_static(&hda_audio_duplex_info);
729 type_register_static(&hda_audio_micro_info);
730 }
731
732 type_init(hda_audio_register_types)