]> git.proxmox.com Git - mirror_qemu.git/blame - hw/audio/hda-codec.c
qga: Make qemu-ga compile statically for Windows
[mirror_qemu.git] / hw / audio / hda-codec.c
CommitLineData
d61a4ce8
GH
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
6086a565 20#include "qemu/osdep.h"
83c9f4ca
PB
21#include "hw/hw.h"
22#include "hw/pci/pci.h"
47b43a1f
PB
23#include "intel-hda.h"
24#include "intel-hda-defs.h"
d61a4ce8
GH
25#include "audio/audio.h"
26
27/* -------------------------------------------------------------------------- */
28
29typedef struct desc_param {
30 uint32_t id;
31 uint32_t val;
32} desc_param;
33
34typedef 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
45typedef struct desc_codec {
46 const char *name;
47 uint32_t iid;
48 const desc_node *nodes;
49 uint32_t nnodes;
50} desc_codec;
51
52static 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
64static 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
76static 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
d61a4ce8
GH
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
2690e61e
BD
122#define PARAM mixemu
123#define HDA_MIXER
7953793c 124#include "hda-codec-common.h"
2690e61e
BD
125
126#define PARAM nomixemu
127#include "hda-codec-common.h"
128
d61a4ce8
GH
129/* -------------------------------------------------------------------------- */
130
131static 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
140typedef struct HDAAudioState HDAAudioState;
141typedef struct HDAAudioStream HDAAudioStream;
142
143struct 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
cd6c8830
GH
161#define TYPE_HDA_AUDIO "hda-audio"
162#define HDA_AUDIO(obj) OBJECT_CHECK(HDAAudioState, (obj), TYPE_HDA_AUDIO)
163
d61a4ce8
GH
164struct HDAAudioState {
165 HDACodecDevice hda;
166 const char *name;
167
168 QEMUSoundCard card;
169 const desc_codec *desc;
170 HDAAudioStream st[4];
ba43d289
MAL
171 bool running_compat[16];
172 bool running_real[2 * 16];
d61a4ce8
GH
173
174 /* properties */
175 uint32_t debug;
2690e61e 176 bool mixer;
d61a4ce8
GH
177};
178
179static 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
205static 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
231static 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
249static 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
4843877e
GH
265 if (!st->state->mixer) {
266 return;
267 }
d61a4ce8 268 if (st->output) {
9fe5497c 269 AUD_set_volume_out(st->voice.out, muted, left, right);
d61a4ce8 270 } else {
9fe5497c 271 AUD_set_volume_in(st->voice.in, muted, left, right);
d61a4ce8
GH
272 }
273}
274
275static 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
296static void hda_audio_command(HDACodecDevice *hda, uint32_t nid, uint32_t data)
297{
cd6c8830 298 HDAAudioState *a = HDA_AUDIO(hda);
d61a4ce8
GH
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);
ba43d289 373 hda_audio_set_running(st, a->running_real[st->output * 16 + st->stream]);
d61a4ce8
GH
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
450fail:
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
ba43d289 456static void hda_audio_stream(HDACodecDevice *hda, uint32_t stnr, bool running, bool output)
d61a4ce8 457{
cd6c8830 458 HDAAudioState *a = HDA_AUDIO(hda);
d61a4ce8
GH
459 int s;
460
ba43d289
MAL
461 a->running_compat[stnr] = running;
462 a->running_real[output * 16 + stnr] = running;
d61a4ce8
GH
463 for (s = 0; s < ARRAY_SIZE(a->st); s++) {
464 if (a->st[s].node == NULL) {
465 continue;
466 }
ba43d289
MAL
467 if (a->st[s].output != output) {
468 continue;
469 }
d61a4ce8
GH
470 if (a->st[s].stream != stnr) {
471 continue;
472 }
473 hda_audio_set_running(&a->st[s], running);
474 }
475}
476
477static int hda_audio_init(HDACodecDevice *hda, const struct desc_codec *desc)
478{
cd6c8830 479 HDAAudioState *a = HDA_AUDIO(hda);
d61a4ce8
GH
480 HDAAudioStream *st;
481 const desc_node *node;
482 const desc_param *param;
483 uint32_t i, type;
484
485 a->desc = desc;
f79f2bfc 486 a->name = object_get_typename(OBJECT(a));
d61a4ce8
GH
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);
2ab5bf67 493 if (param == NULL) {
d61a4ce8 494 continue;
2ab5bf67 495 }
d61a4ce8
GH
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
129dcd2c
GH
523static int hda_audio_exit(HDACodecDevice *hda)
524{
cd6c8830 525 HDAAudioState *a = HDA_AUDIO(hda);
129dcd2c
GH
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
d61a4ce8
GH
545static 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__);
ba43d289
MAL
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
d61a4ce8
GH
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);
ba43d289 565 hda_audio_set_running(st, a->running_real[st->output * 16 + st->stream]);
d61a4ce8
GH
566 }
567 return 0;
568}
569
39e6a38c
GH
570static void hda_audio_reset(DeviceState *dev)
571{
cd6c8830 572 HDAAudioState *a = HDA_AUDIO(dev);
39e6a38c
GH
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
d61a4ce8
GH
585static const VMStateDescription vmstate_hda_audio_stream = {
586 .name = "hda-audio-stream",
587 .version_id = 1,
d49805ae 588 .fields = (VMStateField[]) {
d61a4ce8
GH
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
602static const VMStateDescription vmstate_hda_audio = {
603 .name = "hda-audio",
ba43d289 604 .version_id = 2,
d61a4ce8 605 .post_load = hda_audio_post_load,
d49805ae 606 .fields = (VMStateField[]) {
d61a4ce8
GH
607 VMSTATE_STRUCT_ARRAY(st, HDAAudioState, 4, 0,
608 vmstate_hda_audio_stream,
609 HDAAudioStream),
ba43d289
MAL
610 VMSTATE_BOOL_ARRAY(running_compat, HDAAudioState, 16),
611 VMSTATE_BOOL_ARRAY_V(running_real, HDAAudioState, 2 * 16, 2),
d61a4ce8
GH
612 VMSTATE_END_OF_LIST()
613 }
614};
615
616static Property hda_audio_properties[] = {
2690e61e 617 DEFINE_PROP_UINT32("debug", HDAAudioState, debug, 0),
2690e61e 618 DEFINE_PROP_BOOL("mixer", HDAAudioState, mixer, true),
d61a4ce8
GH
619 DEFINE_PROP_END_OF_LIST(),
620};
621
622static int hda_audio_init_output(HDACodecDevice *hda)
623{
cd6c8830 624 HDAAudioState *a = HDA_AUDIO(hda);
2690e61e
BD
625
626 if (!a->mixer) {
627 return hda_audio_init(hda, &output_nomixemu);
628 } else {
2690e61e 629 return hda_audio_init(hda, &output_mixemu);
2690e61e 630 }
d61a4ce8
GH
631}
632
633static int hda_audio_init_duplex(HDACodecDevice *hda)
634{
cd6c8830 635 HDAAudioState *a = HDA_AUDIO(hda);
2690e61e
BD
636
637 if (!a->mixer) {
638 return hda_audio_init(hda, &duplex_nomixemu);
639 } else {
2690e61e 640 return hda_audio_init(hda, &duplex_mixemu);
2690e61e 641 }
d61a4ce8
GH
642}
643
20110065
GH
644static int hda_audio_init_micro(HDACodecDevice *hda)
645{
cd6c8830 646 HDAAudioState *a = HDA_AUDIO(hda);
2690e61e
BD
647
648 if (!a->mixer) {
649 return hda_audio_init(hda, &micro_nomixemu);
650 } else {
2690e61e 651 return hda_audio_init(hda, &micro_mixemu);
2690e61e 652 }
20110065
GH
653}
654
cd6c8830 655static void hda_audio_base_class_init(ObjectClass *klass, void *data)
dbaa7904 656{
39bffca2 657 DeviceClass *dc = DEVICE_CLASS(klass);
dbaa7904
AL
658 HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass);
659
dbaa7904
AL
660 k->exit = hda_audio_exit;
661 k->command = hda_audio_command;
662 k->stream = hda_audio_stream;
125ee0ed 663 set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
39e6a38c 664 dc->reset = hda_audio_reset;
39bffca2
AL
665 dc->vmsd = &vmstate_hda_audio;
666 dc->props = hda_audio_properties;
dbaa7904
AL
667}
668
cd6c8830
GH
669static 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
676static 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
8c43a6f0 685static const TypeInfo hda_audio_output_info = {
39bffca2 686 .name = "hda-output",
cd6c8830 687 .parent = TYPE_HDA_AUDIO,
39bffca2
AL
688 .instance_size = sizeof(HDAAudioState),
689 .class_init = hda_audio_output_class_init,
d61a4ce8
GH
690};
691
dbaa7904
AL
692static void hda_audio_duplex_class_init(ObjectClass *klass, void *data)
693{
39bffca2 694 DeviceClass *dc = DEVICE_CLASS(klass);
dbaa7904
AL
695 HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass);
696
697 k->init = hda_audio_init_duplex;
20110065 698 dc->desc = "HDA Audio Codec, duplex (line-out, line-in)";
dbaa7904
AL
699}
700
8c43a6f0 701static const TypeInfo hda_audio_duplex_info = {
39bffca2 702 .name = "hda-duplex",
cd6c8830 703 .parent = TYPE_HDA_AUDIO,
39bffca2
AL
704 .instance_size = sizeof(HDAAudioState),
705 .class_init = hda_audio_duplex_class_init,
d61a4ce8
GH
706};
707
20110065
GH
708static 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;
20110065 714 dc->desc = "HDA Audio Codec, duplex (speaker, microphone)";
20110065
GH
715}
716
8c43a6f0 717static const TypeInfo hda_audio_micro_info = {
20110065 718 .name = "hda-micro",
cd6c8830 719 .parent = TYPE_HDA_AUDIO,
20110065
GH
720 .instance_size = sizeof(HDAAudioState),
721 .class_init = hda_audio_micro_class_init,
722};
723
83f7d43a 724static void hda_audio_register_types(void)
d61a4ce8 725{
cd6c8830 726 type_register_static(&hda_audio_info);
39bffca2
AL
727 type_register_static(&hda_audio_output_info);
728 type_register_static(&hda_audio_duplex_info);
20110065 729 type_register_static(&hda_audio_micro_info);
d61a4ce8 730}
83f7d43a
AF
731
732type_init(hda_audio_register_types)