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/pci/pci.h" |
22 | #include "hw/qdev-properties.h" |
23 | #include "intel-hda.h" |
24 | #include "migration/vmstate.h" |
25 | #include "qemu/module.h" |
26 | #include "intel-hda-defs.h" |
27 | #include "audio/audio.h" |
28 | #include "trace.h" |
29 | |
30 | /* -------------------------------------------------------------------------- */ |
31 | |
32 | typedef struct desc_param { |
33 | uint32_t id; |
34 | uint32_t val; |
35 | } desc_param; |
36 | |
37 | typedef struct desc_node { |
38 | uint32_t nid; |
39 | const char *name; |
40 | const desc_param *params; |
41 | uint32_t nparams; |
42 | uint32_t config; |
43 | uint32_t pinctl; |
44 | uint32_t *conn; |
45 | uint32_t stindex; |
46 | } desc_node; |
47 | |
48 | typedef struct desc_codec { |
49 | const char *name; |
50 | uint32_t iid; |
51 | const desc_node *nodes; |
52 | uint32_t nnodes; |
53 | } desc_codec; |
54 | |
55 | static const desc_param* hda_codec_find_param(const desc_node *node, uint32_t id) |
56 | { |
57 | int i; |
58 | |
59 | for (i = 0; i < node->nparams; i++) { |
60 | if (node->params[i].id == id) { |
61 | return &node->params[i]; |
62 | } |
63 | } |
64 | return NULL; |
65 | } |
66 | |
67 | static const desc_node* hda_codec_find_node(const desc_codec *codec, uint32_t nid) |
68 | { |
69 | int i; |
70 | |
71 | for (i = 0; i < codec->nnodes; i++) { |
72 | if (codec->nodes[i].nid == nid) { |
73 | return &codec->nodes[i]; |
74 | } |
75 | } |
76 | return NULL; |
77 | } |
78 | |
79 | static void hda_codec_parse_fmt(uint32_t format, struct audsettings *as) |
80 | { |
81 | if (format & AC_FMT_TYPE_NON_PCM) { |
82 | return; |
83 | } |
84 | |
85 | as->freq = (format & AC_FMT_BASE_44K) ? 44100 : 48000; |
86 | |
87 | switch ((format & AC_FMT_MULT_MASK) >> AC_FMT_MULT_SHIFT) { |
88 | case 1: as->freq *= 2; break; |
89 | case 2: as->freq *= 3; break; |
90 | case 3: as->freq *= 4; break; |
91 | } |
92 | |
93 | switch ((format & AC_FMT_DIV_MASK) >> AC_FMT_DIV_SHIFT) { |
94 | case 1: as->freq /= 2; break; |
95 | case 2: as->freq /= 3; break; |
96 | case 3: as->freq /= 4; break; |
97 | case 4: as->freq /= 5; break; |
98 | case 5: as->freq /= 6; break; |
99 | case 6: as->freq /= 7; break; |
100 | case 7: as->freq /= 8; break; |
101 | } |
102 | |
103 | switch (format & AC_FMT_BITS_MASK) { |
104 | case AC_FMT_BITS_8: as->fmt = AUDIO_FORMAT_S8; break; |
105 | case AC_FMT_BITS_16: as->fmt = AUDIO_FORMAT_S16; break; |
106 | case AC_FMT_BITS_32: as->fmt = AUDIO_FORMAT_S32; break; |
107 | } |
108 | |
109 | as->nchannels = ((format & AC_FMT_CHAN_MASK) >> AC_FMT_CHAN_SHIFT) + 1; |
110 | } |
111 | |
112 | /* -------------------------------------------------------------------------- */ |
113 | /* |
114 | * HDA codec descriptions |
115 | */ |
116 | |
117 | /* some defines */ |
118 | |
119 | #define QEMU_HDA_ID_VENDOR 0x1af4 |
120 | #define QEMU_HDA_PCM_FORMATS (AC_SUPPCM_BITS_16 | \ |
121 | 0x1fc /* 16 -> 96 kHz */) |
122 | #define QEMU_HDA_AMP_NONE (0) |
123 | #define QEMU_HDA_AMP_STEPS 0x4a |
124 | |
125 | #define PARAM mixemu |
126 | #define HDA_MIXER |
127 | #include "hda-codec-common.h" |
128 | |
129 | #define PARAM nomixemu |
130 | #include "hda-codec-common.h" |
131 | |
132 | #define HDA_TIMER_TICKS (SCALE_MS) |
133 | #define B_SIZE sizeof(st->buf) |
134 | #define B_MASK (sizeof(st->buf) - 1) |
135 | |
136 | /* -------------------------------------------------------------------------- */ |
137 | |
138 | static const char *fmt2name[] = { |
139 | [ AUDIO_FORMAT_U8 ] = "PCM-U8" , |
140 | [ AUDIO_FORMAT_S8 ] = "PCM-S8" , |
141 | [ AUDIO_FORMAT_U16 ] = "PCM-U16" , |
142 | [ AUDIO_FORMAT_S16 ] = "PCM-S16" , |
143 | [ AUDIO_FORMAT_U32 ] = "PCM-U32" , |
144 | [ AUDIO_FORMAT_S32 ] = "PCM-S32" , |
145 | }; |
146 | |
147 | typedef struct HDAAudioState HDAAudioState; |
148 | typedef struct HDAAudioStream HDAAudioStream; |
149 | |
150 | struct HDAAudioStream { |
151 | HDAAudioState *state; |
152 | const desc_node *node; |
153 | bool output, running; |
154 | uint32_t stream; |
155 | uint32_t channel; |
156 | uint32_t format; |
157 | uint32_t gain_left, gain_right; |
158 | bool mute_left, mute_right; |
159 | struct audsettings as; |
160 | union { |
161 | SWVoiceIn *in; |
162 | SWVoiceOut *out; |
163 | } voice; |
164 | uint8_t compat_buf[HDA_BUFFER_SIZE]; |
165 | uint32_t compat_bpos; |
166 | uint8_t buf[8192]; /* size must be power of two */ |
167 | int64_t rpos; |
168 | int64_t wpos; |
169 | QEMUTimer *buft; |
170 | int64_t buft_start; |
171 | }; |
172 | |
173 | #define TYPE_HDA_AUDIO "hda-audio" |
174 | #define HDA_AUDIO(obj) OBJECT_CHECK(HDAAudioState, (obj), TYPE_HDA_AUDIO) |
175 | |
176 | struct HDAAudioState { |
177 | HDACodecDevice hda; |
178 | const char *name; |
179 | |
180 | QEMUSoundCard card; |
181 | const desc_codec *desc; |
182 | HDAAudioStream st[4]; |
183 | bool running_compat[16]; |
184 | bool running_real[2 * 16]; |
185 | |
186 | /* properties */ |
187 | uint32_t debug; |
188 | bool mixer; |
189 | bool use_timer; |
190 | }; |
191 | |
192 | static inline int64_t hda_bytes_per_second(HDAAudioStream *st) |
193 | { |
194 | return 2LL * st->as.nchannels * st->as.freq; |
195 | } |
196 | |
197 | static inline void hda_timer_sync_adjust(HDAAudioStream *st, int64_t target_pos) |
198 | { |
199 | int64_t limit = B_SIZE / 8; |
200 | int64_t corr = 0; |
201 | |
202 | if (target_pos > limit) { |
203 | corr = HDA_TIMER_TICKS; |
204 | } |
205 | if (target_pos < -limit) { |
206 | corr = -HDA_TIMER_TICKS; |
207 | } |
208 | if (target_pos < -(2 * limit)) { |
209 | corr = -(4 * HDA_TIMER_TICKS); |
210 | } |
211 | if (corr == 0) { |
212 | return; |
213 | } |
214 | |
215 | trace_hda_audio_adjust(st->node->name, target_pos); |
216 | st->buft_start += corr; |
217 | } |
218 | |
219 | static void hda_audio_input_timer(void *opaque) |
220 | { |
221 | HDAAudioStream *st = opaque; |
222 | |
223 | int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); |
224 | |
225 | int64_t buft_start = st->buft_start; |
226 | int64_t wpos = st->wpos; |
227 | int64_t rpos = st->rpos; |
228 | |
229 | int64_t wanted_rpos = hda_bytes_per_second(st) * (now - buft_start) |
230 | / NANOSECONDS_PER_SECOND; |
231 | wanted_rpos &= -4; /* IMPORTANT! clip to frames */ |
232 | |
233 | if (wanted_rpos <= rpos) { |
234 | /* we already transmitted the data */ |
235 | goto out_timer; |
236 | } |
237 | |
238 | int64_t to_transfer = MIN(wpos - rpos, wanted_rpos - rpos); |
239 | while (to_transfer) { |
240 | uint32_t start = (rpos & B_MASK); |
241 | uint32_t chunk = MIN(B_SIZE - start, to_transfer); |
242 | int rc = hda_codec_xfer( |
243 | &st->state->hda, st->stream, false, st->buf + start, chunk); |
244 | if (!rc) { |
245 | break; |
246 | } |
247 | rpos += chunk; |
248 | to_transfer -= chunk; |
249 | st->rpos += chunk; |
250 | } |
251 | |
252 | out_timer: |
253 | |
254 | if (st->running) { |
255 | timer_mod_anticipate_ns(st->buft, now + HDA_TIMER_TICKS); |
256 | } |
257 | } |
258 | |
259 | static void hda_audio_input_cb(void *opaque, int avail) |
260 | { |
261 | HDAAudioStream *st = opaque; |
262 | |
263 | int64_t wpos = st->wpos; |
264 | int64_t rpos = st->rpos; |
265 | |
266 | int64_t to_transfer = MIN(B_SIZE - (wpos - rpos), avail); |
267 | |
268 | hda_timer_sync_adjust(st, -((wpos - rpos) + to_transfer - (B_SIZE >> 1))); |
269 | |
270 | while (to_transfer) { |
271 | uint32_t start = (uint32_t) (wpos & B_MASK); |
272 | uint32_t chunk = (uint32_t) MIN(B_SIZE - start, to_transfer); |
273 | uint32_t read = AUD_read(st->voice.in, st->buf + start, chunk); |
274 | wpos += read; |
275 | to_transfer -= read; |
276 | st->wpos += read; |
277 | if (chunk != read) { |
278 | break; |
279 | } |
280 | } |
281 | } |
282 | |
283 | static void hda_audio_output_timer(void *opaque) |
284 | { |
285 | HDAAudioStream *st = opaque; |
286 | |
287 | int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); |
288 | |
289 | int64_t buft_start = st->buft_start; |
290 | int64_t wpos = st->wpos; |
291 | int64_t rpos = st->rpos; |
292 | |
293 | int64_t wanted_wpos = hda_bytes_per_second(st) * (now - buft_start) |
294 | / NANOSECONDS_PER_SECOND; |
295 | wanted_wpos &= -4; /* IMPORTANT! clip to frames */ |
296 | |
297 | if (wanted_wpos <= wpos) { |
298 | /* we already received the data */ |
299 | goto out_timer; |
300 | } |
301 | |
302 | int64_t to_transfer = MIN(B_SIZE - (wpos - rpos), wanted_wpos - wpos); |
303 | while (to_transfer) { |
304 | uint32_t start = (wpos & B_MASK); |
305 | uint32_t chunk = MIN(B_SIZE - start, to_transfer); |
306 | int rc = hda_codec_xfer( |
307 | &st->state->hda, st->stream, true, st->buf + start, chunk); |
308 | if (!rc) { |
309 | break; |
310 | } |
311 | wpos += chunk; |
312 | to_transfer -= chunk; |
313 | st->wpos += chunk; |
314 | } |
315 | |
316 | out_timer: |
317 | |
318 | if (st->running) { |
319 | timer_mod_anticipate_ns(st->buft, now + HDA_TIMER_TICKS); |
320 | } |
321 | } |
322 | |
323 | static void hda_audio_output_cb(void *opaque, int avail) |
324 | { |
325 | HDAAudioStream *st = opaque; |
326 | |
327 | int64_t wpos = st->wpos; |
328 | int64_t rpos = st->rpos; |
329 | |
330 | int64_t to_transfer = MIN(wpos - rpos, avail); |
331 | |
332 | if (wpos - rpos == B_SIZE) { |
333 | /* drop buffer, reset timer adjust */ |
334 | st->rpos = 0; |
335 | st->wpos = 0; |
336 | st->buft_start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); |
337 | trace_hda_audio_overrun(st->node->name); |
338 | return; |
339 | } |
340 | |
341 | hda_timer_sync_adjust(st, (wpos - rpos) - to_transfer - (B_SIZE >> 1)); |
342 | |
343 | while (to_transfer) { |
344 | uint32_t start = (uint32_t) (rpos & B_MASK); |
345 | uint32_t chunk = (uint32_t) MIN(B_SIZE - start, to_transfer); |
346 | uint32_t written = AUD_write(st->voice.out, st->buf + start, chunk); |
347 | rpos += written; |
348 | to_transfer -= written; |
349 | st->rpos += written; |
350 | if (chunk != written) { |
351 | break; |
352 | } |
353 | } |
354 | } |
355 | |
356 | static void hda_audio_compat_input_cb(void *opaque, int avail) |
357 | { |
358 | HDAAudioStream *st = opaque; |
359 | int recv = 0; |
360 | int len; |
361 | bool rc; |
362 | |
363 | while (avail - recv >= sizeof(st->compat_buf)) { |
364 | if (st->compat_bpos != sizeof(st->compat_buf)) { |
365 | len = AUD_read(st->voice.in, st->compat_buf + st->compat_bpos, |
366 | sizeof(st->compat_buf) - st->compat_bpos); |
367 | st->compat_bpos += len; |
368 | recv += len; |
369 | if (st->compat_bpos != sizeof(st->compat_buf)) { |
370 | break; |
371 | } |
372 | } |
373 | rc = hda_codec_xfer(&st->state->hda, st->stream, false, |
374 | st->compat_buf, sizeof(st->compat_buf)); |
375 | if (!rc) { |
376 | break; |
377 | } |
378 | st->compat_bpos = 0; |
379 | } |
380 | } |
381 | |
382 | static void hda_audio_compat_output_cb(void *opaque, int avail) |
383 | { |
384 | HDAAudioStream *st = opaque; |
385 | int sent = 0; |
386 | int len; |
387 | bool rc; |
388 | |
389 | while (avail - sent >= sizeof(st->compat_buf)) { |
390 | if (st->compat_bpos == sizeof(st->compat_buf)) { |
391 | rc = hda_codec_xfer(&st->state->hda, st->stream, true, |
392 | st->compat_buf, sizeof(st->compat_buf)); |
393 | if (!rc) { |
394 | break; |
395 | } |
396 | st->compat_bpos = 0; |
397 | } |
398 | len = AUD_write(st->voice.out, st->compat_buf + st->compat_bpos, |
399 | sizeof(st->compat_buf) - st->compat_bpos); |
400 | st->compat_bpos += len; |
401 | sent += len; |
402 | if (st->compat_bpos != sizeof(st->compat_buf)) { |
403 | break; |
404 | } |
405 | } |
406 | } |
407 | |
408 | static void hda_audio_set_running(HDAAudioStream *st, bool running) |
409 | { |
410 | if (st->node == NULL) { |
411 | return; |
412 | } |
413 | if (st->running == running) { |
414 | return; |
415 | } |
416 | st->running = running; |
417 | trace_hda_audio_running(st->node->name, st->stream, st->running); |
418 | if (st->state->use_timer) { |
419 | if (running) { |
420 | int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); |
421 | st->rpos = 0; |
422 | st->wpos = 0; |
423 | st->buft_start = now; |
424 | timer_mod_anticipate_ns(st->buft, now + HDA_TIMER_TICKS); |
425 | } else { |
426 | timer_del(st->buft); |
427 | } |
428 | } |
429 | if (st->output) { |
430 | AUD_set_active_out(st->voice.out, st->running); |
431 | } else { |
432 | AUD_set_active_in(st->voice.in, st->running); |
433 | } |
434 | } |
435 | |
436 | static void hda_audio_set_amp(HDAAudioStream *st) |
437 | { |
438 | bool muted; |
439 | uint32_t left, right; |
440 | |
441 | if (st->node == NULL) { |
442 | return; |
443 | } |
444 | |
445 | muted = st->mute_left && st->mute_right; |
446 | left = st->mute_left ? 0 : st->gain_left; |
447 | right = st->mute_right ? 0 : st->gain_right; |
448 | |
449 | left = left * 255 / QEMU_HDA_AMP_STEPS; |
450 | right = right * 255 / QEMU_HDA_AMP_STEPS; |
451 | |
452 | if (!st->state->mixer) { |
453 | return; |
454 | } |
455 | if (st->output) { |
456 | AUD_set_volume_out(st->voice.out, muted, left, right); |
457 | } else { |
458 | AUD_set_volume_in(st->voice.in, muted, left, right); |
459 | } |
460 | } |
461 | |
462 | static void hda_audio_setup(HDAAudioStream *st) |
463 | { |
464 | bool use_timer = st->state->use_timer; |
465 | audio_callback_fn cb; |
466 | |
467 | if (st->node == NULL) { |
468 | return; |
469 | } |
470 | |
471 | trace_hda_audio_format(st->node->name, st->as.nchannels, |
472 | fmt2name[st->as.fmt], st->as.freq); |
473 | |
474 | if (st->output) { |
475 | if (use_timer) { |
476 | cb = hda_audio_output_cb; |
477 | st->buft = timer_new_ns(QEMU_CLOCK_VIRTUAL, |
478 | hda_audio_output_timer, st); |
479 | } else { |
480 | cb = hda_audio_compat_output_cb; |
481 | } |
482 | st->voice.out = AUD_open_out(&st->state->card, st->voice.out, |
483 | st->node->name, st, cb, &st->as); |
484 | } else { |
485 | if (use_timer) { |
486 | cb = hda_audio_input_cb; |
487 | st->buft = timer_new_ns(QEMU_CLOCK_VIRTUAL, |
488 | hda_audio_input_timer, st); |
489 | } else { |
490 | cb = hda_audio_compat_input_cb; |
491 | } |
492 | st->voice.in = AUD_open_in(&st->state->card, st->voice.in, |
493 | st->node->name, st, cb, &st->as); |
494 | } |
495 | } |
496 | |
497 | static void hda_audio_command(HDACodecDevice *hda, uint32_t nid, uint32_t data) |
498 | { |
499 | HDAAudioState *a = HDA_AUDIO(hda); |
500 | HDAAudioStream *st; |
501 | const desc_node *node = NULL; |
502 | const desc_param *param; |
503 | uint32_t verb, payload, response, count, shift; |
504 | |
505 | if ((data & 0x70000) == 0x70000) { |
506 | /* 12/8 id/payload */ |
507 | verb = (data >> 8) & 0xfff; |
508 | payload = data & 0x00ff; |
509 | } else { |
510 | /* 4/16 id/payload */ |
511 | verb = (data >> 8) & 0xf00; |
512 | payload = data & 0xffff; |
513 | } |
514 | |
515 | node = hda_codec_find_node(a->desc, nid); |
516 | if (node == NULL) { |
517 | goto fail; |
518 | } |
519 | dprint(a, 2, "%s: nid %d (%s), verb 0x%x, payload 0x%x\n" , |
520 | __func__, nid, node->name, verb, payload); |
521 | |
522 | switch (verb) { |
523 | /* all nodes */ |
524 | case AC_VERB_PARAMETERS: |
525 | param = hda_codec_find_param(node, payload); |
526 | if (param == NULL) { |
527 | goto fail; |
528 | } |
529 | hda_codec_response(hda, true, param->val); |
530 | break; |
531 | case AC_VERB_GET_SUBSYSTEM_ID: |
532 | hda_codec_response(hda, true, a->desc->iid); |
533 | break; |
534 | |
535 | /* all functions */ |
536 | case AC_VERB_GET_CONNECT_LIST: |
537 | param = hda_codec_find_param(node, AC_PAR_CONNLIST_LEN); |
538 | count = param ? param->val : 0; |
539 | response = 0; |
540 | shift = 0; |
541 | while (payload < count && shift < 32) { |
542 | response |= node->conn[payload] << shift; |
543 | payload++; |
544 | shift += 8; |
545 | } |
546 | hda_codec_response(hda, true, response); |
547 | break; |
548 | |
549 | /* pin widget */ |
550 | case AC_VERB_GET_CONFIG_DEFAULT: |
551 | hda_codec_response(hda, true, node->config); |
552 | break; |
553 | case AC_VERB_GET_PIN_WIDGET_CONTROL: |
554 | hda_codec_response(hda, true, node->pinctl); |
555 | break; |
556 | case AC_VERB_SET_PIN_WIDGET_CONTROL: |
557 | if (node->pinctl != payload) { |
558 | dprint(a, 1, "unhandled pin control bit\n" ); |
559 | } |
560 | hda_codec_response(hda, true, 0); |
561 | break; |
562 | |
563 | /* audio in/out widget */ |
564 | case AC_VERB_SET_CHANNEL_STREAMID: |
565 | st = a->st + node->stindex; |
566 | if (st->node == NULL) { |
567 | goto fail; |
568 | } |
569 | hda_audio_set_running(st, false); |
570 | st->stream = (payload >> 4) & 0x0f; |
571 | st->channel = payload & 0x0f; |
572 | dprint(a, 2, "%s: stream %d, channel %d\n" , |
573 | st->node->name, st->stream, st->channel); |
574 | hda_audio_set_running(st, a->running_real[st->output * 16 + st->stream]); |
575 | hda_codec_response(hda, true, 0); |
576 | break; |
577 | case AC_VERB_GET_CONV: |
578 | st = a->st + node->stindex; |
579 | if (st->node == NULL) { |
580 | goto fail; |
581 | } |
582 | response = st->stream << 4 | st->channel; |
583 | hda_codec_response(hda, true, response); |
584 | break; |
585 | case AC_VERB_SET_STREAM_FORMAT: |
586 | st = a->st + node->stindex; |
587 | if (st->node == NULL) { |
588 | goto fail; |
589 | } |
590 | st->format = payload; |
591 | hda_codec_parse_fmt(st->format, &st->as); |
592 | hda_audio_setup(st); |
593 | hda_codec_response(hda, true, 0); |
594 | break; |
595 | case AC_VERB_GET_STREAM_FORMAT: |
596 | st = a->st + node->stindex; |
597 | if (st->node == NULL) { |
598 | goto fail; |
599 | } |
600 | hda_codec_response(hda, true, st->format); |
601 | break; |
602 | case AC_VERB_GET_AMP_GAIN_MUTE: |
603 | st = a->st + node->stindex; |
604 | if (st->node == NULL) { |
605 | goto fail; |
606 | } |
607 | if (payload & AC_AMP_GET_LEFT) { |
608 | response = st->gain_left | (st->mute_left ? AC_AMP_MUTE : 0); |
609 | } else { |
610 | response = st->gain_right | (st->mute_right ? AC_AMP_MUTE : 0); |
611 | } |
612 | hda_codec_response(hda, true, response); |
613 | break; |
614 | case AC_VERB_SET_AMP_GAIN_MUTE: |
615 | st = a->st + node->stindex; |
616 | if (st->node == NULL) { |
617 | goto fail; |
618 | } |
619 | dprint(a, 1, "amp (%s): %s%s%s%s index %d gain %3d %s\n" , |
620 | st->node->name, |
621 | (payload & AC_AMP_SET_OUTPUT) ? "o" : "-" , |
622 | (payload & AC_AMP_SET_INPUT) ? "i" : "-" , |
623 | (payload & AC_AMP_SET_LEFT) ? "l" : "-" , |
624 | (payload & AC_AMP_SET_RIGHT) ? "r" : "-" , |
625 | (payload & AC_AMP_SET_INDEX) >> AC_AMP_SET_INDEX_SHIFT, |
626 | (payload & AC_AMP_GAIN), |
627 | (payload & AC_AMP_MUTE) ? "muted" : "" ); |
628 | if (payload & AC_AMP_SET_LEFT) { |
629 | st->gain_left = payload & AC_AMP_GAIN; |
630 | st->mute_left = payload & AC_AMP_MUTE; |
631 | } |
632 | if (payload & AC_AMP_SET_RIGHT) { |
633 | st->gain_right = payload & AC_AMP_GAIN; |
634 | st->mute_right = payload & AC_AMP_MUTE; |
635 | } |
636 | hda_audio_set_amp(st); |
637 | hda_codec_response(hda, true, 0); |
638 | break; |
639 | |
640 | /* not supported */ |
641 | case AC_VERB_SET_POWER_STATE: |
642 | case AC_VERB_GET_POWER_STATE: |
643 | case AC_VERB_GET_SDI_SELECT: |
644 | hda_codec_response(hda, true, 0); |
645 | break; |
646 | default: |
647 | goto fail; |
648 | } |
649 | return; |
650 | |
651 | fail: |
652 | dprint(a, 1, "%s: not handled: nid %d (%s), verb 0x%x, payload 0x%x\n" , |
653 | __func__, nid, node ? node->name : "?" , verb, payload); |
654 | hda_codec_response(hda, true, 0); |
655 | } |
656 | |
657 | static void hda_audio_stream(HDACodecDevice *hda, uint32_t stnr, bool running, bool output) |
658 | { |
659 | HDAAudioState *a = HDA_AUDIO(hda); |
660 | int s; |
661 | |
662 | a->running_compat[stnr] = running; |
663 | a->running_real[output * 16 + stnr] = running; |
664 | for (s = 0; s < ARRAY_SIZE(a->st); s++) { |
665 | if (a->st[s].node == NULL) { |
666 | continue; |
667 | } |
668 | if (a->st[s].output != output) { |
669 | continue; |
670 | } |
671 | if (a->st[s].stream != stnr) { |
672 | continue; |
673 | } |
674 | hda_audio_set_running(&a->st[s], running); |
675 | } |
676 | } |
677 | |
678 | static int hda_audio_init(HDACodecDevice *hda, const struct desc_codec *desc) |
679 | { |
680 | HDAAudioState *a = HDA_AUDIO(hda); |
681 | HDAAudioStream *st; |
682 | const desc_node *node; |
683 | const desc_param *param; |
684 | uint32_t i, type; |
685 | |
686 | a->desc = desc; |
687 | a->name = object_get_typename(OBJECT(a)); |
688 | dprint(a, 1, "%s: cad %d\n" , __func__, a->hda.cad); |
689 | |
690 | AUD_register_card("hda" , &a->card); |
691 | for (i = 0; i < a->desc->nnodes; i++) { |
692 | node = a->desc->nodes + i; |
693 | param = hda_codec_find_param(node, AC_PAR_AUDIO_WIDGET_CAP); |
694 | if (param == NULL) { |
695 | continue; |
696 | } |
697 | type = (param->val & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; |
698 | switch (type) { |
699 | case AC_WID_AUD_OUT: |
700 | case AC_WID_AUD_IN: |
701 | assert(node->stindex < ARRAY_SIZE(a->st)); |
702 | st = a->st + node->stindex; |
703 | st->state = a; |
704 | st->node = node; |
705 | if (type == AC_WID_AUD_OUT) { |
706 | /* unmute output by default */ |
707 | st->gain_left = QEMU_HDA_AMP_STEPS; |
708 | st->gain_right = QEMU_HDA_AMP_STEPS; |
709 | st->compat_bpos = sizeof(st->compat_buf); |
710 | st->output = true; |
711 | } else { |
712 | st->output = false; |
713 | } |
714 | st->format = AC_FMT_TYPE_PCM | AC_FMT_BITS_16 | |
715 | (1 << AC_FMT_CHAN_SHIFT); |
716 | hda_codec_parse_fmt(st->format, &st->as); |
717 | hda_audio_setup(st); |
718 | break; |
719 | } |
720 | } |
721 | return 0; |
722 | } |
723 | |
724 | static void hda_audio_exit(HDACodecDevice *hda) |
725 | { |
726 | HDAAudioState *a = HDA_AUDIO(hda); |
727 | HDAAudioStream *st; |
728 | int i; |
729 | |
730 | dprint(a, 1, "%s\n" , __func__); |
731 | for (i = 0; i < ARRAY_SIZE(a->st); i++) { |
732 | st = a->st + i; |
733 | if (st->node == NULL) { |
734 | continue; |
735 | } |
736 | if (a->use_timer) { |
737 | timer_del(st->buft); |
738 | } |
739 | if (st->output) { |
740 | AUD_close_out(&a->card, st->voice.out); |
741 | } else { |
742 | AUD_close_in(&a->card, st->voice.in); |
743 | } |
744 | } |
745 | AUD_remove_card(&a->card); |
746 | } |
747 | |
748 | static int hda_audio_post_load(void *opaque, int version) |
749 | { |
750 | HDAAudioState *a = opaque; |
751 | HDAAudioStream *st; |
752 | int i; |
753 | |
754 | dprint(a, 1, "%s\n" , __func__); |
755 | if (version == 1) { |
756 | /* assume running_compat[] is for output streams */ |
757 | for (i = 0; i < ARRAY_SIZE(a->running_compat); i++) |
758 | a->running_real[16 + i] = a->running_compat[i]; |
759 | } |
760 | |
761 | for (i = 0; i < ARRAY_SIZE(a->st); i++) { |
762 | st = a->st + i; |
763 | if (st->node == NULL) |
764 | continue; |
765 | hda_codec_parse_fmt(st->format, &st->as); |
766 | hda_audio_setup(st); |
767 | hda_audio_set_amp(st); |
768 | hda_audio_set_running(st, a->running_real[st->output * 16 + st->stream]); |
769 | } |
770 | return 0; |
771 | } |
772 | |
773 | static void hda_audio_reset(DeviceState *dev) |
774 | { |
775 | HDAAudioState *a = HDA_AUDIO(dev); |
776 | HDAAudioStream *st; |
777 | int i; |
778 | |
779 | dprint(a, 1, "%s\n" , __func__); |
780 | for (i = 0; i < ARRAY_SIZE(a->st); i++) { |
781 | st = a->st + i; |
782 | if (st->node != NULL) { |
783 | hda_audio_set_running(st, false); |
784 | } |
785 | } |
786 | } |
787 | |
788 | static bool vmstate_hda_audio_stream_buf_needed(void *opaque) |
789 | { |
790 | HDAAudioStream *st = opaque; |
791 | return st->state && st->state->use_timer; |
792 | } |
793 | |
794 | static const VMStateDescription vmstate_hda_audio_stream_buf = { |
795 | .name = "hda-audio-stream/buffer" , |
796 | .version_id = 1, |
797 | .needed = vmstate_hda_audio_stream_buf_needed, |
798 | .fields = (VMStateField[]) { |
799 | VMSTATE_BUFFER(buf, HDAAudioStream), |
800 | VMSTATE_INT64(rpos, HDAAudioStream), |
801 | VMSTATE_INT64(wpos, HDAAudioStream), |
802 | VMSTATE_TIMER_PTR(buft, HDAAudioStream), |
803 | VMSTATE_INT64(buft_start, HDAAudioStream), |
804 | VMSTATE_END_OF_LIST() |
805 | } |
806 | }; |
807 | |
808 | static const VMStateDescription vmstate_hda_audio_stream = { |
809 | .name = "hda-audio-stream" , |
810 | .version_id = 1, |
811 | .fields = (VMStateField[]) { |
812 | VMSTATE_UINT32(stream, HDAAudioStream), |
813 | VMSTATE_UINT32(channel, HDAAudioStream), |
814 | VMSTATE_UINT32(format, HDAAudioStream), |
815 | VMSTATE_UINT32(gain_left, HDAAudioStream), |
816 | VMSTATE_UINT32(gain_right, HDAAudioStream), |
817 | VMSTATE_BOOL(mute_left, HDAAudioStream), |
818 | VMSTATE_BOOL(mute_right, HDAAudioStream), |
819 | VMSTATE_UINT32(compat_bpos, HDAAudioStream), |
820 | VMSTATE_BUFFER(compat_buf, HDAAudioStream), |
821 | VMSTATE_END_OF_LIST() |
822 | }, |
823 | .subsections = (const VMStateDescription * []) { |
824 | &vmstate_hda_audio_stream_buf, |
825 | NULL |
826 | } |
827 | }; |
828 | |
829 | static const VMStateDescription vmstate_hda_audio = { |
830 | .name = "hda-audio" , |
831 | .version_id = 2, |
832 | .post_load = hda_audio_post_load, |
833 | .fields = (VMStateField[]) { |
834 | VMSTATE_STRUCT_ARRAY(st, HDAAudioState, 4, 0, |
835 | vmstate_hda_audio_stream, |
836 | HDAAudioStream), |
837 | VMSTATE_BOOL_ARRAY(running_compat, HDAAudioState, 16), |
838 | VMSTATE_BOOL_ARRAY_V(running_real, HDAAudioState, 2 * 16, 2), |
839 | VMSTATE_END_OF_LIST() |
840 | } |
841 | }; |
842 | |
843 | static Property hda_audio_properties[] = { |
844 | DEFINE_AUDIO_PROPERTIES(HDAAudioState, card), |
845 | DEFINE_PROP_UINT32("debug" , HDAAudioState, debug, 0), |
846 | DEFINE_PROP_BOOL("mixer" , HDAAudioState, mixer, true), |
847 | DEFINE_PROP_BOOL("use-timer" , HDAAudioState, use_timer, true), |
848 | DEFINE_PROP_END_OF_LIST(), |
849 | }; |
850 | |
851 | static int hda_audio_init_output(HDACodecDevice *hda) |
852 | { |
853 | HDAAudioState *a = HDA_AUDIO(hda); |
854 | |
855 | if (!a->mixer) { |
856 | return hda_audio_init(hda, &output_nomixemu); |
857 | } else { |
858 | return hda_audio_init(hda, &output_mixemu); |
859 | } |
860 | } |
861 | |
862 | static int hda_audio_init_duplex(HDACodecDevice *hda) |
863 | { |
864 | HDAAudioState *a = HDA_AUDIO(hda); |
865 | |
866 | if (!a->mixer) { |
867 | return hda_audio_init(hda, &duplex_nomixemu); |
868 | } else { |
869 | return hda_audio_init(hda, &duplex_mixemu); |
870 | } |
871 | } |
872 | |
873 | static int hda_audio_init_micro(HDACodecDevice *hda) |
874 | { |
875 | HDAAudioState *a = HDA_AUDIO(hda); |
876 | |
877 | if (!a->mixer) { |
878 | return hda_audio_init(hda, µ_nomixemu); |
879 | } else { |
880 | return hda_audio_init(hda, µ_mixemu); |
881 | } |
882 | } |
883 | |
884 | static void hda_audio_base_class_init(ObjectClass *klass, void *data) |
885 | { |
886 | DeviceClass *dc = DEVICE_CLASS(klass); |
887 | HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass); |
888 | |
889 | k->exit = hda_audio_exit; |
890 | k->command = hda_audio_command; |
891 | k->stream = hda_audio_stream; |
892 | set_bit(DEVICE_CATEGORY_SOUND, dc->categories); |
893 | dc->reset = hda_audio_reset; |
894 | dc->vmsd = &vmstate_hda_audio; |
895 | dc->props = hda_audio_properties; |
896 | } |
897 | |
898 | static const TypeInfo hda_audio_info = { |
899 | .name = TYPE_HDA_AUDIO, |
900 | .parent = TYPE_HDA_CODEC_DEVICE, |
901 | .class_init = hda_audio_base_class_init, |
902 | .abstract = true, |
903 | }; |
904 | |
905 | static void hda_audio_output_class_init(ObjectClass *klass, void *data) |
906 | { |
907 | DeviceClass *dc = DEVICE_CLASS(klass); |
908 | HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass); |
909 | |
910 | k->init = hda_audio_init_output; |
911 | dc->desc = "HDA Audio Codec, output-only (line-out)" ; |
912 | } |
913 | |
914 | static const TypeInfo hda_audio_output_info = { |
915 | .name = "hda-output" , |
916 | .parent = TYPE_HDA_AUDIO, |
917 | .instance_size = sizeof(HDAAudioState), |
918 | .class_init = hda_audio_output_class_init, |
919 | }; |
920 | |
921 | static void hda_audio_duplex_class_init(ObjectClass *klass, void *data) |
922 | { |
923 | DeviceClass *dc = DEVICE_CLASS(klass); |
924 | HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass); |
925 | |
926 | k->init = hda_audio_init_duplex; |
927 | dc->desc = "HDA Audio Codec, duplex (line-out, line-in)" ; |
928 | } |
929 | |
930 | static const TypeInfo hda_audio_duplex_info = { |
931 | .name = "hda-duplex" , |
932 | .parent = TYPE_HDA_AUDIO, |
933 | .instance_size = sizeof(HDAAudioState), |
934 | .class_init = hda_audio_duplex_class_init, |
935 | }; |
936 | |
937 | static void hda_audio_micro_class_init(ObjectClass *klass, void *data) |
938 | { |
939 | DeviceClass *dc = DEVICE_CLASS(klass); |
940 | HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass); |
941 | |
942 | k->init = hda_audio_init_micro; |
943 | dc->desc = "HDA Audio Codec, duplex (speaker, microphone)" ; |
944 | } |
945 | |
946 | static const TypeInfo hda_audio_micro_info = { |
947 | .name = "hda-micro" , |
948 | .parent = TYPE_HDA_AUDIO, |
949 | .instance_size = sizeof(HDAAudioState), |
950 | .class_init = hda_audio_micro_class_init, |
951 | }; |
952 | |
953 | static void hda_audio_register_types(void) |
954 | { |
955 | type_register_static(&hda_audio_info); |
956 | type_register_static(&hda_audio_output_info); |
957 | type_register_static(&hda_audio_duplex_info); |
958 | type_register_static(&hda_audio_micro_info); |
959 | } |
960 | |
961 | type_init(hda_audio_register_types) |
962 | |