⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ac97.c

📁 xen虚拟机源代码安装包
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Copyright (C) 2006 InnoTek Systemberatung GmbH * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; * you can redistribute it and/or modify it under the terms of the GNU * General Public License as published by the Free Software Foundation, * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE * distribution. VirtualBox OSE is distributed in the hope that it will * be useful, but WITHOUT ANY WARRANTY of any kind. * * If you received this file as part of a commercial VirtualBox * distribution, then only the terms of your commercial VirtualBox * license agreement apply instead of the previous paragraph. */#include "hw.h"#include "audiodev.h"#include "audio/audio.h"#include "pci.h"enum {    AC97_Reset                     = 0x00,    AC97_Master_Volume_Mute        = 0x02,    AC97_Headphone_Volume_Mute     = 0x04,    AC97_Master_Volume_Mono_Mute   = 0x06,    AC97_Master_Tone_RL            = 0x08,    AC97_PC_BEEP_Volume_Mute       = 0x0A,    AC97_Phone_Volume_Mute         = 0x0C,    AC97_Mic_Volume_Mute           = 0x0E,    AC97_Line_In_Volume_Mute       = 0x10,    AC97_CD_Volume_Mute            = 0x12,    AC97_Video_Volume_Mute         = 0x14,    AC97_Aux_Volume_Mute           = 0x16,    AC97_PCM_Out_Volume_Mute       = 0x18,    AC97_Record_Select             = 0x1A,    AC97_Record_Gain_Mute          = 0x1C,    AC97_Record_Gain_Mic_Mute      = 0x1E,    AC97_General_Purpose           = 0x20,    AC97_3D_Control                = 0x22,    AC97_AC_97_RESERVED            = 0x24,    AC97_Powerdown_Ctrl_Stat       = 0x26,    AC97_Extended_Audio_ID         = 0x28,    AC97_Extended_Audio_Ctrl_Stat  = 0x2A,    AC97_PCM_Front_DAC_Rate        = 0x2C,    AC97_PCM_Surround_DAC_Rate     = 0x2E,    AC97_PCM_LFE_DAC_Rate          = 0x30,    AC97_PCM_LR_ADC_Rate           = 0x32,    AC97_MIC_ADC_Rate              = 0x34,    AC97_6Ch_Vol_C_LFE_Mute        = 0x36,    AC97_6Ch_Vol_L_R_Surround_Mute = 0x38,    AC97_Vendor_Reserved           = 0x58,    AC97_Vendor_ID1                = 0x7c,    AC97_Vendor_ID2                = 0x7e};#define SOFT_VOLUME#define SR_FIFOE 16             /* rwc */#define SR_BCIS  8              /* rwc */#define SR_LVBCI 4              /* rwc */#define SR_CELV  2              /* ro */#define SR_DCH   1              /* ro */#define SR_VALID_MASK ((1 << 5) - 1)#define SR_WCLEAR_MASK (SR_FIFOE | SR_BCIS | SR_LVBCI)#define SR_RO_MASK (SR_DCH | SR_CELV)#define SR_INT_MASK (SR_FIFOE | SR_BCIS | SR_LVBCI)#define CR_IOCE  16             /* rw */#define CR_FEIE  8              /* rw */#define CR_LVBIE 4              /* rw */#define CR_RR    2              /* rw */#define CR_RPBM  1              /* rw */#define CR_VALID_MASK ((1 << 5) - 1)#define CR_DONT_CLEAR_MASK (CR_IOCE | CR_FEIE | CR_LVBIE)#define GC_WR    4              /* rw */#define GC_CR    2              /* rw */#define GC_VALID_MASK ((1 << 6) - 1)#define GS_MD3   (1<<17)        /* rw */#define GS_AD3   (1<<16)        /* rw */#define GS_RCS   (1<<15)        /* rwc */#define GS_B3S12 (1<<14)        /* ro */#define GS_B2S12 (1<<13)        /* ro */#define GS_B1S12 (1<<12)        /* ro */#define GS_S1R1  (1<<11)        /* rwc */#define GS_S0R1  (1<<10)        /* rwc */#define GS_S1CR  (1<<9)         /* ro */#define GS_S0CR  (1<<8)         /* ro */#define GS_MINT  (1<<7)         /* ro */#define GS_POINT (1<<6)         /* ro */#define GS_PIINT (1<<5)         /* ro */#define GS_RSRVD ((1<<4)|(1<<3))#define GS_MOINT (1<<2)         /* ro */#define GS_MIINT (1<<1)         /* ro */#define GS_GSCI  1              /* rwc */#define GS_RO_MASK (GS_B3S12|                   \                    GS_B2S12|                   \                    GS_B1S12|                   \                    GS_S1CR|                    \                    GS_S0CR|                    \                    GS_MINT|                    \                    GS_POINT|                   \                    GS_PIINT|                   \                    GS_RSRVD|                   \                    GS_MOINT|                   \                    GS_MIINT)#define GS_VALID_MASK ((1 << 18) - 1)#define GS_WCLEAR_MASK (GS_RCS|GS_S1R1|GS_S0R1|GS_GSCI)#define BD_IOC (1<<31)#define BD_BUP (1<<30)#define EACS_VRA 1#define EACS_VRM 8#define VOL_MASK 0x1f#define MUTE_SHIFT 15#define REC_MASK 7enum {    REC_MIC = 0,    REC_CD,    REC_VIDEO,    REC_AUX,    REC_LINE_IN,    REC_STEREO_MIX,    REC_MONO_MIX,    REC_PHONE};typedef struct BD {    uint32_t addr;    uint32_t ctl_len;} BD;typedef struct AC97BusMasterRegs {    uint32_t bdbar;             /* rw 0 */    uint8_t civ;                /* ro 0 */    uint8_t lvi;                /* rw 0 */    uint16_t sr;                /* rw 1 */    uint16_t picb;              /* ro 0 */    uint8_t piv;                /* ro 0 */    uint8_t cr;                 /* rw 0 */    unsigned int bd_valid;    BD bd;} AC97BusMasterRegs;typedef struct AC97LinkState {    PCIDevice *pci_dev;    QEMUSoundCard card;    uint32_t glob_cnt;    uint32_t glob_sta;    uint32_t cas;    uint32_t last_samp;    AC97BusMasterRegs bm_regs[3];    uint8_t mixer_data[256];    SWVoiceIn *voice_pi;    SWVoiceOut *voice_po;    SWVoiceIn *voice_mc;    uint8_t silence[128];    uint32_t base[2];    int bup_flag;} AC97LinkState;enum {    BUP_SET = 1,    BUP_LAST = 2};#ifdef DEBUG_AC97#define dolog(...) AUD_log ("ac97", __VA_ARGS__)#else#define dolog(...)#endiftypedef struct PCIAC97LinkState {    PCIDevice dev;    AC97LinkState ac97;} PCIAC97LinkState;#define MKREGS(prefix, start)                   \enum {                                          \    prefix ## _BDBAR = start,                   \    prefix ## _CIV = start + 4,                 \    prefix ## _LVI = start + 5,                 \    prefix ## _SR = start + 6,                  \    prefix ## _PICB = start + 8,                \    prefix ## _PIV = start + 10,                \    prefix ## _CR = start + 11                  \}enum {    PI_INDEX = 0,    PO_INDEX,    MC_INDEX,    LAST_INDEX};MKREGS (PI, PI_INDEX * 16);MKREGS (PO, PO_INDEX * 16);MKREGS (MC, MC_INDEX * 16);enum {    GLOB_CNT = 0x2c,    GLOB_STA = 0x30,    CAS      = 0x34};#define GET_BM(index) (((index) >> 4) & 3)static void po_callback (void *opaque, int free);static void pi_callback (void *opaque, int avail);static void mc_callback (void *opaque, int avail);static void warm_reset (AC97LinkState *s){    (void) s;}static void cold_reset (AC97LinkState * s){    (void) s;}static void fetch_bd (AC97LinkState *s, AC97BusMasterRegs *r){    uint8_t b[8];    cpu_physical_memory_read (r->bdbar + r->civ * 8, b, 8);    r->bd_valid = 1;    r->bd.addr = le32_to_cpu (*(uint32_t *) &b[0]) & ~3;    r->bd.ctl_len = le32_to_cpu (*(uint32_t *) &b[4]);    r->picb = r->bd.ctl_len & 0xffff;    dolog ("bd %2d addr=%#x ctl=%#06x len=%#x(%d bytes)\n",           r->civ, r->bd.addr, r->bd.ctl_len >> 16,           r->bd.ctl_len & 0xffff,           (r->bd.ctl_len & 0xffff) << 1);}static void update_sr (AC97LinkState *s, AC97BusMasterRegs *r, uint32_t new_sr){    int event = 0;    int level = 0;    uint32_t new_mask = new_sr & SR_INT_MASK;    uint32_t old_mask = r->sr & SR_INT_MASK;    uint32_t masks[] = {GS_PIINT, GS_POINT, GS_MINT};    if (new_mask ^ old_mask) {        /** @todo is IRQ deasserted when only one of status bits is cleared? */        if (!new_mask) {            event = 1;            level = 0;        }        else {            if ((new_mask & SR_LVBCI) && (r->cr & CR_LVBIE)) {                event = 1;                level = 1;            }            if ((new_mask & SR_BCIS) && (r->cr & CR_IOCE)) {                event = 1;                level = 1;            }        }    }    r->sr = new_sr;    dolog ("IOC%d LVB%d sr=%#x event=%d level=%d\n",           r->sr & SR_BCIS, r->sr & SR_LVBCI,           r->sr,           event, level);    if (!event)        return;    if (level) {        s->glob_sta |= masks[r - s->bm_regs];        dolog ("set irq level=1\n");        qemu_set_irq(s->pci_dev->irq[0], 1);    }    else {        s->glob_sta &= ~masks[r - s->bm_regs];        dolog ("set irq level=0\n");        qemu_set_irq(s->pci_dev->irq[0], 0);    }}static void voice_set_active (AC97LinkState *s, int bm_index, int on){    switch (bm_index) {    case PI_INDEX:        AUD_set_active_in (s->voice_pi, on);        break;    case PO_INDEX:        AUD_set_active_out (s->voice_po, on);        break;    case MC_INDEX:        AUD_set_active_in (s->voice_mc, on);        break;    default:        AUD_log ("ac97", "invalid bm_index(%d) in voice_set_active", bm_index);        break;    }}static void reset_bm_regs (AC97LinkState *s, AC97BusMasterRegs *r){    dolog ("reset_bm_regs\n");    r->bdbar = 0;    r->civ = 0;    r->lvi = 0;    /** todo do we need to do that? */    update_sr (s, r, SR_DCH);    r->picb = 0;    r->piv = 0;    r->cr = r->cr & CR_DONT_CLEAR_MASK;    r->bd_valid = 0;    voice_set_active (s, r - s->bm_regs, 0);    memset (s->silence, 0, sizeof (s->silence));}static void mixer_store (AC97LinkState *s, uint32_t i, uint16_t v){    if (i + 2 > sizeof (s->mixer_data)) {        dolog ("mixer_store: index %d out of bounds %d\n",               i, sizeof (s->mixer_data));        return;    }    s->mixer_data[i + 0] = v & 0xff;    s->mixer_data[i + 1] = v >> 8;}static uint16_t mixer_load (AC97LinkState *s, uint32_t i){    uint16_t val = 0xffff;    if (i + 2 > sizeof (s->mixer_data)) {        dolog ("mixer_store: index %d out of bounds %d\n",               i, sizeof (s->mixer_data));    }    else {        val = s->mixer_data[i + 0] | (s->mixer_data[i + 1] << 8);    }    return val;}static void open_voice (AC97LinkState *s, int index, int freq){    audsettings_t as;    as.freq = freq;    as.nchannels = 2;    as.fmt = AUD_FMT_S16;    as.endianness = 0;    switch (index) {    case PI_INDEX:        s->voice_pi = AUD_open_in (            &s->card,            s->voice_pi,            "ac97.pi",            s,            pi_callback,            &as            );        break;    case PO_INDEX:        s->voice_po = AUD_open_out (            &s->card,            s->voice_po,            "ac97.po",            s,            po_callback,            &as            );        break;    case MC_INDEX:        s->voice_mc = AUD_open_in (            &s->card,            s->voice_mc,            "ac97.mc",            s,            mc_callback,            &as            );        break;    }}static void reset_voices (AC97LinkState *s, uint8_t active[LAST_INDEX]){    uint16_t freq;    freq = mixer_load (s, AC97_PCM_LR_ADC_Rate);    open_voice (s, PI_INDEX, freq);    AUD_set_active_in (s->voice_pi, active[PI_INDEX]);    freq = mixer_load (s, AC97_PCM_Front_DAC_Rate);    open_voice (s, PO_INDEX, freq);    AUD_set_active_out (s->voice_po, active[PO_INDEX]);    freq = mixer_load (s, AC97_MIC_ADC_Rate);    open_voice (s, MC_INDEX, freq);    AUD_set_active_in (s->voice_mc, active[MC_INDEX]);}#ifdef USE_MIXERstatic void set_volume (AC97LinkState *s, int index,                        audmixerctl_t mt, uint32_t val){    int mute = (val >> MUTE_SHIFT) & 1;    uint8_t rvol = VOL_MASK - (val & VOL_MASK);    uint8_t lvol = VOL_MASK - ((val >> 8) & VOL_MASK);    rvol = 255 * rvol / VOL_MASK;    lvol = 255 * lvol / VOL_MASK;#ifdef SOFT_VOLUME    if (index == AC97_Master_Volume_Mute) {        AUD_set_volume_out (s->voice_po, mute, lvol, rvol);    }    else {        AUD_set_volume (mt, &mute, &lvol, &rvol);    }#else    AUD_set_volume (mt, &mute, &lvol, &rvol);#endif    rvol = VOL_MASK - ((VOL_MASK * rvol) / 255);    lvol = VOL_MASK - ((VOL_MASK * lvol) / 255);    mixer_store (s, index, val);}static audrecsource_t ac97_to_aud_record_source (uint8_t i){    switch (i) {    case REC_MIC:        return AUD_REC_MIC;    case REC_CD:        return AUD_REC_CD;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -