1*7979b1cfSJérôme Duval /* 2*7979b1cfSJérôme Duval * AC97 interface 3*7979b1cfSJérôme Duval * 4*7979b1cfSJérôme Duval * Copyright (c) 2002, Marcus Overhagen <marcus@overhagen.de> 5*7979b1cfSJérôme Duval * Copyright (c) 2008, Jérôme Duval 6*7979b1cfSJérôme Duval * 7*7979b1cfSJérôme Duval * All rights reserved. 8*7979b1cfSJérôme Duval * Redistribution and use in source and binary forms, with or without modification, 9*7979b1cfSJérôme Duval * are permitted provided that the following conditions are met: 10*7979b1cfSJérôme Duval * 11*7979b1cfSJérôme Duval * - Redistributions of source code must retain the above copyright notice, 12*7979b1cfSJérôme Duval * this list of conditions and the following disclaimer. 13*7979b1cfSJérôme Duval * - Redistributions in binary form must reproduce the above copyright notice, 14*7979b1cfSJérôme Duval * this list of conditions and the following disclaimer in the documentation 15*7979b1cfSJérôme Duval * and/or other materials provided with the distribution. 16*7979b1cfSJérôme Duval * 17*7979b1cfSJérôme Duval * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18*7979b1cfSJérôme Duval * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19*7979b1cfSJérôme Duval * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20*7979b1cfSJérôme Duval * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 21*7979b1cfSJérôme Duval * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22*7979b1cfSJérôme Duval * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 23*7979b1cfSJérôme Duval * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24*7979b1cfSJérôme Duval * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25*7979b1cfSJérôme Duval * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 26*7979b1cfSJérôme Duval * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27*7979b1cfSJérôme Duval * 28*7979b1cfSJérôme Duval */ 29*7979b1cfSJérôme Duval #ifndef _AC97_H_ 30*7979b1cfSJérôme Duval #define _AC97_H_ 31*7979b1cfSJérôme Duval 32*7979b1cfSJérôme Duval enum AC97_REGISTER { 33*7979b1cfSJérôme Duval /* Baseline audio register set */ 34*7979b1cfSJérôme Duval AC97_RESET = 0x00, 35*7979b1cfSJérôme Duval AC97_MASTER_VOLUME = 0x02, 36*7979b1cfSJérôme Duval AC97_AUX_OUT_VOLUME = 0x04, 37*7979b1cfSJérôme Duval AC97_MONO_VOLUME = 0x06, 38*7979b1cfSJérôme Duval AC97_MASTER_TONE = 0x08, 39*7979b1cfSJérôme Duval AC97_PC_BEEP_VOLUME = 0x0A, 40*7979b1cfSJérôme Duval AC97_PHONE_VOLUME = 0x0C, 41*7979b1cfSJérôme Duval AC97_MIC_VOLUME = 0x0E, 42*7979b1cfSJérôme Duval AC97_LINE_IN_VOLUME = 0x10, 43*7979b1cfSJérôme Duval AC97_CD_VOLUME = 0x12, 44*7979b1cfSJérôme Duval AC97_VIDEO_VOLUME = 0x14, 45*7979b1cfSJérôme Duval AC97_AUX_IN_VOLUME = 0x16, 46*7979b1cfSJérôme Duval AC97_PCM_OUT_VOLUME = 0x18, 47*7979b1cfSJérôme Duval AC97_RECORD_SELECT = 0x1A, 48*7979b1cfSJérôme Duval AC97_RECORD_GAIN = 0x1C, 49*7979b1cfSJérôme Duval AC97_RECORD_GAIN_MIC = 0x1E, 50*7979b1cfSJérôme Duval AC97_GENERAL_PURPOSE = 0x20, 51*7979b1cfSJérôme Duval AC97_3D_CONTROL = 0x22, 52*7979b1cfSJérôme Duval AC97_PAGING = 0x24, 53*7979b1cfSJérôme Duval AC97_POWERDOWN = 0x26, 54*7979b1cfSJérôme Duval 55*7979b1cfSJérôme Duval /* Extended audio register set */ 56*7979b1cfSJérôme Duval AC97_EXTENDED_ID = 0x28, 57*7979b1cfSJérôme Duval AC97_EXTENDED_STAT_CTRL = 0x2A, 58*7979b1cfSJérôme Duval AC97_PCM_FRONT_DAC_RATE = 0x2C, 59*7979b1cfSJérôme Duval AC97_PCM_SURR_DAC_RATE = 0x2E, 60*7979b1cfSJérôme Duval AC97_PCM_LFE_DAC_RATE = 0x30, 61*7979b1cfSJérôme Duval AC97_PCM_L_R_ADC_RATE = 0x32, 62*7979b1cfSJérôme Duval AC97_MIC_ADC_RATE = 0x34, 63*7979b1cfSJérôme Duval AC97_CENTER_LFE_VOLUME = 0x36, 64*7979b1cfSJérôme Duval AC97_SURR_VOLUME = 0x38, 65*7979b1cfSJérôme Duval AC97_SPDIF_CONTROL = 0x3A, 66*7979b1cfSJérôme Duval 67*7979b1cfSJérôme Duval /* Vendor ID */ 68*7979b1cfSJérôme Duval AC97_VENDOR_ID1 = 0x7C, 69*7979b1cfSJérôme Duval AC97_VENDOR_ID2 = 0x7E, 70*7979b1cfSJérôme Duval 71*7979b1cfSJérôme Duval /* Analog Devices */ 72*7979b1cfSJérôme Duval AC97_AD_JACK_SENSE = 0x72, 73*7979b1cfSJérôme Duval AC97_AD_SERIAL_CONFIG = 0x74, 74*7979b1cfSJérôme Duval AC97_AD_MISC_CONTROL = 0x76, 75*7979b1cfSJérôme Duval AC97_AD_SAMPLE_RATE_0 = 0x78, 76*7979b1cfSJérôme Duval AC97_AD_SAMPLE_RATE_1 = 0x7a, 77*7979b1cfSJérôme Duval 78*7979b1cfSJérôme Duval /* Realtek ALC650 */ 79*7979b1cfSJérôme Duval AC97_ALC650_SPDIF_INPUT_CHAN_STATUS_LO = 0x60, /* only ALC650 Rev. E and later */ 80*7979b1cfSJérôme Duval AC97_ALC650_SPDIF_INPUT_CHAN_STATUS_HI = 0x62, /* only ALC650 Rev. E and later */ 81*7979b1cfSJérôme Duval AC97_ALC650_SURR_VOLUME = 0x64, 82*7979b1cfSJérôme Duval AC97_ALC650_CEN_LFE_VOLUME = 0x66, 83*7979b1cfSJérôme Duval AC97_ALC650_MULTI_CHAN_CTRL = 0x6A, 84*7979b1cfSJérôme Duval AC97_ALC650_MISC_CONTROL = 0x74, 85*7979b1cfSJérôme Duval AC97_ALC650_GPIO_SETUP = 0x76, 86*7979b1cfSJérôme Duval AC97_ALC650_GPIO_STATUS = 0x78, 87*7979b1cfSJérôme Duval AC97_ALC650_CLOCK_SOURCE = 0x7A 88*7979b1cfSJérôme Duval }; 89*7979b1cfSJérôme Duval 90*7979b1cfSJérôme Duval // AC97_EXTENDED_ID bits 91*7979b1cfSJérôme Duval enum { 92*7979b1cfSJérôme Duval EXID_VRA = 0x0001, 93*7979b1cfSJérôme Duval EXID_DRA = 0x0002, 94*7979b1cfSJérôme Duval EXID_SPDIF = 0x0004, 95*7979b1cfSJérôme Duval EXID_VRM = 0x0008, 96*7979b1cfSJérôme Duval EXID_DSA0 = 0x0010, 97*7979b1cfSJérôme Duval EXID_DSA1 = 0x0020, 98*7979b1cfSJérôme Duval EXID_CDAC = 0x0040, 99*7979b1cfSJérôme Duval EXID_SDAC = 0x0080, 100*7979b1cfSJérôme Duval EXID_LDAC = 0x0100, 101*7979b1cfSJérôme Duval EXID_AMAP = 0x0200, 102*7979b1cfSJérôme Duval EXID_REV0 = 0x0400, 103*7979b1cfSJérôme Duval EXID_REV1 = 0x0800, 104*7979b1cfSJérôme Duval EXID_bit12 = 0x1000, 105*7979b1cfSJérôme Duval EXID_bit13 = 0x2000, 106*7979b1cfSJérôme Duval EXID_ID0 = 0x4000, 107*7979b1cfSJérôme Duval EXID_ID1 = 0x8000 108*7979b1cfSJérôme Duval }; 109*7979b1cfSJérôme Duval 110*7979b1cfSJérôme Duval // some codec_ids 111*7979b1cfSJérôme Duval enum { 112*7979b1cfSJérôme Duval CODEC_ID_ALC201A = 0x414c4710, 113*7979b1cfSJérôme Duval CODEC_ID_AK4540 = 0x414b4d00, 114*7979b1cfSJérôme Duval CODEC_ID_AK4542 = 0x414b4d01, 115*7979b1cfSJérôme Duval CODEC_ID_AK4543 = 0x414b4d02, 116*7979b1cfSJérôme Duval CODEC_ID_AD1819 = 0x41445303, // ok, AD1819A, AD1819B 117*7979b1cfSJérôme Duval CODEC_ID_AD1881 = 0x41445340, // ok, AD1881 118*7979b1cfSJérôme Duval CODEC_ID_AD1881A = 0x41445348, // ok, AD1881A 119*7979b1cfSJérôme Duval CODEC_ID_AD1885 = 0x41445360, // ok, AD1885 120*7979b1cfSJérôme Duval CODEC_ID_AD1886 = 0x41445361, // ok, AD1886 121*7979b1cfSJérôme Duval CODEC_ID_AD1886A = 0x41445363, // ok, AD1886A 122*7979b1cfSJérôme Duval CODEC_ID_AD1887 = 0x41445362, // ok, AD1887 123*7979b1cfSJérôme Duval CODEC_ID_AD1888 = 0x41445368, // ok, AD1888 124*7979b1cfSJérôme Duval CODEC_ID_AD1980 = 0x41445370, // ok, AD1980 125*7979b1cfSJérôme Duval CODEC_ID_AD1981B = 0x41445374, // ok, AD1981B 126*7979b1cfSJérôme Duval CODEC_ID_AD1985 = 0x41445375, // ok, AD1985 127*7979b1cfSJérôme Duval CODEC_ID_AD1986 = 0x41445378, // ok, AD1986 128*7979b1cfSJérôme Duval CODEC_ID_CS4299A = 0x43525931, 129*7979b1cfSJérôme Duval CODEC_ID_CS4299C = 0x43525933, 130*7979b1cfSJérôme Duval CODEC_ID_CS4299D = 0x43525934, 131*7979b1cfSJérôme Duval CODEC_ID_STAC9700 = 0x83847600, // ok, STAC9700 132*7979b1cfSJérôme Duval CODEC_ID_STAC9704 = 0x83847604, // STAC9701/03, STAC9704/07, STAC9705 (???) 133*7979b1cfSJérôme Duval CODEC_ID_STAC9705 = 0x83847605, // ??? 134*7979b1cfSJérôme Duval CODEC_ID_STAC9708 = 0x83847608, // ok, STAC9708/11 135*7979b1cfSJérôme Duval CODEC_ID_STAC9721 = 0x83847609, // ok, STAC9721/23 136*7979b1cfSJérôme Duval CODEC_ID_STAC9744 = 0x83847644, // ok, STAC9744 137*7979b1cfSJérôme Duval CODEC_ID_STAC9752 = 0x83847652, // ok, STAC9752/53 138*7979b1cfSJérôme Duval CODEC_ID_STAC9756 = 0x83847656, // ok, STAC9756/57 139*7979b1cfSJérôme Duval CODEC_ID_STAC9766 = 0x83847666, // ok, STAC9766/67 140*7979b1cfSJérôme Duval }; 141*7979b1cfSJérôme Duval 142*7979b1cfSJérôme Duval // capabilities 143*7979b1cfSJérôme Duval enum ac97_capability { 144*7979b1cfSJérôme Duval CAP_PCM_MIC = 0x0000000000000001ULL, /* dedicated mic PCM channel */ 145*7979b1cfSJérôme Duval CAP_BASS_TREBLE_CTRL = 0x0000000000000002ULL, 146*7979b1cfSJérôme Duval CAP_SIMULATED_STEREO = 0x0000000000000004ULL, 147*7979b1cfSJérôme Duval CAP_HEADPHONE_OUT = 0x0000000000000008ULL, 148*7979b1cfSJérôme Duval CAP_LAUDNESS = 0x0000000000000010ULL, 149*7979b1cfSJérôme Duval CAP_DAC_18BIT = 0x0000000000000020ULL, 150*7979b1cfSJérôme Duval CAP_DAC_20BIT = 0x0000000000000040ULL, 151*7979b1cfSJérôme Duval CAP_ADC_18BIT = 0x0000000000000080ULL, 152*7979b1cfSJérôme Duval CAP_ADC_20BIT = 0x0000000000000100ULL, 153*7979b1cfSJérôme Duval CAP_3D_ENHANCEMENT = 0x0000000000000200ULL, 154*7979b1cfSJérôme Duval CAP_VARIABLE_PCM = 0x0000000000000400ULL, /* variable rate PCM */ 155*7979b1cfSJérôme Duval CAP_DOUBLE_PCM = 0x0000000000000800ULL, /* double rate PCM */ 156*7979b1cfSJérôme Duval CAP_SPDIF = 0x0000000000001000ULL, 157*7979b1cfSJérôme Duval CAP_VARIABLE_MIC = 0x0000000000002000ULL, /* variable rate mic PCM */ 158*7979b1cfSJérôme Duval CAP_CENTER_DAC = 0x0000000000004000ULL, 159*7979b1cfSJérôme Duval CAP_SURR_DAC = 0x0000000000008000ULL, 160*7979b1cfSJérôme Duval CAP_LFE_DAC = 0x0000000000010000ULL, 161*7979b1cfSJérôme Duval CAP_AMAP = 0x0000000000020000ULL, 162*7979b1cfSJérôme Duval CAP_REV21 = 0x0000000000040000ULL, 163*7979b1cfSJérôme Duval CAP_REV22 = 0x0000000000080000ULL, 164*7979b1cfSJérôme Duval CAP_REV23 = 0x0000000000100000ULL, 165*7979b1cfSJérôme Duval CAP_PCM_RATE_CONTINUOUS = 0x0000000000200000ULL, 166*7979b1cfSJérôme Duval CAP_PCM_RATE_8000 = 0x0000000000400000ULL, 167*7979b1cfSJérôme Duval CAP_PCM_RATE_11025 = 0x0000000000800000ULL, 168*7979b1cfSJérôme Duval CAP_PCM_RATE_12000 = 0x0000000001000000ULL, 169*7979b1cfSJérôme Duval CAP_PCM_RATE_16000 = 0x0000000002000000ULL, 170*7979b1cfSJérôme Duval CAP_PCM_RATE_22050 = 0x0000000004000000ULL, 171*7979b1cfSJérôme Duval CAP_PCM_RATE_24000 = 0x0000000008000000ULL, 172*7979b1cfSJérôme Duval CAP_PCM_RATE_32000 = 0x0000000010000000ULL, 173*7979b1cfSJérôme Duval CAP_PCM_RATE_44100 = 0x0000000020000000ULL, 174*7979b1cfSJérôme Duval CAP_PCM_RATE_48000 = 0x0000000040000000ULL, 175*7979b1cfSJérôme Duval CAP_PCM_RATE_88200 = 0x0000000080000000ULL, 176*7979b1cfSJérôme Duval CAP_PCM_RATE_96000 = 0x0000000100000000ULL, 177*7979b1cfSJérôme Duval CAP_PCM_RATE_MASK = ( CAP_PCM_RATE_CONTINUOUS | CAP_PCM_RATE_8000 | CAP_PCM_RATE_11025 | 178*7979b1cfSJérôme Duval CAP_PCM_RATE_12000 | CAP_PCM_RATE_16000 | CAP_PCM_RATE_22050 | 179*7979b1cfSJérôme Duval CAP_PCM_RATE_24000 | CAP_PCM_RATE_32000 | CAP_PCM_RATE_44100 | 180*7979b1cfSJérôme Duval CAP_PCM_RATE_48000 | CAP_PCM_RATE_88200 | CAP_PCM_RATE_96000) 181*7979b1cfSJérôme Duval }; 182*7979b1cfSJérôme Duval 183*7979b1cfSJérôme Duval struct ac97_dev; 184*7979b1cfSJérôme Duval typedef struct ac97_dev ac97_dev; 185*7979b1cfSJérôme Duval 186*7979b1cfSJérôme Duval typedef void (* codec_init)(ac97_dev * dev); 187*7979b1cfSJérôme Duval typedef uint16 (* codec_reg_read)(void * cookie, uint8 reg); 188*7979b1cfSJérôme Duval typedef void (* codec_reg_write)(void * cookie, uint8 reg, uint16 value); 189*7979b1cfSJérôme Duval typedef bool (* codec_set_rate)(ac97_dev *dev, uint8 reg, uint32 rate); 190*7979b1cfSJérôme Duval typedef bool (* codec_get_rate)(ac97_dev *dev, uint8 reg, uint32 *rate); 191*7979b1cfSJérôme Duval 192*7979b1cfSJérôme Duval struct ac97_dev { 193*7979b1cfSJérôme Duval uint16 reg_cache[0x7f]; 194*7979b1cfSJérôme Duval 195*7979b1cfSJérôme Duval void * cookie; 196*7979b1cfSJérôme Duval 197*7979b1cfSJérôme Duval uint32 codec_id; 198*7979b1cfSJérôme Duval const char * codec_info; 199*7979b1cfSJérôme Duval const char * codec_3d_stereo_enhancement; 200*7979b1cfSJérôme Duval 201*7979b1cfSJérôme Duval codec_init init; 202*7979b1cfSJérôme Duval codec_reg_read reg_read; 203*7979b1cfSJérôme Duval codec_reg_write reg_write; 204*7979b1cfSJérôme Duval codec_set_rate set_rate; 205*7979b1cfSJérôme Duval codec_get_rate get_rate; 206*7979b1cfSJérôme Duval 207*7979b1cfSJérôme Duval uint32 max_vsr; 208*7979b1cfSJérôme Duval uint32 min_vsr; 209*7979b1cfSJérôme Duval uint32 clock; 210*7979b1cfSJérôme Duval uint64 capabilities; 211*7979b1cfSJérôme Duval bool reversed_eamp_polarity; 212*7979b1cfSJérôme Duval uint32 subsystem; 213*7979b1cfSJérôme Duval }; 214*7979b1cfSJérôme Duval 215*7979b1cfSJérôme Duval #ifdef __cplusplus 216*7979b1cfSJérôme Duval extern "C" { 217*7979b1cfSJérôme Duval #endif 218*7979b1cfSJérôme Duval 219*7979b1cfSJérôme Duval void ac97_attach(ac97_dev **dev, codec_reg_read reg_read, codec_reg_write reg_write, void *cookie, 220*7979b1cfSJérôme Duval ushort subvendor_id, ushort subsystem_id); 221*7979b1cfSJérôme Duval void ac97_detach(ac97_dev *dev); 222*7979b1cfSJérôme Duval void ac97_suspend(ac97_dev *dev); 223*7979b1cfSJérôme Duval void ac97_resume(ac97_dev *dev); 224*7979b1cfSJérôme Duval 225*7979b1cfSJérôme Duval void ac97_reg_cached_write(ac97_dev *dev, uint8 reg, uint16 value); 226*7979b1cfSJérôme Duval uint16 ac97_reg_cached_read(ac97_dev *dev, uint8 reg); 227*7979b1cfSJérôme Duval void ac97_reg_uncached_write(ac97_dev *dev, uint8 reg, uint16 value); 228*7979b1cfSJérôme Duval uint16 ac97_reg_uncached_read(ac97_dev *dev, uint8 reg); 229*7979b1cfSJérôme Duval 230*7979b1cfSJérôme Duval bool ac97_reg_update(ac97_dev *dev, uint8 reg, uint16 value); 231*7979b1cfSJérôme Duval bool ac97_reg_update_bits(ac97_dev *dev, uint8 reg, uint16 mask, uint16 value); 232*7979b1cfSJérôme Duval 233*7979b1cfSJérôme Duval bool ac97_set_rate(ac97_dev *dev, uint8 reg, uint32 rate); 234*7979b1cfSJérôme Duval bool ac97_get_rate(ac97_dev *dev, uint8 reg, uint32 *rate); 235*7979b1cfSJérôme Duval 236*7979b1cfSJérôme Duval bool ac97_has_capability(ac97_dev *dev, uint64 cap); 237*7979b1cfSJérôme Duval 238*7979b1cfSJérôme Duval void ac97_set_clock(ac97_dev *dev, uint32 clock); 239*7979b1cfSJérôme Duval 240*7979b1cfSJérôme Duval #ifdef __cplusplus 241*7979b1cfSJérôme Duval } 242*7979b1cfSJérôme Duval #endif 243*7979b1cfSJérôme Duval 244*7979b1cfSJérôme Duval // multi support 245*7979b1cfSJérôme Duval 246*7979b1cfSJérôme Duval typedef enum { 247*7979b1cfSJérôme Duval B_MIX_GAIN = 1 << 0, 248*7979b1cfSJérôme Duval B_MIX_MUTE = 1 << 1, 249*7979b1cfSJérôme Duval B_MIX_MONO = 1 << 2, 250*7979b1cfSJérôme Duval B_MIX_STEREO = 1 << 3, 251*7979b1cfSJérôme Duval B_MIX_MUX = 1 << 4, 252*7979b1cfSJérôme Duval B_MIX_MICBOOST = 1 << 5, 253*7979b1cfSJérôme Duval B_MIX_RECORDMUX = 1 << 6 254*7979b1cfSJérôme Duval } ac97_mixer_type; 255*7979b1cfSJérôme Duval 256*7979b1cfSJérôme Duval typedef struct _ac97_source_info { 257*7979b1cfSJérôme Duval const char *name; 258*7979b1cfSJérôme Duval ac97_mixer_type type; 259*7979b1cfSJérôme Duval 260*7979b1cfSJérôme Duval int32 id; 261*7979b1cfSJérôme Duval uint8 reg; 262*7979b1cfSJérôme Duval uint16 default_value; 263*7979b1cfSJérôme Duval uint8 bits:3; 264*7979b1cfSJérôme Duval uint8 ofs:4; 265*7979b1cfSJérôme Duval uint8 mute:1; 266*7979b1cfSJérôme Duval uint8 polarity:1; // max_gain -> 0 267*7979b1cfSJérôme Duval float min_gain; 268*7979b1cfSJérôme Duval float max_gain; 269*7979b1cfSJérôme Duval float granularity; 270*7979b1cfSJérôme Duval } ac97_source_info; 271*7979b1cfSJérôme Duval 272*7979b1cfSJérôme Duval extern const ac97_source_info source_info[]; 273*7979b1cfSJérôme Duval extern const int32 source_info_size; 274*7979b1cfSJérôme Duval 275*7979b1cfSJérôme Duval #endif 276