17979b1cfSJérôme Duval /* 27979b1cfSJérôme Duval * AC97 interface 37979b1cfSJérôme Duval * 47979b1cfSJérôme Duval * Copyright (c) 2002, Marcus Overhagen <marcus@overhagen.de> 57979b1cfSJérôme Duval * Copyright (c) 2008, Jérôme Duval 67979b1cfSJérôme Duval * 77979b1cfSJérôme Duval * All rights reserved. 87979b1cfSJérôme Duval * Redistribution and use in source and binary forms, with or without modification, 97979b1cfSJérôme Duval * are permitted provided that the following conditions are met: 107979b1cfSJérôme Duval * 117979b1cfSJérôme Duval * - Redistributions of source code must retain the above copyright notice, 127979b1cfSJérôme Duval * this list of conditions and the following disclaimer. 137979b1cfSJérôme Duval * - Redistributions in binary form must reproduce the above copyright notice, 147979b1cfSJérôme Duval * this list of conditions and the following disclaimer in the documentation 157979b1cfSJérôme Duval * and/or other materials provided with the distribution. 167979b1cfSJérôme Duval * 177979b1cfSJérôme Duval * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 187979b1cfSJérôme Duval * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 197979b1cfSJérôme Duval * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 207979b1cfSJérôme Duval * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 217979b1cfSJérôme Duval * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 227979b1cfSJérôme Duval * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 237979b1cfSJérôme Duval * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 247979b1cfSJérôme Duval * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 257979b1cfSJérôme Duval * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 267979b1cfSJérôme Duval * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 277979b1cfSJérôme Duval * 287979b1cfSJérôme Duval */ 297979b1cfSJérôme Duval #ifndef _AC97_H_ 307979b1cfSJérôme Duval #define _AC97_H_ 317979b1cfSJérôme Duval 327979b1cfSJérôme Duval enum AC97_REGISTER { 337979b1cfSJérôme Duval /* Baseline audio register set */ 347979b1cfSJérôme Duval AC97_RESET = 0x00, 357979b1cfSJérôme Duval AC97_MASTER_VOLUME = 0x02, 367979b1cfSJérôme Duval AC97_AUX_OUT_VOLUME = 0x04, 377979b1cfSJérôme Duval AC97_MONO_VOLUME = 0x06, 387979b1cfSJérôme Duval AC97_MASTER_TONE = 0x08, 397979b1cfSJérôme Duval AC97_PC_BEEP_VOLUME = 0x0A, 407979b1cfSJérôme Duval AC97_PHONE_VOLUME = 0x0C, 417979b1cfSJérôme Duval AC97_MIC_VOLUME = 0x0E, 427979b1cfSJérôme Duval AC97_LINE_IN_VOLUME = 0x10, 437979b1cfSJérôme Duval AC97_CD_VOLUME = 0x12, 447979b1cfSJérôme Duval AC97_VIDEO_VOLUME = 0x14, 457979b1cfSJérôme Duval AC97_AUX_IN_VOLUME = 0x16, 467979b1cfSJérôme Duval AC97_PCM_OUT_VOLUME = 0x18, 477979b1cfSJérôme Duval AC97_RECORD_SELECT = 0x1A, 487979b1cfSJérôme Duval AC97_RECORD_GAIN = 0x1C, 497979b1cfSJérôme Duval AC97_RECORD_GAIN_MIC = 0x1E, 507979b1cfSJérôme Duval AC97_GENERAL_PURPOSE = 0x20, 517979b1cfSJérôme Duval AC97_3D_CONTROL = 0x22, 527979b1cfSJérôme Duval AC97_PAGING = 0x24, 537979b1cfSJérôme Duval AC97_POWERDOWN = 0x26, 547979b1cfSJérôme Duval 557979b1cfSJérôme Duval /* Extended audio register set */ 567979b1cfSJérôme Duval AC97_EXTENDED_ID = 0x28, 577979b1cfSJérôme Duval AC97_EXTENDED_STAT_CTRL = 0x2A, 587979b1cfSJérôme Duval AC97_PCM_FRONT_DAC_RATE = 0x2C, 597979b1cfSJérôme Duval AC97_PCM_SURR_DAC_RATE = 0x2E, 607979b1cfSJérôme Duval AC97_PCM_LFE_DAC_RATE = 0x30, 617979b1cfSJérôme Duval AC97_PCM_L_R_ADC_RATE = 0x32, 627979b1cfSJérôme Duval AC97_MIC_ADC_RATE = 0x34, 637979b1cfSJérôme Duval AC97_CENTER_LFE_VOLUME = 0x36, 647979b1cfSJérôme Duval AC97_SURR_VOLUME = 0x38, 657979b1cfSJérôme Duval AC97_SPDIF_CONTROL = 0x3A, 667979b1cfSJérôme Duval 677979b1cfSJérôme Duval /* Vendor ID */ 687979b1cfSJérôme Duval AC97_VENDOR_ID1 = 0x7C, 697979b1cfSJérôme Duval AC97_VENDOR_ID2 = 0x7E, 707979b1cfSJérôme Duval 717979b1cfSJérôme Duval /* Analog Devices */ 727979b1cfSJérôme Duval AC97_AD_JACK_SENSE = 0x72, 737979b1cfSJérôme Duval AC97_AD_SERIAL_CONFIG = 0x74, 747979b1cfSJérôme Duval AC97_AD_MISC_CONTROL = 0x76, 757979b1cfSJérôme Duval AC97_AD_SAMPLE_RATE_0 = 0x78, 767979b1cfSJérôme Duval AC97_AD_SAMPLE_RATE_1 = 0x7a, 777979b1cfSJérôme Duval 787979b1cfSJérôme Duval /* Realtek ALC650 */ 797979b1cfSJérôme Duval AC97_ALC650_SPDIF_INPUT_CHAN_STATUS_LO = 0x60, /* only ALC650 Rev. E and later */ 807979b1cfSJérôme Duval AC97_ALC650_SPDIF_INPUT_CHAN_STATUS_HI = 0x62, /* only ALC650 Rev. E and later */ 817979b1cfSJérôme Duval AC97_ALC650_SURR_VOLUME = 0x64, 827979b1cfSJérôme Duval AC97_ALC650_CEN_LFE_VOLUME = 0x66, 837979b1cfSJérôme Duval AC97_ALC650_MULTI_CHAN_CTRL = 0x6A, 847979b1cfSJérôme Duval AC97_ALC650_MISC_CONTROL = 0x74, 857979b1cfSJérôme Duval AC97_ALC650_GPIO_SETUP = 0x76, 867979b1cfSJérôme Duval AC97_ALC650_GPIO_STATUS = 0x78, 877979b1cfSJérôme Duval AC97_ALC650_CLOCK_SOURCE = 0x7A 887979b1cfSJérôme Duval }; 897979b1cfSJérôme Duval 907979b1cfSJérôme Duval // AC97_EXTENDED_ID bits 917979b1cfSJérôme Duval enum { 927979b1cfSJérôme Duval EXID_VRA = 0x0001, 937979b1cfSJérôme Duval EXID_DRA = 0x0002, 947979b1cfSJérôme Duval EXID_SPDIF = 0x0004, 957979b1cfSJérôme Duval EXID_VRM = 0x0008, 967979b1cfSJérôme Duval EXID_DSA0 = 0x0010, 977979b1cfSJérôme Duval EXID_DSA1 = 0x0020, 987979b1cfSJérôme Duval EXID_CDAC = 0x0040, 997979b1cfSJérôme Duval EXID_SDAC = 0x0080, 1007979b1cfSJérôme Duval EXID_LDAC = 0x0100, 1017979b1cfSJérôme Duval EXID_AMAP = 0x0200, 1027979b1cfSJérôme Duval EXID_REV0 = 0x0400, 1037979b1cfSJérôme Duval EXID_REV1 = 0x0800, 1047979b1cfSJérôme Duval EXID_bit12 = 0x1000, 1057979b1cfSJérôme Duval EXID_bit13 = 0x2000, 1067979b1cfSJérôme Duval EXID_ID0 = 0x4000, 1077979b1cfSJérôme Duval EXID_ID1 = 0x8000 1087979b1cfSJérôme Duval }; 1097979b1cfSJérôme Duval 1107979b1cfSJérôme Duval // some codec_ids 1117979b1cfSJérôme Duval enum { 1127979b1cfSJérôme Duval CODEC_ID_ALC201A = 0x414c4710, 1137979b1cfSJérôme Duval CODEC_ID_AK4540 = 0x414b4d00, 1147979b1cfSJérôme Duval CODEC_ID_AK4542 = 0x414b4d01, 1157979b1cfSJérôme Duval CODEC_ID_AK4543 = 0x414b4d02, 1167979b1cfSJérôme Duval CODEC_ID_AD1819 = 0x41445303, // ok, AD1819A, AD1819B 1177979b1cfSJérôme Duval CODEC_ID_AD1881 = 0x41445340, // ok, AD1881 1187979b1cfSJérôme Duval CODEC_ID_AD1881A = 0x41445348, // ok, AD1881A 1197979b1cfSJérôme Duval CODEC_ID_AD1885 = 0x41445360, // ok, AD1885 1207979b1cfSJérôme Duval CODEC_ID_AD1886 = 0x41445361, // ok, AD1886 1217979b1cfSJérôme Duval CODEC_ID_AD1886A = 0x41445363, // ok, AD1886A 1227979b1cfSJérôme Duval CODEC_ID_AD1887 = 0x41445362, // ok, AD1887 1237979b1cfSJérôme Duval CODEC_ID_AD1888 = 0x41445368, // ok, AD1888 1247979b1cfSJérôme Duval CODEC_ID_AD1980 = 0x41445370, // ok, AD1980 1257979b1cfSJérôme Duval CODEC_ID_AD1981B = 0x41445374, // ok, AD1981B 1267979b1cfSJérôme Duval CODEC_ID_AD1985 = 0x41445375, // ok, AD1985 1277979b1cfSJérôme Duval CODEC_ID_AD1986 = 0x41445378, // ok, AD1986 1287979b1cfSJérôme Duval CODEC_ID_CS4299A = 0x43525931, 1297979b1cfSJérôme Duval CODEC_ID_CS4299C = 0x43525933, 1307979b1cfSJérôme Duval CODEC_ID_CS4299D = 0x43525934, 1317979b1cfSJérôme Duval CODEC_ID_STAC9700 = 0x83847600, // ok, STAC9700 1327979b1cfSJérôme Duval CODEC_ID_STAC9704 = 0x83847604, // STAC9701/03, STAC9704/07, STAC9705 (???) 1337979b1cfSJérôme Duval CODEC_ID_STAC9705 = 0x83847605, // ??? 1347979b1cfSJérôme Duval CODEC_ID_STAC9708 = 0x83847608, // ok, STAC9708/11 1357979b1cfSJérôme Duval CODEC_ID_STAC9721 = 0x83847609, // ok, STAC9721/23 1367979b1cfSJérôme Duval CODEC_ID_STAC9744 = 0x83847644, // ok, STAC9744 137*fe2d4a0fSJérôme Duval CODEC_ID_STAC9750 = 0x83847650, // ok, STAC9750/51 1387979b1cfSJérôme Duval CODEC_ID_STAC9752 = 0x83847652, // ok, STAC9752/53 1397979b1cfSJérôme Duval CODEC_ID_STAC9756 = 0x83847656, // ok, STAC9756/57 140*fe2d4a0fSJérôme Duval CODEC_ID_STAC9758 = 0x83847658, // ????, STAC9758/59 1417979b1cfSJérôme Duval CODEC_ID_STAC9766 = 0x83847666, // ok, STAC9766/67 1427979b1cfSJérôme Duval }; 1437979b1cfSJérôme Duval 1447979b1cfSJérôme Duval // capabilities 1457979b1cfSJérôme Duval enum ac97_capability { 1467979b1cfSJérôme Duval CAP_PCM_MIC = 0x0000000000000001ULL, /* dedicated mic PCM channel */ 1477979b1cfSJérôme Duval CAP_BASS_TREBLE_CTRL = 0x0000000000000002ULL, 1487979b1cfSJérôme Duval CAP_SIMULATED_STEREO = 0x0000000000000004ULL, 1497979b1cfSJérôme Duval CAP_HEADPHONE_OUT = 0x0000000000000008ULL, 1507979b1cfSJérôme Duval CAP_LAUDNESS = 0x0000000000000010ULL, 1517979b1cfSJérôme Duval CAP_DAC_18BIT = 0x0000000000000020ULL, 1527979b1cfSJérôme Duval CAP_DAC_20BIT = 0x0000000000000040ULL, 1537979b1cfSJérôme Duval CAP_ADC_18BIT = 0x0000000000000080ULL, 1547979b1cfSJérôme Duval CAP_ADC_20BIT = 0x0000000000000100ULL, 1557979b1cfSJérôme Duval CAP_3D_ENHANCEMENT = 0x0000000000000200ULL, 1567979b1cfSJérôme Duval CAP_VARIABLE_PCM = 0x0000000000000400ULL, /* variable rate PCM */ 1577979b1cfSJérôme Duval CAP_DOUBLE_PCM = 0x0000000000000800ULL, /* double rate PCM */ 1587979b1cfSJérôme Duval CAP_SPDIF = 0x0000000000001000ULL, 1597979b1cfSJérôme Duval CAP_VARIABLE_MIC = 0x0000000000002000ULL, /* variable rate mic PCM */ 1607979b1cfSJérôme Duval CAP_CENTER_DAC = 0x0000000000004000ULL, 1617979b1cfSJérôme Duval CAP_SURR_DAC = 0x0000000000008000ULL, 1627979b1cfSJérôme Duval CAP_LFE_DAC = 0x0000000000010000ULL, 1637979b1cfSJérôme Duval CAP_AMAP = 0x0000000000020000ULL, 1647979b1cfSJérôme Duval CAP_REV21 = 0x0000000000040000ULL, 1657979b1cfSJérôme Duval CAP_REV22 = 0x0000000000080000ULL, 1667979b1cfSJérôme Duval CAP_REV23 = 0x0000000000100000ULL, 1677979b1cfSJérôme Duval CAP_PCM_RATE_CONTINUOUS = 0x0000000000200000ULL, 1687979b1cfSJérôme Duval CAP_PCM_RATE_8000 = 0x0000000000400000ULL, 1697979b1cfSJérôme Duval CAP_PCM_RATE_11025 = 0x0000000000800000ULL, 1707979b1cfSJérôme Duval CAP_PCM_RATE_12000 = 0x0000000001000000ULL, 1717979b1cfSJérôme Duval CAP_PCM_RATE_16000 = 0x0000000002000000ULL, 1727979b1cfSJérôme Duval CAP_PCM_RATE_22050 = 0x0000000004000000ULL, 1737979b1cfSJérôme Duval CAP_PCM_RATE_24000 = 0x0000000008000000ULL, 1747979b1cfSJérôme Duval CAP_PCM_RATE_32000 = 0x0000000010000000ULL, 1757979b1cfSJérôme Duval CAP_PCM_RATE_44100 = 0x0000000020000000ULL, 1767979b1cfSJérôme Duval CAP_PCM_RATE_48000 = 0x0000000040000000ULL, 1777979b1cfSJérôme Duval CAP_PCM_RATE_88200 = 0x0000000080000000ULL, 1787979b1cfSJérôme Duval CAP_PCM_RATE_96000 = 0x0000000100000000ULL, 1797979b1cfSJérôme Duval CAP_PCM_RATE_MASK = ( CAP_PCM_RATE_CONTINUOUS | CAP_PCM_RATE_8000 | CAP_PCM_RATE_11025 | 1807979b1cfSJérôme Duval CAP_PCM_RATE_12000 | CAP_PCM_RATE_16000 | CAP_PCM_RATE_22050 | 1817979b1cfSJérôme Duval CAP_PCM_RATE_24000 | CAP_PCM_RATE_32000 | CAP_PCM_RATE_44100 | 1827979b1cfSJérôme Duval CAP_PCM_RATE_48000 | CAP_PCM_RATE_88200 | CAP_PCM_RATE_96000) 1837979b1cfSJérôme Duval }; 1847979b1cfSJérôme Duval 1857979b1cfSJérôme Duval struct ac97_dev; 1867979b1cfSJérôme Duval typedef struct ac97_dev ac97_dev; 1877979b1cfSJérôme Duval 1887979b1cfSJérôme Duval typedef void (* codec_init)(ac97_dev * dev); 1897979b1cfSJérôme Duval typedef uint16 (* codec_reg_read)(void * cookie, uint8 reg); 1907979b1cfSJérôme Duval typedef void (* codec_reg_write)(void * cookie, uint8 reg, uint16 value); 1917979b1cfSJérôme Duval typedef bool (* codec_set_rate)(ac97_dev *dev, uint8 reg, uint32 rate); 1927979b1cfSJérôme Duval typedef bool (* codec_get_rate)(ac97_dev *dev, uint8 reg, uint32 *rate); 1937979b1cfSJérôme Duval 1947979b1cfSJérôme Duval struct ac97_dev { 1957979b1cfSJérôme Duval uint16 reg_cache[0x7f]; 1967979b1cfSJérôme Duval 1977979b1cfSJérôme Duval void * cookie; 1987979b1cfSJérôme Duval 1997979b1cfSJérôme Duval uint32 codec_id; 2007979b1cfSJérôme Duval const char * codec_info; 2017979b1cfSJérôme Duval const char * codec_3d_stereo_enhancement; 2027979b1cfSJérôme Duval 2037979b1cfSJérôme Duval codec_init init; 2047979b1cfSJérôme Duval codec_reg_read reg_read; 2057979b1cfSJérôme Duval codec_reg_write reg_write; 2067979b1cfSJérôme Duval codec_set_rate set_rate; 2077979b1cfSJérôme Duval codec_get_rate get_rate; 2087979b1cfSJérôme Duval 2097979b1cfSJérôme Duval uint32 max_vsr; 2107979b1cfSJérôme Duval uint32 min_vsr; 2117979b1cfSJérôme Duval uint32 clock; 2127979b1cfSJérôme Duval uint64 capabilities; 2137979b1cfSJérôme Duval bool reversed_eamp_polarity; 2147979b1cfSJérôme Duval uint32 subsystem; 2157979b1cfSJérôme Duval }; 2167979b1cfSJérôme Duval 2177979b1cfSJérôme Duval #ifdef __cplusplus 2187979b1cfSJérôme Duval extern "C" { 2197979b1cfSJérôme Duval #endif 2207979b1cfSJérôme Duval 221*fe2d4a0fSJérôme Duval void ac97_attach(ac97_dev **dev, codec_reg_read reg_read, 222*fe2d4a0fSJérôme Duval codec_reg_write reg_write, void *cookie, ushort subvendor_id, 223*fe2d4a0fSJérôme Duval ushort subsystem_id); 2247979b1cfSJérôme Duval void ac97_detach(ac97_dev *dev); 2257979b1cfSJérôme Duval void ac97_suspend(ac97_dev *dev); 2267979b1cfSJérôme Duval void ac97_resume(ac97_dev *dev); 2277979b1cfSJérôme Duval 2287979b1cfSJérôme Duval void ac97_reg_cached_write(ac97_dev *dev, uint8 reg, uint16 value); 2297979b1cfSJérôme Duval uint16 ac97_reg_cached_read(ac97_dev *dev, uint8 reg); 2307979b1cfSJérôme Duval void ac97_reg_uncached_write(ac97_dev *dev, uint8 reg, uint16 value); 2317979b1cfSJérôme Duval uint16 ac97_reg_uncached_read(ac97_dev *dev, uint8 reg); 2327979b1cfSJérôme Duval 2337979b1cfSJérôme Duval bool ac97_reg_update(ac97_dev *dev, uint8 reg, uint16 value); 234*fe2d4a0fSJérôme Duval bool ac97_reg_update_bits(ac97_dev *dev, uint8 reg, uint16 mask, 235*fe2d4a0fSJérôme Duval uint16 value); 2367979b1cfSJérôme Duval 2377979b1cfSJérôme Duval bool ac97_set_rate(ac97_dev *dev, uint8 reg, uint32 rate); 2387979b1cfSJérôme Duval bool ac97_get_rate(ac97_dev *dev, uint8 reg, uint32 *rate); 2397979b1cfSJérôme Duval 2407979b1cfSJérôme Duval bool ac97_has_capability(ac97_dev *dev, uint64 cap); 2417979b1cfSJérôme Duval 2427979b1cfSJérôme Duval void ac97_set_clock(ac97_dev *dev, uint32 clock); 2437979b1cfSJérôme Duval 2447979b1cfSJérôme Duval #ifdef __cplusplus 2457979b1cfSJérôme Duval } 2467979b1cfSJérôme Duval #endif 2477979b1cfSJérôme Duval 2487979b1cfSJérôme Duval // multi support 2497979b1cfSJérôme Duval 2507979b1cfSJérôme Duval typedef enum { 2517979b1cfSJérôme Duval B_MIX_GAIN = 1 << 0, 2527979b1cfSJérôme Duval B_MIX_MUTE = 1 << 1, 2537979b1cfSJérôme Duval B_MIX_MONO = 1 << 2, 2547979b1cfSJérôme Duval B_MIX_STEREO = 1 << 3, 2557979b1cfSJérôme Duval B_MIX_MUX = 1 << 4, 2567979b1cfSJérôme Duval B_MIX_MICBOOST = 1 << 5, 2577979b1cfSJérôme Duval B_MIX_RECORDMUX = 1 << 6 2587979b1cfSJérôme Duval } ac97_mixer_type; 2597979b1cfSJérôme Duval 2607979b1cfSJérôme Duval typedef struct _ac97_source_info { 2617979b1cfSJérôme Duval const char *name; 2627979b1cfSJérôme Duval ac97_mixer_type type; 2637979b1cfSJérôme Duval 2647979b1cfSJérôme Duval int32 id; 2657979b1cfSJérôme Duval uint8 reg; 2667979b1cfSJérôme Duval uint16 default_value; 2677979b1cfSJérôme Duval uint8 bits:3; 2687979b1cfSJérôme Duval uint8 ofs:4; 2697979b1cfSJérôme Duval uint8 mute:1; 2707979b1cfSJérôme Duval uint8 polarity:1; // max_gain -> 0 2717979b1cfSJérôme Duval float min_gain; 2727979b1cfSJérôme Duval float max_gain; 2737979b1cfSJérôme Duval float granularity; 2747979b1cfSJérôme Duval } ac97_source_info; 2757979b1cfSJérôme Duval 2767979b1cfSJérôme Duval extern const ac97_source_info source_info[]; 2777979b1cfSJérôme Duval extern const int32 source_info_size; 2787979b1cfSJérôme Duval 2797979b1cfSJérôme Duval #endif 280