/*
* Copyright (c) by Jaroslav Kysela <perex@suse.cz>
* Universal interface for Audio Codec '97
*
* For more details look to AC '97 component specification revision 2.2
* by Intel Corporation (http://developer.intel.com).
*
*
* This program 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; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <sound/driver.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/pci.h>
#include <linux/moduleparam.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/ac97_codec.h>
#include <sound/asoundef.h>
#include <sound/initval.h>
#include "ac97_local.h"
#include "ac97_id.h"
#include "ac97_patch.h"
MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
MODULE_DESCRIPTION("Universal interface for Audio Codec '97");
MODULE_LICENSE("GPL");
static int enable_loopback;
module_param(enable_loopback, bool, 0444);
MODULE_PARM_DESC(enable_loopback, "Enable AC97 ADC/DAC Loopback Control");
/*
*/
typedef struct {
unsigned int id;
unsigned int mask;
const char *name;
int (*patch)(ac97_t *ac97);
int (*mpatch)(ac97_t *ac97);
} ac97_codec_id_t;
static const ac97_codec_id_t snd_ac97_codec_id_vendors[] = {
{ 0x414b4d00, 0xffffff00, "Asahi Kasei", NULL, NULL },
{ 0x41445300, 0xffffff00, "Analog Devices", NULL, NULL },
{ 0x414c4300, 0xffffff00, "Realtek", NULL, NULL },
{ 0x414c4700, 0xffffff00, "Realtek", NULL, NULL },
{ 0x434d4900, 0xffffff00, "C-Media Electronics", NULL, NULL },
{ 0x43525900, 0xffffff00, "Cirrus Logic", NULL, NULL },
{ 0x43585400, 0xffffff00, "Conexant", NULL, NULL },
{ 0x44543000, 0xffffff00, "Diamond Technology", NULL, NULL },
{ 0x454d4300, 0xffffff00, "eMicro", NULL, NULL },
{ 0x45838300, 0xffffff00, "ESS Technology", NULL, NULL },
{ 0x48525300, 0xffffff00, "Intersil", NULL, NULL },
{ 0x49434500, 0xffffff00, "ICEnsemble", NULL, NULL },
{ 0x49544500, 0xffffff00, "ITE Tech.Inc", NULL, NULL },
{ 0x4e534300, 0xffffff00, "National Semiconductor", NULL, NULL },
{ 0x50534300, 0xffffff00, "Philips", NULL, NULL },
{ 0x53494c00, 0xffffff00, "Silicon Laboratory", NULL, NULL },
{ 0x54524100, 0xffffff00, "TriTech", NULL, NULL },
{ 0x54584e00, 0xffffff00, "Texas Instruments", NULL, NULL },
{ 0x56494100, 0xffffff00, "VIA Technologies", NULL, NULL },
{ 0x57454300, 0xffffff00, "Winbond", NULL, NULL },
{ 0x574d4c00, 0xffffff00, "Wolfson", NULL, NULL },
{ 0x594d4800, 0xffffff00, "Yamaha", NULL, NULL },
{ 0x83847600, 0xffffff00, "SigmaTel", NULL, NULL },
{ 0, 0, NULL, NULL, NULL }
};
static const ac97_codec_id_t snd_ac97_codec_ids[] = {
{ 0x414b4d00, 0xffffffff, "AK4540", NULL, NULL },
{ 0x414b4d01, 0xffffffff, "AK4542", NULL, NULL },
{ 0x414b4d02, 0xffffffff, "AK4543", NULL, NULL },
{ 0x414b4d06, 0xffffffff, "AK4544A", NULL, NULL },
{ 0x414b4d07, 0xffffffff, "AK4545", NULL, NULL },
{ 0x41445303, 0xffffffff, "AD1819", patch_ad1819, NULL },
{ 0x41445340, 0xffffffff, "AD1881", patch_ad1881, NULL },
{ 0x41445348, 0xffffffff, "AD1881A", patch_ad1881, NULL },
{ 0x41445360, 0xffffffff, "AD1885", patch_ad1885, NULL },
{ 0x41445361, 0xffffffff, "AD1886", patch_ad1886, NULL },
{ 0x41445362, 0xffffffff, "AD1887", patch_ad1881, NULL },
{ 0x41445363, 0xffffffff, "AD1886A", patch_ad1881, NULL },
{ 0x41445368, 0xffffffff, "AD1888", patch_ad1888, NULL },
{ 0x41445370, 0xffffffff, "AD1980", patch_ad1980, NULL },
{ 0x41445372, 0xffffffff, "AD1981A", patch_ad1981a, NULL },
{ 0x41445374, 0xffffffff, "AD1981B", patch_ad1981b, NULL },
{ 0x41445375, 0xffffffff, "AD1985", patch_ad1985, NULL },
{ 0x414c4300, 0xffffff00, "ALC100/100P", NULL, NULL },
{ 0x414c4710, 0xfffffff0, "ALC200/200P", NULL, NULL },
{ 0x414c4721, 0xffffffff, "ALC650D", NULL, NULL }, /* already patched */
{ 0x414c4722, 0xffffffff, "ALC650E", NULL, NULL }, /* already patched */
{ 0x414c4723, 0xffffffff, "ALC650F", NULL, NULL }, /* already patched */
{ 0x414c4720, 0xfffffff0, "ALC650", patch_alc650, NULL },
{ 0x414c4760, 0xfffffff0, "ALC655", patch_alc655, NULL },
{ 0x414c4780, 0xfffffff0, "ALC658", patch_alc655, NULL },
{ 0x414c4790, 0xfffffff0, "ALC850", patch_alc850, NULL },
{ 0x414c4730, 0xffffffff, "ALC101", NULL, NULL },
{ 0x414c4740, 0xfffffff0, "ALC202", NULL, NULL },
{ 0x414c4750, 0xfffffff0, "ALC250", NULL, NULL },
{ 0x414c4770, 0xfffffff0, "ALC203", NULL, NULL },
{ 0x434d4941, 0xffffffff, "CMI9738", patch_cm9738, NULL },
{ 0x434d4961, 0xffffffff, "CMI9739", patch_cm9739, NULL },
{ 0x43525900, 0xfffffff8, "CS4297", NULL, NULL },
{ 0x43525910, 0xfffffff8, "CS4297A", patch_cirrus_spdif, NULL },
{ 0x43525920, 0xfffffff8, "CS4294/4298", NULL, NULL },
{ 0x43525928, 0xfffffff8, "CS4294", NULL, NULL },
{ 0x43525930, 0xfffffff8, "CS4299", patch_cirrus_cs4299, NULL },
{ 0x43525948, 0xfffffff8, "CS4201", NULL, NULL },
{ 0x43525958, 0xfffffff8, "CS4205", patch_cirrus_spdif, NULL },
{ 0x43525960, 0xfffffff8, "CS4291", NULL, NULL },
{ 0x43525970, 0xfffffff8, "CS4202", NULL, NULL },
{ 0x43585421, 0xffffffff, "HSD11246", NULL, NULL }, // SmartMC II
{ 0x43585428, 0xfffffff8, "Cx20468", patch_conexant, NULL }, // SmartAMC fixme: the mask might be different
{ 0x44543031, 0xfffffff0, "DT0398", NULL, NULL },
{ 0x454d4328, 0xffffffff, "28028", NULL, NULL }, // same as TR28028?
{ 0x45838308, 0xffffffff, "ESS1988", NULL, NULL },
{ 0x48525300, 0xffffff00, "HMP9701", NULL, NULL },
{ 0x49434501, 0xffffffff, "ICE1230", NULL, NULL },
{ 0x49434511, 0xffffffff, "ICE1232", NULL, NULL }, // alias VIA VT1611A?
{ 0x49434514, 0xffffffff, "ICE1232A", NULL, NULL },
{ 0x49434551, 0xffffffff, "VT1616", patch_vt1616, NULL },
{ 0x49434552, 0xffffffff, "VT1616i", patch_vt1616, NULL }, // VT1616 compatible (chipset integrated)
{ 0x49544520, 0xffffffff, "IT2226E", NULL, NULL },
{ 0x49544561, 0xffffffff, "IT2646E", patch_it2646, NULL },
{ 0x4e534300, 0xffffffff, "LM4540/43/45/46/48", NULL, NULL }, // only guess --jk
{ 0x4e534331, 0xffffffff, "LM4549", NULL, NULL },
{ 0x4e534350, 0xffffffff, "LM4550", NULL, NULL },
{ 0x50534304, 0xffffffff, "UCB1400", NULL, NULL },
{ 0x53494c20, 0xffffffe0, "Si3036/8", NULL, mpatch_si3036 },
{ 0x54524102, 0xffffffff, "TR28022", NULL, NULL },
{ 0x54524106, 0xffffffff, "TR28026", NULL, NULL },
{ 0x54524108, 0xffffffff, "TR28028", patch_tritech_tr28028, NULL }, // added by xin jin [07/09/99]
{ 0x54524123, 0xffffffff, "TR28602", NULL, NULL }, // only guess --jk [TR28023 = eMicro EM28023 (new CT1297)]
{ 0x54584e20, 0xffffffff, "TLC320AD9xC", NULL, NULL },
{ 0x56494161, 0xffffffff, "VIA1612A", NULL, NULL }, // modified ICE1232 with S/PDIF
{ 0x57454301, 0xffffffff, "W83971D", NULL, NULL },
{ 0x574d4c00, 0xffffffff, "WM9701A", NULL, NULL },
{ 0x574d4C03, 0xffffffff, "WM9703/WM9707/WM9708/WM9717", patch_wolfson03, NULL},
{ 0x574d4C04, 0xffffffff, "WM9704M/WM9704Q", patch_wolfson04, NULL},
{ 0x574d4C05, 0xffffffff, "WM9705/WM9710", patch_wolfson05, NULL},
{ 0x574d4C09, 0xffffffff, "WM9709", NULL, NULL},
{ 0x574d4C12, 0xffffffff, "WM9711/WM9712", patch_wolfson11, NULL},
{ 0x594d4800, 0xffffffff, "YMF743", NULL, NULL },
{ 0x594d4802, 0xffffffff, "YMF752", NULL, NULL },
{ 0x594d4803, 0xffffffff, "YMF753", patch_yamaha_ymf753, NULL },
{ 0x83847600, 0xffffffff, "STAC9700/83/84", patch_sigmatel_stac9700, NULL },
{ 0x83847604, 0xffffffff, "STAC9701/3/4/5", NULL, NULL },
{ 0x83