cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

hda-codec.c (27344B)


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