18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * ALSA driver for Intel ICH (i8x0) chipsets 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2000 Jaroslav Kysela <perex@perex.cz> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * This code also contains alpha support for SiS 735 chipsets provided 88c2ecf20Sopenharmony_ci * by Mike Pieper <mptei@users.sourceforge.net>. We have no datasheet 98c2ecf20Sopenharmony_ci * for SiS735, so the code is not fully functional. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/io.h> 158c2ecf20Sopenharmony_ci#include <linux/delay.h> 168c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 178c2ecf20Sopenharmony_ci#include <linux/init.h> 188c2ecf20Sopenharmony_ci#include <linux/pci.h> 198c2ecf20Sopenharmony_ci#include <linux/slab.h> 208c2ecf20Sopenharmony_ci#include <linux/module.h> 218c2ecf20Sopenharmony_ci#include <sound/core.h> 228c2ecf20Sopenharmony_ci#include <sound/pcm.h> 238c2ecf20Sopenharmony_ci#include <sound/ac97_codec.h> 248c2ecf20Sopenharmony_ci#include <sound/info.h> 258c2ecf20Sopenharmony_ci#include <sound/initval.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); 288c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Intel 82801AA,82901AB,i810,i820,i830,i840,i845,MX440; SiS 7012; Ali 5455"); 298c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 308c2ecf20Sopenharmony_ciMODULE_SUPPORTED_DEVICE("{{Intel,82801AA-ICH}," 318c2ecf20Sopenharmony_ci "{Intel,82901AB-ICH0}," 328c2ecf20Sopenharmony_ci "{Intel,82801BA-ICH2}," 338c2ecf20Sopenharmony_ci "{Intel,82801CA-ICH3}," 348c2ecf20Sopenharmony_ci "{Intel,82801DB-ICH4}," 358c2ecf20Sopenharmony_ci "{Intel,ICH5}," 368c2ecf20Sopenharmony_ci "{Intel,ICH6}," 378c2ecf20Sopenharmony_ci "{Intel,ICH7}," 388c2ecf20Sopenharmony_ci "{Intel,6300ESB}," 398c2ecf20Sopenharmony_ci "{Intel,ESB2}," 408c2ecf20Sopenharmony_ci "{Intel,MX440}," 418c2ecf20Sopenharmony_ci "{SiS,SI7012}," 428c2ecf20Sopenharmony_ci "{NVidia,nForce Audio}," 438c2ecf20Sopenharmony_ci "{NVidia,nForce2 Audio}," 448c2ecf20Sopenharmony_ci "{NVidia,nForce3 Audio}," 458c2ecf20Sopenharmony_ci "{NVidia,MCP04}," 468c2ecf20Sopenharmony_ci "{NVidia,MCP501}," 478c2ecf20Sopenharmony_ci "{NVidia,CK804}," 488c2ecf20Sopenharmony_ci "{NVidia,CK8}," 498c2ecf20Sopenharmony_ci "{NVidia,CK8S}," 508c2ecf20Sopenharmony_ci "{AMD,AMD768}," 518c2ecf20Sopenharmony_ci "{AMD,AMD8111}," 528c2ecf20Sopenharmony_ci "{ALI,M5455}}"); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */ 558c2ecf20Sopenharmony_cistatic char *id = SNDRV_DEFAULT_STR1; /* ID for this card */ 568c2ecf20Sopenharmony_cistatic int ac97_clock; 578c2ecf20Sopenharmony_cistatic char *ac97_quirk; 588c2ecf20Sopenharmony_cistatic bool buggy_semaphore; 598c2ecf20Sopenharmony_cistatic int buggy_irq = -1; /* auto-check */ 608c2ecf20Sopenharmony_cistatic bool xbox; 618c2ecf20Sopenharmony_cistatic int spdif_aclink = -1; 628c2ecf20Sopenharmony_cistatic int inside_vm = -1; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cimodule_param(index, int, 0444); 658c2ecf20Sopenharmony_ciMODULE_PARM_DESC(index, "Index value for Intel i8x0 soundcard."); 668c2ecf20Sopenharmony_cimodule_param(id, charp, 0444); 678c2ecf20Sopenharmony_ciMODULE_PARM_DESC(id, "ID string for Intel i8x0 soundcard."); 688c2ecf20Sopenharmony_cimodule_param(ac97_clock, int, 0444); 698c2ecf20Sopenharmony_ciMODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (0 = allowlist + auto-detect, 1 = force autodetect)."); 708c2ecf20Sopenharmony_cimodule_param(ac97_quirk, charp, 0444); 718c2ecf20Sopenharmony_ciMODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware."); 728c2ecf20Sopenharmony_cimodule_param(buggy_semaphore, bool, 0444); 738c2ecf20Sopenharmony_ciMODULE_PARM_DESC(buggy_semaphore, "Enable workaround for hardwares with problematic codec semaphores."); 748c2ecf20Sopenharmony_cimodule_param(buggy_irq, bint, 0444); 758c2ecf20Sopenharmony_ciMODULE_PARM_DESC(buggy_irq, "Enable workaround for buggy interrupts on some motherboards."); 768c2ecf20Sopenharmony_cimodule_param(xbox, bool, 0444); 778c2ecf20Sopenharmony_ciMODULE_PARM_DESC(xbox, "Set to 1 for Xbox, if you have problems with the AC'97 codec detection."); 788c2ecf20Sopenharmony_cimodule_param(spdif_aclink, int, 0444); 798c2ecf20Sopenharmony_ciMODULE_PARM_DESC(spdif_aclink, "S/PDIF over AC-link."); 808c2ecf20Sopenharmony_cimodule_param(inside_vm, bint, 0444); 818c2ecf20Sopenharmony_ciMODULE_PARM_DESC(inside_vm, "KVM/Parallels optimization."); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci/* just for backward compatibility */ 848c2ecf20Sopenharmony_cistatic bool enable; 858c2ecf20Sopenharmony_cimodule_param(enable, bool, 0444); 868c2ecf20Sopenharmony_cistatic int joystick; 878c2ecf20Sopenharmony_cimodule_param(joystick, int, 0444); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci/* 908c2ecf20Sopenharmony_ci * Direct registers 918c2ecf20Sopenharmony_ci */ 928c2ecf20Sopenharmony_cienum { DEVICE_INTEL, DEVICE_INTEL_ICH4, DEVICE_SIS, DEVICE_ALI, DEVICE_NFORCE }; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci#define ICHREG(x) ICH_REG_##x 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci#define DEFINE_REGSET(name,base) \ 978c2ecf20Sopenharmony_cienum { \ 988c2ecf20Sopenharmony_ci ICH_REG_##name##_BDBAR = base + 0x0, /* dword - buffer descriptor list base address */ \ 998c2ecf20Sopenharmony_ci ICH_REG_##name##_CIV = base + 0x04, /* byte - current index value */ \ 1008c2ecf20Sopenharmony_ci ICH_REG_##name##_LVI = base + 0x05, /* byte - last valid index */ \ 1018c2ecf20Sopenharmony_ci ICH_REG_##name##_SR = base + 0x06, /* byte - status register */ \ 1028c2ecf20Sopenharmony_ci ICH_REG_##name##_PICB = base + 0x08, /* word - position in current buffer */ \ 1038c2ecf20Sopenharmony_ci ICH_REG_##name##_PIV = base + 0x0a, /* byte - prefetched index value */ \ 1048c2ecf20Sopenharmony_ci ICH_REG_##name##_CR = base + 0x0b, /* byte - control register */ \ 1058c2ecf20Sopenharmony_ci}; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci/* busmaster blocks */ 1088c2ecf20Sopenharmony_ciDEFINE_REGSET(OFF, 0); /* offset */ 1098c2ecf20Sopenharmony_ciDEFINE_REGSET(PI, 0x00); /* PCM in */ 1108c2ecf20Sopenharmony_ciDEFINE_REGSET(PO, 0x10); /* PCM out */ 1118c2ecf20Sopenharmony_ciDEFINE_REGSET(MC, 0x20); /* Mic in */ 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci/* ICH4 busmaster blocks */ 1148c2ecf20Sopenharmony_ciDEFINE_REGSET(MC2, 0x40); /* Mic in 2 */ 1158c2ecf20Sopenharmony_ciDEFINE_REGSET(PI2, 0x50); /* PCM in 2 */ 1168c2ecf20Sopenharmony_ciDEFINE_REGSET(SP, 0x60); /* SPDIF out */ 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci/* values for each busmaster block */ 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci/* LVI */ 1218c2ecf20Sopenharmony_ci#define ICH_REG_LVI_MASK 0x1f 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci/* SR */ 1248c2ecf20Sopenharmony_ci#define ICH_FIFOE 0x10 /* FIFO error */ 1258c2ecf20Sopenharmony_ci#define ICH_BCIS 0x08 /* buffer completion interrupt status */ 1268c2ecf20Sopenharmony_ci#define ICH_LVBCI 0x04 /* last valid buffer completion interrupt */ 1278c2ecf20Sopenharmony_ci#define ICH_CELV 0x02 /* current equals last valid */ 1288c2ecf20Sopenharmony_ci#define ICH_DCH 0x01 /* DMA controller halted */ 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci/* PIV */ 1318c2ecf20Sopenharmony_ci#define ICH_REG_PIV_MASK 0x1f /* mask */ 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci/* CR */ 1348c2ecf20Sopenharmony_ci#define ICH_IOCE 0x10 /* interrupt on completion enable */ 1358c2ecf20Sopenharmony_ci#define ICH_FEIE 0x08 /* fifo error interrupt enable */ 1368c2ecf20Sopenharmony_ci#define ICH_LVBIE 0x04 /* last valid buffer interrupt enable */ 1378c2ecf20Sopenharmony_ci#define ICH_RESETREGS 0x02 /* reset busmaster registers */ 1388c2ecf20Sopenharmony_ci#define ICH_STARTBM 0x01 /* start busmaster operation */ 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci/* global block */ 1428c2ecf20Sopenharmony_ci#define ICH_REG_GLOB_CNT 0x2c /* dword - global control */ 1438c2ecf20Sopenharmony_ci#define ICH_PCM_SPDIF_MASK 0xc0000000 /* s/pdif pcm slot mask (ICH4) */ 1448c2ecf20Sopenharmony_ci#define ICH_PCM_SPDIF_NONE 0x00000000 /* reserved - undefined */ 1458c2ecf20Sopenharmony_ci#define ICH_PCM_SPDIF_78 0x40000000 /* s/pdif pcm on slots 7&8 */ 1468c2ecf20Sopenharmony_ci#define ICH_PCM_SPDIF_69 0x80000000 /* s/pdif pcm on slots 6&9 */ 1478c2ecf20Sopenharmony_ci#define ICH_PCM_SPDIF_1011 0xc0000000 /* s/pdif pcm on slots 10&11 */ 1488c2ecf20Sopenharmony_ci#define ICH_PCM_20BIT 0x00400000 /* 20-bit samples (ICH4) */ 1498c2ecf20Sopenharmony_ci#define ICH_PCM_246_MASK 0x00300000 /* chan mask (not all chips) */ 1508c2ecf20Sopenharmony_ci#define ICH_PCM_8 0x00300000 /* 8 channels (not all chips) */ 1518c2ecf20Sopenharmony_ci#define ICH_PCM_6 0x00200000 /* 6 channels (not all chips) */ 1528c2ecf20Sopenharmony_ci#define ICH_PCM_4 0x00100000 /* 4 channels (not all chips) */ 1538c2ecf20Sopenharmony_ci#define ICH_PCM_2 0x00000000 /* 2 channels (stereo) */ 1548c2ecf20Sopenharmony_ci#define ICH_SIS_PCM_246_MASK 0x000000c0 /* 6 channels (SIS7012) */ 1558c2ecf20Sopenharmony_ci#define ICH_SIS_PCM_6 0x00000080 /* 6 channels (SIS7012) */ 1568c2ecf20Sopenharmony_ci#define ICH_SIS_PCM_4 0x00000040 /* 4 channels (SIS7012) */ 1578c2ecf20Sopenharmony_ci#define ICH_SIS_PCM_2 0x00000000 /* 2 channels (SIS7012) */ 1588c2ecf20Sopenharmony_ci#define ICH_TRIE 0x00000040 /* tertiary resume interrupt enable */ 1598c2ecf20Sopenharmony_ci#define ICH_SRIE 0x00000020 /* secondary resume interrupt enable */ 1608c2ecf20Sopenharmony_ci#define ICH_PRIE 0x00000010 /* primary resume interrupt enable */ 1618c2ecf20Sopenharmony_ci#define ICH_ACLINK 0x00000008 /* AClink shut off */ 1628c2ecf20Sopenharmony_ci#define ICH_AC97WARM 0x00000004 /* AC'97 warm reset */ 1638c2ecf20Sopenharmony_ci#define ICH_AC97COLD 0x00000002 /* AC'97 cold reset */ 1648c2ecf20Sopenharmony_ci#define ICH_GIE 0x00000001 /* GPI interrupt enable */ 1658c2ecf20Sopenharmony_ci#define ICH_REG_GLOB_STA 0x30 /* dword - global status */ 1668c2ecf20Sopenharmony_ci#define ICH_TRI 0x20000000 /* ICH4: tertiary (AC_SDIN2) resume interrupt */ 1678c2ecf20Sopenharmony_ci#define ICH_TCR 0x10000000 /* ICH4: tertiary (AC_SDIN2) codec ready */ 1688c2ecf20Sopenharmony_ci#define ICH_BCS 0x08000000 /* ICH4: bit clock stopped */ 1698c2ecf20Sopenharmony_ci#define ICH_SPINT 0x04000000 /* ICH4: S/PDIF interrupt */ 1708c2ecf20Sopenharmony_ci#define ICH_P2INT 0x02000000 /* ICH4: PCM2-In interrupt */ 1718c2ecf20Sopenharmony_ci#define ICH_M2INT 0x01000000 /* ICH4: Mic2-In interrupt */ 1728c2ecf20Sopenharmony_ci#define ICH_SAMPLE_CAP 0x00c00000 /* ICH4: sample capability bits (RO) */ 1738c2ecf20Sopenharmony_ci#define ICH_SAMPLE_16_20 0x00400000 /* ICH4: 16- and 20-bit samples */ 1748c2ecf20Sopenharmony_ci#define ICH_MULTICHAN_CAP 0x00300000 /* ICH4: multi-channel capability bits (RO) */ 1758c2ecf20Sopenharmony_ci#define ICH_SIS_TRI 0x00080000 /* SIS: tertiary resume irq */ 1768c2ecf20Sopenharmony_ci#define ICH_SIS_TCR 0x00040000 /* SIS: tertiary codec ready */ 1778c2ecf20Sopenharmony_ci#define ICH_MD3 0x00020000 /* modem power down semaphore */ 1788c2ecf20Sopenharmony_ci#define ICH_AD3 0x00010000 /* audio power down semaphore */ 1798c2ecf20Sopenharmony_ci#define ICH_RCS 0x00008000 /* read completion status */ 1808c2ecf20Sopenharmony_ci#define ICH_BIT3 0x00004000 /* bit 3 slot 12 */ 1818c2ecf20Sopenharmony_ci#define ICH_BIT2 0x00002000 /* bit 2 slot 12 */ 1828c2ecf20Sopenharmony_ci#define ICH_BIT1 0x00001000 /* bit 1 slot 12 */ 1838c2ecf20Sopenharmony_ci#define ICH_SRI 0x00000800 /* secondary (AC_SDIN1) resume interrupt */ 1848c2ecf20Sopenharmony_ci#define ICH_PRI 0x00000400 /* primary (AC_SDIN0) resume interrupt */ 1858c2ecf20Sopenharmony_ci#define ICH_SCR 0x00000200 /* secondary (AC_SDIN1) codec ready */ 1868c2ecf20Sopenharmony_ci#define ICH_PCR 0x00000100 /* primary (AC_SDIN0) codec ready */ 1878c2ecf20Sopenharmony_ci#define ICH_MCINT 0x00000080 /* MIC capture interrupt */ 1888c2ecf20Sopenharmony_ci#define ICH_POINT 0x00000040 /* playback interrupt */ 1898c2ecf20Sopenharmony_ci#define ICH_PIINT 0x00000020 /* capture interrupt */ 1908c2ecf20Sopenharmony_ci#define ICH_NVSPINT 0x00000010 /* nforce spdif interrupt */ 1918c2ecf20Sopenharmony_ci#define ICH_MOINT 0x00000004 /* modem playback interrupt */ 1928c2ecf20Sopenharmony_ci#define ICH_MIINT 0x00000002 /* modem capture interrupt */ 1938c2ecf20Sopenharmony_ci#define ICH_GSCI 0x00000001 /* GPI status change interrupt */ 1948c2ecf20Sopenharmony_ci#define ICH_REG_ACC_SEMA 0x34 /* byte - codec write semaphore */ 1958c2ecf20Sopenharmony_ci#define ICH_CAS 0x01 /* codec access semaphore */ 1968c2ecf20Sopenharmony_ci#define ICH_REG_SDM 0x80 1978c2ecf20Sopenharmony_ci#define ICH_DI2L_MASK 0x000000c0 /* PCM In 2, Mic In 2 data in line */ 1988c2ecf20Sopenharmony_ci#define ICH_DI2L_SHIFT 6 1998c2ecf20Sopenharmony_ci#define ICH_DI1L_MASK 0x00000030 /* PCM In 1, Mic In 1 data in line */ 2008c2ecf20Sopenharmony_ci#define ICH_DI1L_SHIFT 4 2018c2ecf20Sopenharmony_ci#define ICH_SE 0x00000008 /* steer enable */ 2028c2ecf20Sopenharmony_ci#define ICH_LDI_MASK 0x00000003 /* last codec read data input */ 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci#define ICH_MAX_FRAGS 32 /* max hw frags */ 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci/* 2088c2ecf20Sopenharmony_ci * registers for Ali5455 2098c2ecf20Sopenharmony_ci */ 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci/* ALi 5455 busmaster blocks */ 2128c2ecf20Sopenharmony_ciDEFINE_REGSET(AL_PI, 0x40); /* ALi PCM in */ 2138c2ecf20Sopenharmony_ciDEFINE_REGSET(AL_PO, 0x50); /* Ali PCM out */ 2148c2ecf20Sopenharmony_ciDEFINE_REGSET(AL_MC, 0x60); /* Ali Mic in */ 2158c2ecf20Sopenharmony_ciDEFINE_REGSET(AL_CDC_SPO, 0x70); /* Ali Codec SPDIF out */ 2168c2ecf20Sopenharmony_ciDEFINE_REGSET(AL_CENTER, 0x80); /* Ali center out */ 2178c2ecf20Sopenharmony_ciDEFINE_REGSET(AL_LFE, 0x90); /* Ali center out */ 2188c2ecf20Sopenharmony_ciDEFINE_REGSET(AL_CLR_SPI, 0xa0); /* Ali Controller SPDIF in */ 2198c2ecf20Sopenharmony_ciDEFINE_REGSET(AL_CLR_SPO, 0xb0); /* Ali Controller SPDIF out */ 2208c2ecf20Sopenharmony_ciDEFINE_REGSET(AL_I2S, 0xc0); /* Ali I2S in */ 2218c2ecf20Sopenharmony_ciDEFINE_REGSET(AL_PI2, 0xd0); /* Ali PCM2 in */ 2228c2ecf20Sopenharmony_ciDEFINE_REGSET(AL_MC2, 0xe0); /* Ali Mic2 in */ 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_cienum { 2258c2ecf20Sopenharmony_ci ICH_REG_ALI_SCR = 0x00, /* System Control Register */ 2268c2ecf20Sopenharmony_ci ICH_REG_ALI_SSR = 0x04, /* System Status Register */ 2278c2ecf20Sopenharmony_ci ICH_REG_ALI_DMACR = 0x08, /* DMA Control Register */ 2288c2ecf20Sopenharmony_ci ICH_REG_ALI_FIFOCR1 = 0x0c, /* FIFO Control Register 1 */ 2298c2ecf20Sopenharmony_ci ICH_REG_ALI_INTERFACECR = 0x10, /* Interface Control Register */ 2308c2ecf20Sopenharmony_ci ICH_REG_ALI_INTERRUPTCR = 0x14, /* Interrupt control Register */ 2318c2ecf20Sopenharmony_ci ICH_REG_ALI_INTERRUPTSR = 0x18, /* Interrupt Status Register */ 2328c2ecf20Sopenharmony_ci ICH_REG_ALI_FIFOCR2 = 0x1c, /* FIFO Control Register 2 */ 2338c2ecf20Sopenharmony_ci ICH_REG_ALI_CPR = 0x20, /* Command Port Register */ 2348c2ecf20Sopenharmony_ci ICH_REG_ALI_CPR_ADDR = 0x22, /* ac97 addr write */ 2358c2ecf20Sopenharmony_ci ICH_REG_ALI_SPR = 0x24, /* Status Port Register */ 2368c2ecf20Sopenharmony_ci ICH_REG_ALI_SPR_ADDR = 0x26, /* ac97 addr read */ 2378c2ecf20Sopenharmony_ci ICH_REG_ALI_FIFOCR3 = 0x2c, /* FIFO Control Register 3 */ 2388c2ecf20Sopenharmony_ci ICH_REG_ALI_TTSR = 0x30, /* Transmit Tag Slot Register */ 2398c2ecf20Sopenharmony_ci ICH_REG_ALI_RTSR = 0x34, /* Receive Tag Slot Register */ 2408c2ecf20Sopenharmony_ci ICH_REG_ALI_CSPSR = 0x38, /* Command/Status Port Status Register */ 2418c2ecf20Sopenharmony_ci ICH_REG_ALI_CAS = 0x3c, /* Codec Write Semaphore Register */ 2428c2ecf20Sopenharmony_ci ICH_REG_ALI_HWVOL = 0xf0, /* hardware volume control/status */ 2438c2ecf20Sopenharmony_ci ICH_REG_ALI_I2SCR = 0xf4, /* I2S control/status */ 2448c2ecf20Sopenharmony_ci ICH_REG_ALI_SPDIFCSR = 0xf8, /* spdif channel status register */ 2458c2ecf20Sopenharmony_ci ICH_REG_ALI_SPDIFICS = 0xfc, /* spdif interface control/status */ 2468c2ecf20Sopenharmony_ci}; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci#define ALI_CAS_SEM_BUSY 0x80000000 2498c2ecf20Sopenharmony_ci#define ALI_CPR_ADDR_SECONDARY 0x100 2508c2ecf20Sopenharmony_ci#define ALI_CPR_ADDR_READ 0x80 2518c2ecf20Sopenharmony_ci#define ALI_CSPSR_CODEC_READY 0x08 2528c2ecf20Sopenharmony_ci#define ALI_CSPSR_READ_OK 0x02 2538c2ecf20Sopenharmony_ci#define ALI_CSPSR_WRITE_OK 0x01 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci/* interrupts for the whole chip by interrupt status register finish */ 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci#define ALI_INT_MICIN2 (1<<26) 2588c2ecf20Sopenharmony_ci#define ALI_INT_PCMIN2 (1<<25) 2598c2ecf20Sopenharmony_ci#define ALI_INT_I2SIN (1<<24) 2608c2ecf20Sopenharmony_ci#define ALI_INT_SPDIFOUT (1<<23) /* controller spdif out INTERRUPT */ 2618c2ecf20Sopenharmony_ci#define ALI_INT_SPDIFIN (1<<22) 2628c2ecf20Sopenharmony_ci#define ALI_INT_LFEOUT (1<<21) 2638c2ecf20Sopenharmony_ci#define ALI_INT_CENTEROUT (1<<20) 2648c2ecf20Sopenharmony_ci#define ALI_INT_CODECSPDIFOUT (1<<19) 2658c2ecf20Sopenharmony_ci#define ALI_INT_MICIN (1<<18) 2668c2ecf20Sopenharmony_ci#define ALI_INT_PCMOUT (1<<17) 2678c2ecf20Sopenharmony_ci#define ALI_INT_PCMIN (1<<16) 2688c2ecf20Sopenharmony_ci#define ALI_INT_CPRAIS (1<<7) /* command port available */ 2698c2ecf20Sopenharmony_ci#define ALI_INT_SPRAIS (1<<5) /* status port available */ 2708c2ecf20Sopenharmony_ci#define ALI_INT_GPIO (1<<1) 2718c2ecf20Sopenharmony_ci#define ALI_INT_MASK (ALI_INT_SPDIFOUT|ALI_INT_CODECSPDIFOUT|\ 2728c2ecf20Sopenharmony_ci ALI_INT_MICIN|ALI_INT_PCMOUT|ALI_INT_PCMIN) 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci#define ICH_ALI_SC_RESET (1<<31) /* master reset */ 2758c2ecf20Sopenharmony_ci#define ICH_ALI_SC_AC97_DBL (1<<30) 2768c2ecf20Sopenharmony_ci#define ICH_ALI_SC_CODEC_SPDF (3<<20) /* 1=7/8, 2=6/9, 3=10/11 */ 2778c2ecf20Sopenharmony_ci#define ICH_ALI_SC_IN_BITS (3<<18) 2788c2ecf20Sopenharmony_ci#define ICH_ALI_SC_OUT_BITS (3<<16) 2798c2ecf20Sopenharmony_ci#define ICH_ALI_SC_6CH_CFG (3<<14) 2808c2ecf20Sopenharmony_ci#define ICH_ALI_SC_PCM_4 (1<<8) 2818c2ecf20Sopenharmony_ci#define ICH_ALI_SC_PCM_6 (2<<8) 2828c2ecf20Sopenharmony_ci#define ICH_ALI_SC_PCM_246_MASK (3<<8) 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci#define ICH_ALI_SS_SEC_ID (3<<5) 2858c2ecf20Sopenharmony_ci#define ICH_ALI_SS_PRI_ID (3<<3) 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci#define ICH_ALI_IF_AC97SP (1<<21) 2888c2ecf20Sopenharmony_ci#define ICH_ALI_IF_MC (1<<20) 2898c2ecf20Sopenharmony_ci#define ICH_ALI_IF_PI (1<<19) 2908c2ecf20Sopenharmony_ci#define ICH_ALI_IF_MC2 (1<<18) 2918c2ecf20Sopenharmony_ci#define ICH_ALI_IF_PI2 (1<<17) 2928c2ecf20Sopenharmony_ci#define ICH_ALI_IF_LINE_SRC (1<<15) /* 0/1 = slot 3/6 */ 2938c2ecf20Sopenharmony_ci#define ICH_ALI_IF_MIC_SRC (1<<14) /* 0/1 = slot 3/6 */ 2948c2ecf20Sopenharmony_ci#define ICH_ALI_IF_SPDF_SRC (3<<12) /* 00 = PCM, 01 = AC97-in, 10 = spdif-in, 11 = i2s */ 2958c2ecf20Sopenharmony_ci#define ICH_ALI_IF_AC97_OUT (3<<8) /* 00 = PCM, 10 = spdif-in, 11 = i2s */ 2968c2ecf20Sopenharmony_ci#define ICH_ALI_IF_PO_SPDF (1<<3) 2978c2ecf20Sopenharmony_ci#define ICH_ALI_IF_PO (1<<1) 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci/* 3008c2ecf20Sopenharmony_ci * 3018c2ecf20Sopenharmony_ci */ 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_cienum { 3048c2ecf20Sopenharmony_ci ICHD_PCMIN, 3058c2ecf20Sopenharmony_ci ICHD_PCMOUT, 3068c2ecf20Sopenharmony_ci ICHD_MIC, 3078c2ecf20Sopenharmony_ci ICHD_MIC2, 3088c2ecf20Sopenharmony_ci ICHD_PCM2IN, 3098c2ecf20Sopenharmony_ci ICHD_SPBAR, 3108c2ecf20Sopenharmony_ci ICHD_LAST = ICHD_SPBAR 3118c2ecf20Sopenharmony_ci}; 3128c2ecf20Sopenharmony_cienum { 3138c2ecf20Sopenharmony_ci NVD_PCMIN, 3148c2ecf20Sopenharmony_ci NVD_PCMOUT, 3158c2ecf20Sopenharmony_ci NVD_MIC, 3168c2ecf20Sopenharmony_ci NVD_SPBAR, 3178c2ecf20Sopenharmony_ci NVD_LAST = NVD_SPBAR 3188c2ecf20Sopenharmony_ci}; 3198c2ecf20Sopenharmony_cienum { 3208c2ecf20Sopenharmony_ci ALID_PCMIN, 3218c2ecf20Sopenharmony_ci ALID_PCMOUT, 3228c2ecf20Sopenharmony_ci ALID_MIC, 3238c2ecf20Sopenharmony_ci ALID_AC97SPDIFOUT, 3248c2ecf20Sopenharmony_ci ALID_SPDIFIN, 3258c2ecf20Sopenharmony_ci ALID_SPDIFOUT, 3268c2ecf20Sopenharmony_ci ALID_LAST = ALID_SPDIFOUT 3278c2ecf20Sopenharmony_ci}; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci#define get_ichdev(substream) (substream->runtime->private_data) 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_cistruct ichdev { 3328c2ecf20Sopenharmony_ci unsigned int ichd; /* ich device number */ 3338c2ecf20Sopenharmony_ci unsigned long reg_offset; /* offset to bmaddr */ 3348c2ecf20Sopenharmony_ci __le32 *bdbar; /* CPU address (32bit) */ 3358c2ecf20Sopenharmony_ci unsigned int bdbar_addr; /* PCI bus address (32bit) */ 3368c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream; 3378c2ecf20Sopenharmony_ci unsigned int physbuf; /* physical address (32bit) */ 3388c2ecf20Sopenharmony_ci unsigned int size; 3398c2ecf20Sopenharmony_ci unsigned int fragsize; 3408c2ecf20Sopenharmony_ci unsigned int fragsize1; 3418c2ecf20Sopenharmony_ci unsigned int position; 3428c2ecf20Sopenharmony_ci unsigned int pos_shift; 3438c2ecf20Sopenharmony_ci unsigned int last_pos; 3448c2ecf20Sopenharmony_ci int frags; 3458c2ecf20Sopenharmony_ci int lvi; 3468c2ecf20Sopenharmony_ci int lvi_frag; 3478c2ecf20Sopenharmony_ci int civ; 3488c2ecf20Sopenharmony_ci int ack; 3498c2ecf20Sopenharmony_ci int ack_reload; 3508c2ecf20Sopenharmony_ci unsigned int ack_bit; 3518c2ecf20Sopenharmony_ci unsigned int roff_sr; 3528c2ecf20Sopenharmony_ci unsigned int roff_picb; 3538c2ecf20Sopenharmony_ci unsigned int int_sta_mask; /* interrupt status mask */ 3548c2ecf20Sopenharmony_ci unsigned int ali_slot; /* ALI DMA slot */ 3558c2ecf20Sopenharmony_ci struct ac97_pcm *pcm; 3568c2ecf20Sopenharmony_ci int pcm_open_flag; 3578c2ecf20Sopenharmony_ci unsigned int prepared:1; 3588c2ecf20Sopenharmony_ci unsigned int suspended: 1; 3598c2ecf20Sopenharmony_ci}; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_cistruct intel8x0 { 3628c2ecf20Sopenharmony_ci unsigned int device_type; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci int irq; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci void __iomem *addr; 3678c2ecf20Sopenharmony_ci void __iomem *bmaddr; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci struct pci_dev *pci; 3708c2ecf20Sopenharmony_ci struct snd_card *card; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci int pcm_devs; 3738c2ecf20Sopenharmony_ci struct snd_pcm *pcm[6]; 3748c2ecf20Sopenharmony_ci struct ichdev ichd[6]; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci unsigned multi4: 1, 3778c2ecf20Sopenharmony_ci multi6: 1, 3788c2ecf20Sopenharmony_ci multi8 :1, 3798c2ecf20Sopenharmony_ci dra: 1, 3808c2ecf20Sopenharmony_ci smp20bit: 1; 3818c2ecf20Sopenharmony_ci unsigned in_ac97_init: 1, 3828c2ecf20Sopenharmony_ci in_sdin_init: 1; 3838c2ecf20Sopenharmony_ci unsigned in_measurement: 1; /* during ac97 clock measurement */ 3848c2ecf20Sopenharmony_ci unsigned fix_nocache: 1; /* workaround for 440MX */ 3858c2ecf20Sopenharmony_ci unsigned buggy_irq: 1; /* workaround for buggy mobos */ 3868c2ecf20Sopenharmony_ci unsigned xbox: 1; /* workaround for Xbox AC'97 detection */ 3878c2ecf20Sopenharmony_ci unsigned buggy_semaphore: 1; /* workaround for buggy codec semaphore */ 3888c2ecf20Sopenharmony_ci unsigned inside_vm: 1; /* enable VM optimization */ 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci int spdif_idx; /* SPDIF BAR index; *_SPBAR or -1 if use PCMOUT */ 3918c2ecf20Sopenharmony_ci unsigned int sdm_saved; /* SDM reg value */ 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci struct snd_ac97_bus *ac97_bus; 3948c2ecf20Sopenharmony_ci struct snd_ac97 *ac97[3]; 3958c2ecf20Sopenharmony_ci unsigned int ac97_sdin[3]; 3968c2ecf20Sopenharmony_ci unsigned int max_codecs, ncodecs; 3978c2ecf20Sopenharmony_ci const unsigned int *codec_bit; 3988c2ecf20Sopenharmony_ci unsigned int codec_isr_bits; 3998c2ecf20Sopenharmony_ci unsigned int codec_ready_bits; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci spinlock_t reg_lock; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci u32 bdbars_count; 4048c2ecf20Sopenharmony_ci struct snd_dma_buffer bdbars; 4058c2ecf20Sopenharmony_ci u32 int_sta_reg; /* interrupt status register */ 4068c2ecf20Sopenharmony_ci u32 int_sta_mask; /* interrupt status mask */ 4078c2ecf20Sopenharmony_ci}; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_cistatic const struct pci_device_id snd_intel8x0_ids[] = { 4108c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0x2415), DEVICE_INTEL }, /* 82801AA */ 4118c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0x2425), DEVICE_INTEL }, /* 82901AB */ 4128c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0x2445), DEVICE_INTEL }, /* 82801BA */ 4138c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0x2485), DEVICE_INTEL }, /* ICH3 */ 4148c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0x24c5), DEVICE_INTEL_ICH4 }, /* ICH4 */ 4158c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0x24d5), DEVICE_INTEL_ICH4 }, /* ICH5 */ 4168c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0x25a6), DEVICE_INTEL_ICH4 }, /* ESB */ 4178c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0x266e), DEVICE_INTEL_ICH4 }, /* ICH6 */ 4188c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0x27de), DEVICE_INTEL_ICH4 }, /* ICH7 */ 4198c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0x2698), DEVICE_INTEL_ICH4 }, /* ESB2 */ 4208c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0x7195), DEVICE_INTEL }, /* 440MX */ 4218c2ecf20Sopenharmony_ci { PCI_VDEVICE(SI, 0x7012), DEVICE_SIS }, /* SI7012 */ 4228c2ecf20Sopenharmony_ci { PCI_VDEVICE(NVIDIA, 0x01b1), DEVICE_NFORCE }, /* NFORCE */ 4238c2ecf20Sopenharmony_ci { PCI_VDEVICE(NVIDIA, 0x003a), DEVICE_NFORCE }, /* MCP04 */ 4248c2ecf20Sopenharmony_ci { PCI_VDEVICE(NVIDIA, 0x006a), DEVICE_NFORCE }, /* NFORCE2 */ 4258c2ecf20Sopenharmony_ci { PCI_VDEVICE(NVIDIA, 0x0059), DEVICE_NFORCE }, /* CK804 */ 4268c2ecf20Sopenharmony_ci { PCI_VDEVICE(NVIDIA, 0x008a), DEVICE_NFORCE }, /* CK8 */ 4278c2ecf20Sopenharmony_ci { PCI_VDEVICE(NVIDIA, 0x00da), DEVICE_NFORCE }, /* NFORCE3 */ 4288c2ecf20Sopenharmony_ci { PCI_VDEVICE(NVIDIA, 0x00ea), DEVICE_NFORCE }, /* CK8S */ 4298c2ecf20Sopenharmony_ci { PCI_VDEVICE(NVIDIA, 0x026b), DEVICE_NFORCE }, /* MCP51 */ 4308c2ecf20Sopenharmony_ci { PCI_VDEVICE(AMD, 0x746d), DEVICE_INTEL }, /* AMD8111 */ 4318c2ecf20Sopenharmony_ci { PCI_VDEVICE(AMD, 0x7445), DEVICE_INTEL }, /* AMD768 */ 4328c2ecf20Sopenharmony_ci { PCI_VDEVICE(AL, 0x5455), DEVICE_ALI }, /* Ali5455 */ 4338c2ecf20Sopenharmony_ci { 0, } 4348c2ecf20Sopenharmony_ci}; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, snd_intel8x0_ids); 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci/* 4398c2ecf20Sopenharmony_ci * Lowlevel I/O - busmaster 4408c2ecf20Sopenharmony_ci */ 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_cistatic inline u8 igetbyte(struct intel8x0 *chip, u32 offset) 4438c2ecf20Sopenharmony_ci{ 4448c2ecf20Sopenharmony_ci return ioread8(chip->bmaddr + offset); 4458c2ecf20Sopenharmony_ci} 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_cistatic inline u16 igetword(struct intel8x0 *chip, u32 offset) 4488c2ecf20Sopenharmony_ci{ 4498c2ecf20Sopenharmony_ci return ioread16(chip->bmaddr + offset); 4508c2ecf20Sopenharmony_ci} 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_cistatic inline u32 igetdword(struct intel8x0 *chip, u32 offset) 4538c2ecf20Sopenharmony_ci{ 4548c2ecf20Sopenharmony_ci return ioread32(chip->bmaddr + offset); 4558c2ecf20Sopenharmony_ci} 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_cistatic inline void iputbyte(struct intel8x0 *chip, u32 offset, u8 val) 4588c2ecf20Sopenharmony_ci{ 4598c2ecf20Sopenharmony_ci iowrite8(val, chip->bmaddr + offset); 4608c2ecf20Sopenharmony_ci} 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_cistatic inline void iputword(struct intel8x0 *chip, u32 offset, u16 val) 4638c2ecf20Sopenharmony_ci{ 4648c2ecf20Sopenharmony_ci iowrite16(val, chip->bmaddr + offset); 4658c2ecf20Sopenharmony_ci} 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_cistatic inline void iputdword(struct intel8x0 *chip, u32 offset, u32 val) 4688c2ecf20Sopenharmony_ci{ 4698c2ecf20Sopenharmony_ci iowrite32(val, chip->bmaddr + offset); 4708c2ecf20Sopenharmony_ci} 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci/* 4738c2ecf20Sopenharmony_ci * Lowlevel I/O - AC'97 registers 4748c2ecf20Sopenharmony_ci */ 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_cistatic inline u16 iagetword(struct intel8x0 *chip, u32 offset) 4778c2ecf20Sopenharmony_ci{ 4788c2ecf20Sopenharmony_ci return ioread16(chip->addr + offset); 4798c2ecf20Sopenharmony_ci} 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_cistatic inline void iaputword(struct intel8x0 *chip, u32 offset, u16 val) 4828c2ecf20Sopenharmony_ci{ 4838c2ecf20Sopenharmony_ci iowrite16(val, chip->addr + offset); 4848c2ecf20Sopenharmony_ci} 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci/* 4878c2ecf20Sopenharmony_ci * Basic I/O 4888c2ecf20Sopenharmony_ci */ 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci/* 4918c2ecf20Sopenharmony_ci * access to AC97 codec via normal i/o (for ICH and SIS7012) 4928c2ecf20Sopenharmony_ci */ 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_cistatic int snd_intel8x0_codec_semaphore(struct intel8x0 *chip, unsigned int codec) 4958c2ecf20Sopenharmony_ci{ 4968c2ecf20Sopenharmony_ci int time; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci if (codec > 2) 4998c2ecf20Sopenharmony_ci return -EIO; 5008c2ecf20Sopenharmony_ci if (chip->in_sdin_init) { 5018c2ecf20Sopenharmony_ci /* we don't know the ready bit assignment at the moment */ 5028c2ecf20Sopenharmony_ci /* so we check any */ 5038c2ecf20Sopenharmony_ci codec = chip->codec_isr_bits; 5048c2ecf20Sopenharmony_ci } else { 5058c2ecf20Sopenharmony_ci codec = chip->codec_bit[chip->ac97_sdin[codec]]; 5068c2ecf20Sopenharmony_ci } 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci /* codec ready ? */ 5098c2ecf20Sopenharmony_ci if ((igetdword(chip, ICHREG(GLOB_STA)) & codec) == 0) 5108c2ecf20Sopenharmony_ci return -EIO; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci if (chip->buggy_semaphore) 5138c2ecf20Sopenharmony_ci return 0; /* just ignore ... */ 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci /* Anyone holding a semaphore for 1 msec should be shot... */ 5168c2ecf20Sopenharmony_ci time = 100; 5178c2ecf20Sopenharmony_ci do { 5188c2ecf20Sopenharmony_ci if (!(igetbyte(chip, ICHREG(ACC_SEMA)) & ICH_CAS)) 5198c2ecf20Sopenharmony_ci return 0; 5208c2ecf20Sopenharmony_ci udelay(10); 5218c2ecf20Sopenharmony_ci } while (time--); 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci /* access to some forbidden (non existent) ac97 registers will not 5248c2ecf20Sopenharmony_ci * reset the semaphore. So even if you don't get the semaphore, still 5258c2ecf20Sopenharmony_ci * continue the access. We don't need the semaphore anyway. */ 5268c2ecf20Sopenharmony_ci dev_err(chip->card->dev, 5278c2ecf20Sopenharmony_ci "codec_semaphore: semaphore is not ready [0x%x][0x%x]\n", 5288c2ecf20Sopenharmony_ci igetbyte(chip, ICHREG(ACC_SEMA)), igetdword(chip, ICHREG(GLOB_STA))); 5298c2ecf20Sopenharmony_ci iagetword(chip, 0); /* clear semaphore flag */ 5308c2ecf20Sopenharmony_ci /* I don't care about the semaphore */ 5318c2ecf20Sopenharmony_ci return -EBUSY; 5328c2ecf20Sopenharmony_ci} 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_cistatic void snd_intel8x0_codec_write(struct snd_ac97 *ac97, 5358c2ecf20Sopenharmony_ci unsigned short reg, 5368c2ecf20Sopenharmony_ci unsigned short val) 5378c2ecf20Sopenharmony_ci{ 5388c2ecf20Sopenharmony_ci struct intel8x0 *chip = ac97->private_data; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci if (snd_intel8x0_codec_semaphore(chip, ac97->num) < 0) { 5418c2ecf20Sopenharmony_ci if (! chip->in_ac97_init) 5428c2ecf20Sopenharmony_ci dev_err(chip->card->dev, 5438c2ecf20Sopenharmony_ci "codec_write %d: semaphore is not ready for register 0x%x\n", 5448c2ecf20Sopenharmony_ci ac97->num, reg); 5458c2ecf20Sopenharmony_ci } 5468c2ecf20Sopenharmony_ci iaputword(chip, reg + ac97->num * 0x80, val); 5478c2ecf20Sopenharmony_ci} 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_cistatic unsigned short snd_intel8x0_codec_read(struct snd_ac97 *ac97, 5508c2ecf20Sopenharmony_ci unsigned short reg) 5518c2ecf20Sopenharmony_ci{ 5528c2ecf20Sopenharmony_ci struct intel8x0 *chip = ac97->private_data; 5538c2ecf20Sopenharmony_ci unsigned short res; 5548c2ecf20Sopenharmony_ci unsigned int tmp; 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci if (snd_intel8x0_codec_semaphore(chip, ac97->num) < 0) { 5578c2ecf20Sopenharmony_ci if (! chip->in_ac97_init) 5588c2ecf20Sopenharmony_ci dev_err(chip->card->dev, 5598c2ecf20Sopenharmony_ci "codec_read %d: semaphore is not ready for register 0x%x\n", 5608c2ecf20Sopenharmony_ci ac97->num, reg); 5618c2ecf20Sopenharmony_ci res = 0xffff; 5628c2ecf20Sopenharmony_ci } else { 5638c2ecf20Sopenharmony_ci res = iagetword(chip, reg + ac97->num * 0x80); 5648c2ecf20Sopenharmony_ci if ((tmp = igetdword(chip, ICHREG(GLOB_STA))) & ICH_RCS) { 5658c2ecf20Sopenharmony_ci /* reset RCS and preserve other R/WC bits */ 5668c2ecf20Sopenharmony_ci iputdword(chip, ICHREG(GLOB_STA), tmp & 5678c2ecf20Sopenharmony_ci ~(chip->codec_ready_bits | ICH_GSCI)); 5688c2ecf20Sopenharmony_ci if (! chip->in_ac97_init) 5698c2ecf20Sopenharmony_ci dev_err(chip->card->dev, 5708c2ecf20Sopenharmony_ci "codec_read %d: read timeout for register 0x%x\n", 5718c2ecf20Sopenharmony_ci ac97->num, reg); 5728c2ecf20Sopenharmony_ci res = 0xffff; 5738c2ecf20Sopenharmony_ci } 5748c2ecf20Sopenharmony_ci } 5758c2ecf20Sopenharmony_ci return res; 5768c2ecf20Sopenharmony_ci} 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_cistatic void snd_intel8x0_codec_read_test(struct intel8x0 *chip, 5798c2ecf20Sopenharmony_ci unsigned int codec) 5808c2ecf20Sopenharmony_ci{ 5818c2ecf20Sopenharmony_ci unsigned int tmp; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci if (snd_intel8x0_codec_semaphore(chip, codec) >= 0) { 5848c2ecf20Sopenharmony_ci iagetword(chip, codec * 0x80); 5858c2ecf20Sopenharmony_ci if ((tmp = igetdword(chip, ICHREG(GLOB_STA))) & ICH_RCS) { 5868c2ecf20Sopenharmony_ci /* reset RCS and preserve other R/WC bits */ 5878c2ecf20Sopenharmony_ci iputdword(chip, ICHREG(GLOB_STA), tmp & 5888c2ecf20Sopenharmony_ci ~(chip->codec_ready_bits | ICH_GSCI)); 5898c2ecf20Sopenharmony_ci } 5908c2ecf20Sopenharmony_ci } 5918c2ecf20Sopenharmony_ci} 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci/* 5948c2ecf20Sopenharmony_ci * access to AC97 for Ali5455 5958c2ecf20Sopenharmony_ci */ 5968c2ecf20Sopenharmony_cistatic int snd_intel8x0_ali_codec_ready(struct intel8x0 *chip, int mask) 5978c2ecf20Sopenharmony_ci{ 5988c2ecf20Sopenharmony_ci int count = 0; 5998c2ecf20Sopenharmony_ci for (count = 0; count < 0x7f; count++) { 6008c2ecf20Sopenharmony_ci int val = igetbyte(chip, ICHREG(ALI_CSPSR)); 6018c2ecf20Sopenharmony_ci if (val & mask) 6028c2ecf20Sopenharmony_ci return 0; 6038c2ecf20Sopenharmony_ci } 6048c2ecf20Sopenharmony_ci if (! chip->in_ac97_init) 6058c2ecf20Sopenharmony_ci dev_warn(chip->card->dev, "AC97 codec ready timeout.\n"); 6068c2ecf20Sopenharmony_ci return -EBUSY; 6078c2ecf20Sopenharmony_ci} 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_cistatic int snd_intel8x0_ali_codec_semaphore(struct intel8x0 *chip) 6108c2ecf20Sopenharmony_ci{ 6118c2ecf20Sopenharmony_ci int time = 100; 6128c2ecf20Sopenharmony_ci if (chip->buggy_semaphore) 6138c2ecf20Sopenharmony_ci return 0; /* just ignore ... */ 6148c2ecf20Sopenharmony_ci while (--time && (igetdword(chip, ICHREG(ALI_CAS)) & ALI_CAS_SEM_BUSY)) 6158c2ecf20Sopenharmony_ci udelay(1); 6168c2ecf20Sopenharmony_ci if (! time && ! chip->in_ac97_init) 6178c2ecf20Sopenharmony_ci dev_warn(chip->card->dev, "ali_codec_semaphore timeout\n"); 6188c2ecf20Sopenharmony_ci return snd_intel8x0_ali_codec_ready(chip, ALI_CSPSR_CODEC_READY); 6198c2ecf20Sopenharmony_ci} 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_cistatic unsigned short snd_intel8x0_ali_codec_read(struct snd_ac97 *ac97, unsigned short reg) 6228c2ecf20Sopenharmony_ci{ 6238c2ecf20Sopenharmony_ci struct intel8x0 *chip = ac97->private_data; 6248c2ecf20Sopenharmony_ci unsigned short data = 0xffff; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci if (snd_intel8x0_ali_codec_semaphore(chip)) 6278c2ecf20Sopenharmony_ci goto __err; 6288c2ecf20Sopenharmony_ci reg |= ALI_CPR_ADDR_READ; 6298c2ecf20Sopenharmony_ci if (ac97->num) 6308c2ecf20Sopenharmony_ci reg |= ALI_CPR_ADDR_SECONDARY; 6318c2ecf20Sopenharmony_ci iputword(chip, ICHREG(ALI_CPR_ADDR), reg); 6328c2ecf20Sopenharmony_ci if (snd_intel8x0_ali_codec_ready(chip, ALI_CSPSR_READ_OK)) 6338c2ecf20Sopenharmony_ci goto __err; 6348c2ecf20Sopenharmony_ci data = igetword(chip, ICHREG(ALI_SPR)); 6358c2ecf20Sopenharmony_ci __err: 6368c2ecf20Sopenharmony_ci return data; 6378c2ecf20Sopenharmony_ci} 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_cistatic void snd_intel8x0_ali_codec_write(struct snd_ac97 *ac97, unsigned short reg, 6408c2ecf20Sopenharmony_ci unsigned short val) 6418c2ecf20Sopenharmony_ci{ 6428c2ecf20Sopenharmony_ci struct intel8x0 *chip = ac97->private_data; 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci if (snd_intel8x0_ali_codec_semaphore(chip)) 6458c2ecf20Sopenharmony_ci return; 6468c2ecf20Sopenharmony_ci iputword(chip, ICHREG(ALI_CPR), val); 6478c2ecf20Sopenharmony_ci if (ac97->num) 6488c2ecf20Sopenharmony_ci reg |= ALI_CPR_ADDR_SECONDARY; 6498c2ecf20Sopenharmony_ci iputword(chip, ICHREG(ALI_CPR_ADDR), reg); 6508c2ecf20Sopenharmony_ci snd_intel8x0_ali_codec_ready(chip, ALI_CSPSR_WRITE_OK); 6518c2ecf20Sopenharmony_ci} 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci/* 6558c2ecf20Sopenharmony_ci * DMA I/O 6568c2ecf20Sopenharmony_ci */ 6578c2ecf20Sopenharmony_cistatic void snd_intel8x0_setup_periods(struct intel8x0 *chip, struct ichdev *ichdev) 6588c2ecf20Sopenharmony_ci{ 6598c2ecf20Sopenharmony_ci int idx; 6608c2ecf20Sopenharmony_ci __le32 *bdbar = ichdev->bdbar; 6618c2ecf20Sopenharmony_ci unsigned long port = ichdev->reg_offset; 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci iputdword(chip, port + ICH_REG_OFF_BDBAR, ichdev->bdbar_addr); 6648c2ecf20Sopenharmony_ci if (ichdev->size == ichdev->fragsize) { 6658c2ecf20Sopenharmony_ci ichdev->ack_reload = ichdev->ack = 2; 6668c2ecf20Sopenharmony_ci ichdev->fragsize1 = ichdev->fragsize >> 1; 6678c2ecf20Sopenharmony_ci for (idx = 0; idx < (ICH_REG_LVI_MASK + 1) * 2; idx += 4) { 6688c2ecf20Sopenharmony_ci bdbar[idx + 0] = cpu_to_le32(ichdev->physbuf); 6698c2ecf20Sopenharmony_ci bdbar[idx + 1] = cpu_to_le32(0x80000000 | /* interrupt on completion */ 6708c2ecf20Sopenharmony_ci ichdev->fragsize1 >> ichdev->pos_shift); 6718c2ecf20Sopenharmony_ci bdbar[idx + 2] = cpu_to_le32(ichdev->physbuf + (ichdev->size >> 1)); 6728c2ecf20Sopenharmony_ci bdbar[idx + 3] = cpu_to_le32(0x80000000 | /* interrupt on completion */ 6738c2ecf20Sopenharmony_ci ichdev->fragsize1 >> ichdev->pos_shift); 6748c2ecf20Sopenharmony_ci } 6758c2ecf20Sopenharmony_ci ichdev->frags = 2; 6768c2ecf20Sopenharmony_ci } else { 6778c2ecf20Sopenharmony_ci ichdev->ack_reload = ichdev->ack = 1; 6788c2ecf20Sopenharmony_ci ichdev->fragsize1 = ichdev->fragsize; 6798c2ecf20Sopenharmony_ci for (idx = 0; idx < (ICH_REG_LVI_MASK + 1) * 2; idx += 2) { 6808c2ecf20Sopenharmony_ci bdbar[idx + 0] = cpu_to_le32(ichdev->physbuf + 6818c2ecf20Sopenharmony_ci (((idx >> 1) * ichdev->fragsize) % 6828c2ecf20Sopenharmony_ci ichdev->size)); 6838c2ecf20Sopenharmony_ci bdbar[idx + 1] = cpu_to_le32(0x80000000 | /* interrupt on completion */ 6848c2ecf20Sopenharmony_ci ichdev->fragsize >> ichdev->pos_shift); 6858c2ecf20Sopenharmony_ci#if 0 6868c2ecf20Sopenharmony_ci dev_dbg(chip->card->dev, "bdbar[%i] = 0x%x [0x%x]\n", 6878c2ecf20Sopenharmony_ci idx + 0, bdbar[idx + 0], bdbar[idx + 1]); 6888c2ecf20Sopenharmony_ci#endif 6898c2ecf20Sopenharmony_ci } 6908c2ecf20Sopenharmony_ci ichdev->frags = ichdev->size / ichdev->fragsize; 6918c2ecf20Sopenharmony_ci } 6928c2ecf20Sopenharmony_ci iputbyte(chip, port + ICH_REG_OFF_LVI, ichdev->lvi = ICH_REG_LVI_MASK); 6938c2ecf20Sopenharmony_ci ichdev->civ = 0; 6948c2ecf20Sopenharmony_ci iputbyte(chip, port + ICH_REG_OFF_CIV, 0); 6958c2ecf20Sopenharmony_ci ichdev->lvi_frag = ICH_REG_LVI_MASK % ichdev->frags; 6968c2ecf20Sopenharmony_ci ichdev->position = 0; 6978c2ecf20Sopenharmony_ci#if 0 6988c2ecf20Sopenharmony_ci dev_dbg(chip->card->dev, 6998c2ecf20Sopenharmony_ci "lvi_frag = %i, frags = %i, period_size = 0x%x, period_size1 = 0x%x\n", 7008c2ecf20Sopenharmony_ci ichdev->lvi_frag, ichdev->frags, ichdev->fragsize, 7018c2ecf20Sopenharmony_ci ichdev->fragsize1); 7028c2ecf20Sopenharmony_ci#endif 7038c2ecf20Sopenharmony_ci /* clear interrupts */ 7048c2ecf20Sopenharmony_ci iputbyte(chip, port + ichdev->roff_sr, ICH_FIFOE | ICH_BCIS | ICH_LVBCI); 7058c2ecf20Sopenharmony_ci} 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci/* 7088c2ecf20Sopenharmony_ci * Interrupt handler 7098c2ecf20Sopenharmony_ci */ 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_cistatic inline void snd_intel8x0_update(struct intel8x0 *chip, struct ichdev *ichdev) 7128c2ecf20Sopenharmony_ci{ 7138c2ecf20Sopenharmony_ci unsigned long port = ichdev->reg_offset; 7148c2ecf20Sopenharmony_ci unsigned long flags; 7158c2ecf20Sopenharmony_ci int status, civ, i, step; 7168c2ecf20Sopenharmony_ci int ack = 0; 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci if (!(ichdev->prepared || chip->in_measurement) || ichdev->suspended) 7198c2ecf20Sopenharmony_ci return; 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci spin_lock_irqsave(&chip->reg_lock, flags); 7228c2ecf20Sopenharmony_ci status = igetbyte(chip, port + ichdev->roff_sr); 7238c2ecf20Sopenharmony_ci civ = igetbyte(chip, port + ICH_REG_OFF_CIV); 7248c2ecf20Sopenharmony_ci if (!(status & ICH_BCIS)) { 7258c2ecf20Sopenharmony_ci step = 0; 7268c2ecf20Sopenharmony_ci } else if (civ == ichdev->civ) { 7278c2ecf20Sopenharmony_ci // snd_printd("civ same %d\n", civ); 7288c2ecf20Sopenharmony_ci step = 1; 7298c2ecf20Sopenharmony_ci ichdev->civ++; 7308c2ecf20Sopenharmony_ci ichdev->civ &= ICH_REG_LVI_MASK; 7318c2ecf20Sopenharmony_ci } else { 7328c2ecf20Sopenharmony_ci step = civ - ichdev->civ; 7338c2ecf20Sopenharmony_ci if (step < 0) 7348c2ecf20Sopenharmony_ci step += ICH_REG_LVI_MASK + 1; 7358c2ecf20Sopenharmony_ci // if (step != 1) 7368c2ecf20Sopenharmony_ci // snd_printd("step = %d, %d -> %d\n", step, ichdev->civ, civ); 7378c2ecf20Sopenharmony_ci ichdev->civ = civ; 7388c2ecf20Sopenharmony_ci } 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci ichdev->position += step * ichdev->fragsize1; 7418c2ecf20Sopenharmony_ci if (! chip->in_measurement) 7428c2ecf20Sopenharmony_ci ichdev->position %= ichdev->size; 7438c2ecf20Sopenharmony_ci ichdev->lvi += step; 7448c2ecf20Sopenharmony_ci ichdev->lvi &= ICH_REG_LVI_MASK; 7458c2ecf20Sopenharmony_ci iputbyte(chip, port + ICH_REG_OFF_LVI, ichdev->lvi); 7468c2ecf20Sopenharmony_ci for (i = 0; i < step; i++) { 7478c2ecf20Sopenharmony_ci ichdev->lvi_frag++; 7488c2ecf20Sopenharmony_ci ichdev->lvi_frag %= ichdev->frags; 7498c2ecf20Sopenharmony_ci ichdev->bdbar[ichdev->lvi * 2] = cpu_to_le32(ichdev->physbuf + ichdev->lvi_frag * ichdev->fragsize1); 7508c2ecf20Sopenharmony_ci#if 0 7518c2ecf20Sopenharmony_ci dev_dbg(chip->card->dev, 7528c2ecf20Sopenharmony_ci "new: bdbar[%i] = 0x%x [0x%x], prefetch = %i, all = 0x%x, 0x%x\n", 7538c2ecf20Sopenharmony_ci ichdev->lvi * 2, ichdev->bdbar[ichdev->lvi * 2], 7548c2ecf20Sopenharmony_ci ichdev->bdbar[ichdev->lvi * 2 + 1], inb(ICH_REG_OFF_PIV + port), 7558c2ecf20Sopenharmony_ci inl(port + 4), inb(port + ICH_REG_OFF_CR)); 7568c2ecf20Sopenharmony_ci#endif 7578c2ecf20Sopenharmony_ci if (--ichdev->ack == 0) { 7588c2ecf20Sopenharmony_ci ichdev->ack = ichdev->ack_reload; 7598c2ecf20Sopenharmony_ci ack = 1; 7608c2ecf20Sopenharmony_ci } 7618c2ecf20Sopenharmony_ci } 7628c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&chip->reg_lock, flags); 7638c2ecf20Sopenharmony_ci if (ack && ichdev->substream) { 7648c2ecf20Sopenharmony_ci snd_pcm_period_elapsed(ichdev->substream); 7658c2ecf20Sopenharmony_ci } 7668c2ecf20Sopenharmony_ci iputbyte(chip, port + ichdev->roff_sr, 7678c2ecf20Sopenharmony_ci status & (ICH_FIFOE | ICH_BCIS | ICH_LVBCI)); 7688c2ecf20Sopenharmony_ci} 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_cistatic irqreturn_t snd_intel8x0_interrupt(int irq, void *dev_id) 7718c2ecf20Sopenharmony_ci{ 7728c2ecf20Sopenharmony_ci struct intel8x0 *chip = dev_id; 7738c2ecf20Sopenharmony_ci struct ichdev *ichdev; 7748c2ecf20Sopenharmony_ci unsigned int status; 7758c2ecf20Sopenharmony_ci unsigned int i; 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci status = igetdword(chip, chip->int_sta_reg); 7788c2ecf20Sopenharmony_ci if (status == 0xffffffff) /* we are not yet resumed */ 7798c2ecf20Sopenharmony_ci return IRQ_NONE; 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci if ((status & chip->int_sta_mask) == 0) { 7828c2ecf20Sopenharmony_ci if (status) { 7838c2ecf20Sopenharmony_ci /* ack */ 7848c2ecf20Sopenharmony_ci iputdword(chip, chip->int_sta_reg, status); 7858c2ecf20Sopenharmony_ci if (! chip->buggy_irq) 7868c2ecf20Sopenharmony_ci status = 0; 7878c2ecf20Sopenharmony_ci } 7888c2ecf20Sopenharmony_ci return IRQ_RETVAL(status); 7898c2ecf20Sopenharmony_ci } 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci for (i = 0; i < chip->bdbars_count; i++) { 7928c2ecf20Sopenharmony_ci ichdev = &chip->ichd[i]; 7938c2ecf20Sopenharmony_ci if (status & ichdev->int_sta_mask) 7948c2ecf20Sopenharmony_ci snd_intel8x0_update(chip, ichdev); 7958c2ecf20Sopenharmony_ci } 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci /* ack them */ 7988c2ecf20Sopenharmony_ci iputdword(chip, chip->int_sta_reg, status & chip->int_sta_mask); 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci return IRQ_HANDLED; 8018c2ecf20Sopenharmony_ci} 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci/* 8048c2ecf20Sopenharmony_ci * PCM part 8058c2ecf20Sopenharmony_ci */ 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_cistatic int snd_intel8x0_pcm_trigger(struct snd_pcm_substream *substream, int cmd) 8088c2ecf20Sopenharmony_ci{ 8098c2ecf20Sopenharmony_ci struct intel8x0 *chip = snd_pcm_substream_chip(substream); 8108c2ecf20Sopenharmony_ci struct ichdev *ichdev = get_ichdev(substream); 8118c2ecf20Sopenharmony_ci unsigned char val = 0; 8128c2ecf20Sopenharmony_ci unsigned long port = ichdev->reg_offset; 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci switch (cmd) { 8158c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_RESUME: 8168c2ecf20Sopenharmony_ci ichdev->suspended = 0; 8178c2ecf20Sopenharmony_ci fallthrough; 8188c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 8198c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 8208c2ecf20Sopenharmony_ci val = ICH_IOCE | ICH_STARTBM; 8218c2ecf20Sopenharmony_ci ichdev->last_pos = ichdev->position; 8228c2ecf20Sopenharmony_ci break; 8238c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_SUSPEND: 8248c2ecf20Sopenharmony_ci ichdev->suspended = 1; 8258c2ecf20Sopenharmony_ci fallthrough; 8268c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 8278c2ecf20Sopenharmony_ci val = 0; 8288c2ecf20Sopenharmony_ci break; 8298c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 8308c2ecf20Sopenharmony_ci val = ICH_IOCE; 8318c2ecf20Sopenharmony_ci break; 8328c2ecf20Sopenharmony_ci default: 8338c2ecf20Sopenharmony_ci return -EINVAL; 8348c2ecf20Sopenharmony_ci } 8358c2ecf20Sopenharmony_ci iputbyte(chip, port + ICH_REG_OFF_CR, val); 8368c2ecf20Sopenharmony_ci if (cmd == SNDRV_PCM_TRIGGER_STOP) { 8378c2ecf20Sopenharmony_ci /* wait until DMA stopped */ 8388c2ecf20Sopenharmony_ci while (!(igetbyte(chip, port + ichdev->roff_sr) & ICH_DCH)) ; 8398c2ecf20Sopenharmony_ci /* reset whole DMA things */ 8408c2ecf20Sopenharmony_ci iputbyte(chip, port + ICH_REG_OFF_CR, ICH_RESETREGS); 8418c2ecf20Sopenharmony_ci } 8428c2ecf20Sopenharmony_ci return 0; 8438c2ecf20Sopenharmony_ci} 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_cistatic int snd_intel8x0_ali_trigger(struct snd_pcm_substream *substream, int cmd) 8468c2ecf20Sopenharmony_ci{ 8478c2ecf20Sopenharmony_ci struct intel8x0 *chip = snd_pcm_substream_chip(substream); 8488c2ecf20Sopenharmony_ci struct ichdev *ichdev = get_ichdev(substream); 8498c2ecf20Sopenharmony_ci unsigned long port = ichdev->reg_offset; 8508c2ecf20Sopenharmony_ci static const int fiforeg[] = { 8518c2ecf20Sopenharmony_ci ICHREG(ALI_FIFOCR1), ICHREG(ALI_FIFOCR2), ICHREG(ALI_FIFOCR3) 8528c2ecf20Sopenharmony_ci }; 8538c2ecf20Sopenharmony_ci unsigned int val, fifo; 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci val = igetdword(chip, ICHREG(ALI_DMACR)); 8568c2ecf20Sopenharmony_ci switch (cmd) { 8578c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_RESUME: 8588c2ecf20Sopenharmony_ci ichdev->suspended = 0; 8598c2ecf20Sopenharmony_ci fallthrough; 8608c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 8618c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 8628c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 8638c2ecf20Sopenharmony_ci /* clear FIFO for synchronization of channels */ 8648c2ecf20Sopenharmony_ci fifo = igetdword(chip, fiforeg[ichdev->ali_slot / 4]); 8658c2ecf20Sopenharmony_ci fifo &= ~(0xff << (ichdev->ali_slot % 4)); 8668c2ecf20Sopenharmony_ci fifo |= 0x83 << (ichdev->ali_slot % 4); 8678c2ecf20Sopenharmony_ci iputdword(chip, fiforeg[ichdev->ali_slot / 4], fifo); 8688c2ecf20Sopenharmony_ci } 8698c2ecf20Sopenharmony_ci iputbyte(chip, port + ICH_REG_OFF_CR, ICH_IOCE); 8708c2ecf20Sopenharmony_ci val &= ~(1 << (ichdev->ali_slot + 16)); /* clear PAUSE flag */ 8718c2ecf20Sopenharmony_ci /* start DMA */ 8728c2ecf20Sopenharmony_ci iputdword(chip, ICHREG(ALI_DMACR), val | (1 << ichdev->ali_slot)); 8738c2ecf20Sopenharmony_ci break; 8748c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_SUSPEND: 8758c2ecf20Sopenharmony_ci ichdev->suspended = 1; 8768c2ecf20Sopenharmony_ci fallthrough; 8778c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 8788c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 8798c2ecf20Sopenharmony_ci /* pause */ 8808c2ecf20Sopenharmony_ci iputdword(chip, ICHREG(ALI_DMACR), val | (1 << (ichdev->ali_slot + 16))); 8818c2ecf20Sopenharmony_ci iputbyte(chip, port + ICH_REG_OFF_CR, 0); 8828c2ecf20Sopenharmony_ci while (igetbyte(chip, port + ICH_REG_OFF_CR)) 8838c2ecf20Sopenharmony_ci ; 8848c2ecf20Sopenharmony_ci if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH) 8858c2ecf20Sopenharmony_ci break; 8868c2ecf20Sopenharmony_ci /* reset whole DMA things */ 8878c2ecf20Sopenharmony_ci iputbyte(chip, port + ICH_REG_OFF_CR, ICH_RESETREGS); 8888c2ecf20Sopenharmony_ci /* clear interrupts */ 8898c2ecf20Sopenharmony_ci iputbyte(chip, port + ICH_REG_OFF_SR, 8908c2ecf20Sopenharmony_ci igetbyte(chip, port + ICH_REG_OFF_SR) | 0x1e); 8918c2ecf20Sopenharmony_ci iputdword(chip, ICHREG(ALI_INTERRUPTSR), 8928c2ecf20Sopenharmony_ci igetdword(chip, ICHREG(ALI_INTERRUPTSR)) & ichdev->int_sta_mask); 8938c2ecf20Sopenharmony_ci break; 8948c2ecf20Sopenharmony_ci default: 8958c2ecf20Sopenharmony_ci return -EINVAL; 8968c2ecf20Sopenharmony_ci } 8978c2ecf20Sopenharmony_ci return 0; 8988c2ecf20Sopenharmony_ci} 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_cistatic int snd_intel8x0_hw_params(struct snd_pcm_substream *substream, 9018c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *hw_params) 9028c2ecf20Sopenharmony_ci{ 9038c2ecf20Sopenharmony_ci struct intel8x0 *chip = snd_pcm_substream_chip(substream); 9048c2ecf20Sopenharmony_ci struct ichdev *ichdev = get_ichdev(substream); 9058c2ecf20Sopenharmony_ci int dbl = params_rate(hw_params) > 48000; 9068c2ecf20Sopenharmony_ci int err; 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci if (ichdev->pcm_open_flag) { 9098c2ecf20Sopenharmony_ci snd_ac97_pcm_close(ichdev->pcm); 9108c2ecf20Sopenharmony_ci ichdev->pcm_open_flag = 0; 9118c2ecf20Sopenharmony_ci ichdev->prepared = 0; 9128c2ecf20Sopenharmony_ci } 9138c2ecf20Sopenharmony_ci err = snd_ac97_pcm_open(ichdev->pcm, params_rate(hw_params), 9148c2ecf20Sopenharmony_ci params_channels(hw_params), 9158c2ecf20Sopenharmony_ci ichdev->pcm->r[dbl].slots); 9168c2ecf20Sopenharmony_ci if (err >= 0) { 9178c2ecf20Sopenharmony_ci ichdev->pcm_open_flag = 1; 9188c2ecf20Sopenharmony_ci /* Force SPDIF setting */ 9198c2ecf20Sopenharmony_ci if (ichdev->ichd == ICHD_PCMOUT && chip->spdif_idx < 0) 9208c2ecf20Sopenharmony_ci snd_ac97_set_rate(ichdev->pcm->r[0].codec[0], AC97_SPDIF, 9218c2ecf20Sopenharmony_ci params_rate(hw_params)); 9228c2ecf20Sopenharmony_ci } 9238c2ecf20Sopenharmony_ci return err; 9248c2ecf20Sopenharmony_ci} 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_cistatic int snd_intel8x0_hw_free(struct snd_pcm_substream *substream) 9278c2ecf20Sopenharmony_ci{ 9288c2ecf20Sopenharmony_ci struct ichdev *ichdev = get_ichdev(substream); 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci if (ichdev->pcm_open_flag) { 9318c2ecf20Sopenharmony_ci snd_ac97_pcm_close(ichdev->pcm); 9328c2ecf20Sopenharmony_ci ichdev->pcm_open_flag = 0; 9338c2ecf20Sopenharmony_ci ichdev->prepared = 0; 9348c2ecf20Sopenharmony_ci } 9358c2ecf20Sopenharmony_ci return 0; 9368c2ecf20Sopenharmony_ci} 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_cistatic void snd_intel8x0_setup_pcm_out(struct intel8x0 *chip, 9398c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime) 9408c2ecf20Sopenharmony_ci{ 9418c2ecf20Sopenharmony_ci unsigned int cnt; 9428c2ecf20Sopenharmony_ci int dbl = runtime->rate > 48000; 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci spin_lock_irq(&chip->reg_lock); 9458c2ecf20Sopenharmony_ci switch (chip->device_type) { 9468c2ecf20Sopenharmony_ci case DEVICE_ALI: 9478c2ecf20Sopenharmony_ci cnt = igetdword(chip, ICHREG(ALI_SCR)); 9488c2ecf20Sopenharmony_ci cnt &= ~ICH_ALI_SC_PCM_246_MASK; 9498c2ecf20Sopenharmony_ci if (runtime->channels == 4 || dbl) 9508c2ecf20Sopenharmony_ci cnt |= ICH_ALI_SC_PCM_4; 9518c2ecf20Sopenharmony_ci else if (runtime->channels == 6) 9528c2ecf20Sopenharmony_ci cnt |= ICH_ALI_SC_PCM_6; 9538c2ecf20Sopenharmony_ci iputdword(chip, ICHREG(ALI_SCR), cnt); 9548c2ecf20Sopenharmony_ci break; 9558c2ecf20Sopenharmony_ci case DEVICE_SIS: 9568c2ecf20Sopenharmony_ci cnt = igetdword(chip, ICHREG(GLOB_CNT)); 9578c2ecf20Sopenharmony_ci cnt &= ~ICH_SIS_PCM_246_MASK; 9588c2ecf20Sopenharmony_ci if (runtime->channels == 4 || dbl) 9598c2ecf20Sopenharmony_ci cnt |= ICH_SIS_PCM_4; 9608c2ecf20Sopenharmony_ci else if (runtime->channels == 6) 9618c2ecf20Sopenharmony_ci cnt |= ICH_SIS_PCM_6; 9628c2ecf20Sopenharmony_ci iputdword(chip, ICHREG(GLOB_CNT), cnt); 9638c2ecf20Sopenharmony_ci break; 9648c2ecf20Sopenharmony_ci default: 9658c2ecf20Sopenharmony_ci cnt = igetdword(chip, ICHREG(GLOB_CNT)); 9668c2ecf20Sopenharmony_ci cnt &= ~(ICH_PCM_246_MASK | ICH_PCM_20BIT); 9678c2ecf20Sopenharmony_ci if (runtime->channels == 4 || dbl) 9688c2ecf20Sopenharmony_ci cnt |= ICH_PCM_4; 9698c2ecf20Sopenharmony_ci else if (runtime->channels == 6) 9708c2ecf20Sopenharmony_ci cnt |= ICH_PCM_6; 9718c2ecf20Sopenharmony_ci else if (runtime->channels == 8) 9728c2ecf20Sopenharmony_ci cnt |= ICH_PCM_8; 9738c2ecf20Sopenharmony_ci if (chip->device_type == DEVICE_NFORCE) { 9748c2ecf20Sopenharmony_ci /* reset to 2ch once to keep the 6 channel data in alignment, 9758c2ecf20Sopenharmony_ci * to start from Front Left always 9768c2ecf20Sopenharmony_ci */ 9778c2ecf20Sopenharmony_ci if (cnt & ICH_PCM_246_MASK) { 9788c2ecf20Sopenharmony_ci iputdword(chip, ICHREG(GLOB_CNT), cnt & ~ICH_PCM_246_MASK); 9798c2ecf20Sopenharmony_ci spin_unlock_irq(&chip->reg_lock); 9808c2ecf20Sopenharmony_ci msleep(50); /* grrr... */ 9818c2ecf20Sopenharmony_ci spin_lock_irq(&chip->reg_lock); 9828c2ecf20Sopenharmony_ci } 9838c2ecf20Sopenharmony_ci } else if (chip->device_type == DEVICE_INTEL_ICH4) { 9848c2ecf20Sopenharmony_ci if (runtime->sample_bits > 16) 9858c2ecf20Sopenharmony_ci cnt |= ICH_PCM_20BIT; 9868c2ecf20Sopenharmony_ci } 9878c2ecf20Sopenharmony_ci iputdword(chip, ICHREG(GLOB_CNT), cnt); 9888c2ecf20Sopenharmony_ci break; 9898c2ecf20Sopenharmony_ci } 9908c2ecf20Sopenharmony_ci spin_unlock_irq(&chip->reg_lock); 9918c2ecf20Sopenharmony_ci} 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_cistatic int snd_intel8x0_pcm_prepare(struct snd_pcm_substream *substream) 9948c2ecf20Sopenharmony_ci{ 9958c2ecf20Sopenharmony_ci struct intel8x0 *chip = snd_pcm_substream_chip(substream); 9968c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 9978c2ecf20Sopenharmony_ci struct ichdev *ichdev = get_ichdev(substream); 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci ichdev->physbuf = runtime->dma_addr; 10008c2ecf20Sopenharmony_ci ichdev->size = snd_pcm_lib_buffer_bytes(substream); 10018c2ecf20Sopenharmony_ci ichdev->fragsize = snd_pcm_lib_period_bytes(substream); 10028c2ecf20Sopenharmony_ci if (ichdev->ichd == ICHD_PCMOUT) { 10038c2ecf20Sopenharmony_ci snd_intel8x0_setup_pcm_out(chip, runtime); 10048c2ecf20Sopenharmony_ci if (chip->device_type == DEVICE_INTEL_ICH4) 10058c2ecf20Sopenharmony_ci ichdev->pos_shift = (runtime->sample_bits > 16) ? 2 : 1; 10068c2ecf20Sopenharmony_ci } 10078c2ecf20Sopenharmony_ci snd_intel8x0_setup_periods(chip, ichdev); 10088c2ecf20Sopenharmony_ci ichdev->prepared = 1; 10098c2ecf20Sopenharmony_ci return 0; 10108c2ecf20Sopenharmony_ci} 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_cistatic snd_pcm_uframes_t snd_intel8x0_pcm_pointer(struct snd_pcm_substream *substream) 10138c2ecf20Sopenharmony_ci{ 10148c2ecf20Sopenharmony_ci struct intel8x0 *chip = snd_pcm_substream_chip(substream); 10158c2ecf20Sopenharmony_ci struct ichdev *ichdev = get_ichdev(substream); 10168c2ecf20Sopenharmony_ci size_t ptr1, ptr; 10178c2ecf20Sopenharmony_ci int civ, timeout = 10; 10188c2ecf20Sopenharmony_ci unsigned int position; 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci spin_lock(&chip->reg_lock); 10218c2ecf20Sopenharmony_ci do { 10228c2ecf20Sopenharmony_ci civ = igetbyte(chip, ichdev->reg_offset + ICH_REG_OFF_CIV); 10238c2ecf20Sopenharmony_ci ptr1 = igetword(chip, ichdev->reg_offset + ichdev->roff_picb); 10248c2ecf20Sopenharmony_ci position = ichdev->position; 10258c2ecf20Sopenharmony_ci if (ptr1 == 0) { 10268c2ecf20Sopenharmony_ci udelay(10); 10278c2ecf20Sopenharmony_ci continue; 10288c2ecf20Sopenharmony_ci } 10298c2ecf20Sopenharmony_ci if (civ != igetbyte(chip, ichdev->reg_offset + ICH_REG_OFF_CIV)) 10308c2ecf20Sopenharmony_ci continue; 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci /* IO read operation is very expensive inside virtual machine 10338c2ecf20Sopenharmony_ci * as it is emulated. The probability that subsequent PICB read 10348c2ecf20Sopenharmony_ci * will return different result is high enough to loop till 10358c2ecf20Sopenharmony_ci * timeout here. 10368c2ecf20Sopenharmony_ci * Same CIV is strict enough condition to be sure that PICB 10378c2ecf20Sopenharmony_ci * is valid inside VM on emulated card. */ 10388c2ecf20Sopenharmony_ci if (chip->inside_vm) 10398c2ecf20Sopenharmony_ci break; 10408c2ecf20Sopenharmony_ci if (ptr1 == igetword(chip, ichdev->reg_offset + ichdev->roff_picb)) 10418c2ecf20Sopenharmony_ci break; 10428c2ecf20Sopenharmony_ci } while (timeout--); 10438c2ecf20Sopenharmony_ci ptr = ichdev->last_pos; 10448c2ecf20Sopenharmony_ci if (ptr1 != 0) { 10458c2ecf20Sopenharmony_ci ptr1 <<= ichdev->pos_shift; 10468c2ecf20Sopenharmony_ci ptr = ichdev->fragsize1 - ptr1; 10478c2ecf20Sopenharmony_ci ptr += position; 10488c2ecf20Sopenharmony_ci if (ptr < ichdev->last_pos) { 10498c2ecf20Sopenharmony_ci unsigned int pos_base, last_base; 10508c2ecf20Sopenharmony_ci pos_base = position / ichdev->fragsize1; 10518c2ecf20Sopenharmony_ci last_base = ichdev->last_pos / ichdev->fragsize1; 10528c2ecf20Sopenharmony_ci /* another sanity check; ptr1 can go back to full 10538c2ecf20Sopenharmony_ci * before the base position is updated 10548c2ecf20Sopenharmony_ci */ 10558c2ecf20Sopenharmony_ci if (pos_base == last_base) 10568c2ecf20Sopenharmony_ci ptr = ichdev->last_pos; 10578c2ecf20Sopenharmony_ci } 10588c2ecf20Sopenharmony_ci } 10598c2ecf20Sopenharmony_ci ichdev->last_pos = ptr; 10608c2ecf20Sopenharmony_ci spin_unlock(&chip->reg_lock); 10618c2ecf20Sopenharmony_ci if (ptr >= ichdev->size) 10628c2ecf20Sopenharmony_ci return 0; 10638c2ecf20Sopenharmony_ci return bytes_to_frames(substream->runtime, ptr); 10648c2ecf20Sopenharmony_ci} 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_cistatic const struct snd_pcm_hardware snd_intel8x0_stream = 10678c2ecf20Sopenharmony_ci{ 10688c2ecf20Sopenharmony_ci .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | 10698c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_BLOCK_TRANSFER | 10708c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_MMAP_VALID | 10718c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_PAUSE | 10728c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_RESUME), 10738c2ecf20Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE, 10748c2ecf20Sopenharmony_ci .rates = SNDRV_PCM_RATE_48000, 10758c2ecf20Sopenharmony_ci .rate_min = 48000, 10768c2ecf20Sopenharmony_ci .rate_max = 48000, 10778c2ecf20Sopenharmony_ci .channels_min = 2, 10788c2ecf20Sopenharmony_ci .channels_max = 2, 10798c2ecf20Sopenharmony_ci .buffer_bytes_max = 128 * 1024, 10808c2ecf20Sopenharmony_ci .period_bytes_min = 32, 10818c2ecf20Sopenharmony_ci .period_bytes_max = 128 * 1024, 10828c2ecf20Sopenharmony_ci .periods_min = 1, 10838c2ecf20Sopenharmony_ci .periods_max = 1024, 10848c2ecf20Sopenharmony_ci .fifo_size = 0, 10858c2ecf20Sopenharmony_ci}; 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_cistatic const unsigned int channels4[] = { 10888c2ecf20Sopenharmony_ci 2, 4, 10898c2ecf20Sopenharmony_ci}; 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_cistatic const struct snd_pcm_hw_constraint_list hw_constraints_channels4 = { 10928c2ecf20Sopenharmony_ci .count = ARRAY_SIZE(channels4), 10938c2ecf20Sopenharmony_ci .list = channels4, 10948c2ecf20Sopenharmony_ci .mask = 0, 10958c2ecf20Sopenharmony_ci}; 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_cistatic const unsigned int channels6[] = { 10988c2ecf20Sopenharmony_ci 2, 4, 6, 10998c2ecf20Sopenharmony_ci}; 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_cistatic const struct snd_pcm_hw_constraint_list hw_constraints_channels6 = { 11028c2ecf20Sopenharmony_ci .count = ARRAY_SIZE(channels6), 11038c2ecf20Sopenharmony_ci .list = channels6, 11048c2ecf20Sopenharmony_ci .mask = 0, 11058c2ecf20Sopenharmony_ci}; 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_cistatic const unsigned int channels8[] = { 11088c2ecf20Sopenharmony_ci 2, 4, 6, 8, 11098c2ecf20Sopenharmony_ci}; 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_cistatic const struct snd_pcm_hw_constraint_list hw_constraints_channels8 = { 11128c2ecf20Sopenharmony_ci .count = ARRAY_SIZE(channels8), 11138c2ecf20Sopenharmony_ci .list = channels8, 11148c2ecf20Sopenharmony_ci .mask = 0, 11158c2ecf20Sopenharmony_ci}; 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_cistatic int snd_intel8x0_pcm_open(struct snd_pcm_substream *substream, struct ichdev *ichdev) 11188c2ecf20Sopenharmony_ci{ 11198c2ecf20Sopenharmony_ci struct intel8x0 *chip = snd_pcm_substream_chip(substream); 11208c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 11218c2ecf20Sopenharmony_ci int err; 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci ichdev->substream = substream; 11248c2ecf20Sopenharmony_ci runtime->hw = snd_intel8x0_stream; 11258c2ecf20Sopenharmony_ci runtime->hw.rates = ichdev->pcm->rates; 11268c2ecf20Sopenharmony_ci snd_pcm_limit_hw_rates(runtime); 11278c2ecf20Sopenharmony_ci if (chip->device_type == DEVICE_SIS) { 11288c2ecf20Sopenharmony_ci runtime->hw.buffer_bytes_max = 64*1024; 11298c2ecf20Sopenharmony_ci runtime->hw.period_bytes_max = 64*1024; 11308c2ecf20Sopenharmony_ci } 11318c2ecf20Sopenharmony_ci if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) 11328c2ecf20Sopenharmony_ci return err; 11338c2ecf20Sopenharmony_ci runtime->private_data = ichdev; 11348c2ecf20Sopenharmony_ci return 0; 11358c2ecf20Sopenharmony_ci} 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_cistatic int snd_intel8x0_playback_open(struct snd_pcm_substream *substream) 11388c2ecf20Sopenharmony_ci{ 11398c2ecf20Sopenharmony_ci struct intel8x0 *chip = snd_pcm_substream_chip(substream); 11408c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 11418c2ecf20Sopenharmony_ci int err; 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci err = snd_intel8x0_pcm_open(substream, &chip->ichd[ICHD_PCMOUT]); 11448c2ecf20Sopenharmony_ci if (err < 0) 11458c2ecf20Sopenharmony_ci return err; 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci if (chip->multi8) { 11488c2ecf20Sopenharmony_ci runtime->hw.channels_max = 8; 11498c2ecf20Sopenharmony_ci snd_pcm_hw_constraint_list(runtime, 0, 11508c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_CHANNELS, 11518c2ecf20Sopenharmony_ci &hw_constraints_channels8); 11528c2ecf20Sopenharmony_ci } else if (chip->multi6) { 11538c2ecf20Sopenharmony_ci runtime->hw.channels_max = 6; 11548c2ecf20Sopenharmony_ci snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 11558c2ecf20Sopenharmony_ci &hw_constraints_channels6); 11568c2ecf20Sopenharmony_ci } else if (chip->multi4) { 11578c2ecf20Sopenharmony_ci runtime->hw.channels_max = 4; 11588c2ecf20Sopenharmony_ci snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 11598c2ecf20Sopenharmony_ci &hw_constraints_channels4); 11608c2ecf20Sopenharmony_ci } 11618c2ecf20Sopenharmony_ci if (chip->dra) { 11628c2ecf20Sopenharmony_ci snd_ac97_pcm_double_rate_rules(runtime); 11638c2ecf20Sopenharmony_ci } 11648c2ecf20Sopenharmony_ci if (chip->smp20bit) { 11658c2ecf20Sopenharmony_ci runtime->hw.formats |= SNDRV_PCM_FMTBIT_S32_LE; 11668c2ecf20Sopenharmony_ci snd_pcm_hw_constraint_msbits(runtime, 0, 32, 20); 11678c2ecf20Sopenharmony_ci } 11688c2ecf20Sopenharmony_ci return 0; 11698c2ecf20Sopenharmony_ci} 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_cistatic int snd_intel8x0_playback_close(struct snd_pcm_substream *substream) 11728c2ecf20Sopenharmony_ci{ 11738c2ecf20Sopenharmony_ci struct intel8x0 *chip = snd_pcm_substream_chip(substream); 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci chip->ichd[ICHD_PCMOUT].substream = NULL; 11768c2ecf20Sopenharmony_ci return 0; 11778c2ecf20Sopenharmony_ci} 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_cistatic int snd_intel8x0_capture_open(struct snd_pcm_substream *substream) 11808c2ecf20Sopenharmony_ci{ 11818c2ecf20Sopenharmony_ci struct intel8x0 *chip = snd_pcm_substream_chip(substream); 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci return snd_intel8x0_pcm_open(substream, &chip->ichd[ICHD_PCMIN]); 11848c2ecf20Sopenharmony_ci} 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_cistatic int snd_intel8x0_capture_close(struct snd_pcm_substream *substream) 11878c2ecf20Sopenharmony_ci{ 11888c2ecf20Sopenharmony_ci struct intel8x0 *chip = snd_pcm_substream_chip(substream); 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci chip->ichd[ICHD_PCMIN].substream = NULL; 11918c2ecf20Sopenharmony_ci return 0; 11928c2ecf20Sopenharmony_ci} 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_cistatic int snd_intel8x0_mic_open(struct snd_pcm_substream *substream) 11958c2ecf20Sopenharmony_ci{ 11968c2ecf20Sopenharmony_ci struct intel8x0 *chip = snd_pcm_substream_chip(substream); 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci return snd_intel8x0_pcm_open(substream, &chip->ichd[ICHD_MIC]); 11998c2ecf20Sopenharmony_ci} 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_cistatic int snd_intel8x0_mic_close(struct snd_pcm_substream *substream) 12028c2ecf20Sopenharmony_ci{ 12038c2ecf20Sopenharmony_ci struct intel8x0 *chip = snd_pcm_substream_chip(substream); 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci chip->ichd[ICHD_MIC].substream = NULL; 12068c2ecf20Sopenharmony_ci return 0; 12078c2ecf20Sopenharmony_ci} 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_cistatic int snd_intel8x0_mic2_open(struct snd_pcm_substream *substream) 12108c2ecf20Sopenharmony_ci{ 12118c2ecf20Sopenharmony_ci struct intel8x0 *chip = snd_pcm_substream_chip(substream); 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci return snd_intel8x0_pcm_open(substream, &chip->ichd[ICHD_MIC2]); 12148c2ecf20Sopenharmony_ci} 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_cistatic int snd_intel8x0_mic2_close(struct snd_pcm_substream *substream) 12178c2ecf20Sopenharmony_ci{ 12188c2ecf20Sopenharmony_ci struct intel8x0 *chip = snd_pcm_substream_chip(substream); 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci chip->ichd[ICHD_MIC2].substream = NULL; 12218c2ecf20Sopenharmony_ci return 0; 12228c2ecf20Sopenharmony_ci} 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_cistatic int snd_intel8x0_capture2_open(struct snd_pcm_substream *substream) 12258c2ecf20Sopenharmony_ci{ 12268c2ecf20Sopenharmony_ci struct intel8x0 *chip = snd_pcm_substream_chip(substream); 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci return snd_intel8x0_pcm_open(substream, &chip->ichd[ICHD_PCM2IN]); 12298c2ecf20Sopenharmony_ci} 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_cistatic int snd_intel8x0_capture2_close(struct snd_pcm_substream *substream) 12328c2ecf20Sopenharmony_ci{ 12338c2ecf20Sopenharmony_ci struct intel8x0 *chip = snd_pcm_substream_chip(substream); 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci chip->ichd[ICHD_PCM2IN].substream = NULL; 12368c2ecf20Sopenharmony_ci return 0; 12378c2ecf20Sopenharmony_ci} 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_cistatic int snd_intel8x0_spdif_open(struct snd_pcm_substream *substream) 12408c2ecf20Sopenharmony_ci{ 12418c2ecf20Sopenharmony_ci struct intel8x0 *chip = snd_pcm_substream_chip(substream); 12428c2ecf20Sopenharmony_ci int idx = chip->device_type == DEVICE_NFORCE ? NVD_SPBAR : ICHD_SPBAR; 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci return snd_intel8x0_pcm_open(substream, &chip->ichd[idx]); 12458c2ecf20Sopenharmony_ci} 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_cistatic int snd_intel8x0_spdif_close(struct snd_pcm_substream *substream) 12488c2ecf20Sopenharmony_ci{ 12498c2ecf20Sopenharmony_ci struct intel8x0 *chip = snd_pcm_substream_chip(substream); 12508c2ecf20Sopenharmony_ci int idx = chip->device_type == DEVICE_NFORCE ? NVD_SPBAR : ICHD_SPBAR; 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci chip->ichd[idx].substream = NULL; 12538c2ecf20Sopenharmony_ci return 0; 12548c2ecf20Sopenharmony_ci} 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_cistatic int snd_intel8x0_ali_ac97spdifout_open(struct snd_pcm_substream *substream) 12578c2ecf20Sopenharmony_ci{ 12588c2ecf20Sopenharmony_ci struct intel8x0 *chip = snd_pcm_substream_chip(substream); 12598c2ecf20Sopenharmony_ci unsigned int val; 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci spin_lock_irq(&chip->reg_lock); 12628c2ecf20Sopenharmony_ci val = igetdword(chip, ICHREG(ALI_INTERFACECR)); 12638c2ecf20Sopenharmony_ci val |= ICH_ALI_IF_AC97SP; 12648c2ecf20Sopenharmony_ci iputdword(chip, ICHREG(ALI_INTERFACECR), val); 12658c2ecf20Sopenharmony_ci /* also needs to set ALI_SC_CODEC_SPDF correctly */ 12668c2ecf20Sopenharmony_ci spin_unlock_irq(&chip->reg_lock); 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci return snd_intel8x0_pcm_open(substream, &chip->ichd[ALID_AC97SPDIFOUT]); 12698c2ecf20Sopenharmony_ci} 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_cistatic int snd_intel8x0_ali_ac97spdifout_close(struct snd_pcm_substream *substream) 12728c2ecf20Sopenharmony_ci{ 12738c2ecf20Sopenharmony_ci struct intel8x0 *chip = snd_pcm_substream_chip(substream); 12748c2ecf20Sopenharmony_ci unsigned int val; 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci chip->ichd[ALID_AC97SPDIFOUT].substream = NULL; 12778c2ecf20Sopenharmony_ci spin_lock_irq(&chip->reg_lock); 12788c2ecf20Sopenharmony_ci val = igetdword(chip, ICHREG(ALI_INTERFACECR)); 12798c2ecf20Sopenharmony_ci val &= ~ICH_ALI_IF_AC97SP; 12808c2ecf20Sopenharmony_ci iputdword(chip, ICHREG(ALI_INTERFACECR), val); 12818c2ecf20Sopenharmony_ci spin_unlock_irq(&chip->reg_lock); 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci return 0; 12848c2ecf20Sopenharmony_ci} 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci#if 0 // NYI 12878c2ecf20Sopenharmony_cistatic int snd_intel8x0_ali_spdifin_open(struct snd_pcm_substream *substream) 12888c2ecf20Sopenharmony_ci{ 12898c2ecf20Sopenharmony_ci struct intel8x0 *chip = snd_pcm_substream_chip(substream); 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci return snd_intel8x0_pcm_open(substream, &chip->ichd[ALID_SPDIFIN]); 12928c2ecf20Sopenharmony_ci} 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_cistatic int snd_intel8x0_ali_spdifin_close(struct snd_pcm_substream *substream) 12958c2ecf20Sopenharmony_ci{ 12968c2ecf20Sopenharmony_ci struct intel8x0 *chip = snd_pcm_substream_chip(substream); 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci chip->ichd[ALID_SPDIFIN].substream = NULL; 12998c2ecf20Sopenharmony_ci return 0; 13008c2ecf20Sopenharmony_ci} 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_cistatic int snd_intel8x0_ali_spdifout_open(struct snd_pcm_substream *substream) 13038c2ecf20Sopenharmony_ci{ 13048c2ecf20Sopenharmony_ci struct intel8x0 *chip = snd_pcm_substream_chip(substream); 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci return snd_intel8x0_pcm_open(substream, &chip->ichd[ALID_SPDIFOUT]); 13078c2ecf20Sopenharmony_ci} 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_cistatic int snd_intel8x0_ali_spdifout_close(struct snd_pcm_substream *substream) 13108c2ecf20Sopenharmony_ci{ 13118c2ecf20Sopenharmony_ci struct intel8x0 *chip = snd_pcm_substream_chip(substream); 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci chip->ichd[ALID_SPDIFOUT].substream = NULL; 13148c2ecf20Sopenharmony_ci return 0; 13158c2ecf20Sopenharmony_ci} 13168c2ecf20Sopenharmony_ci#endif 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_cistatic const struct snd_pcm_ops snd_intel8x0_playback_ops = { 13198c2ecf20Sopenharmony_ci .open = snd_intel8x0_playback_open, 13208c2ecf20Sopenharmony_ci .close = snd_intel8x0_playback_close, 13218c2ecf20Sopenharmony_ci .hw_params = snd_intel8x0_hw_params, 13228c2ecf20Sopenharmony_ci .hw_free = snd_intel8x0_hw_free, 13238c2ecf20Sopenharmony_ci .prepare = snd_intel8x0_pcm_prepare, 13248c2ecf20Sopenharmony_ci .trigger = snd_intel8x0_pcm_trigger, 13258c2ecf20Sopenharmony_ci .pointer = snd_intel8x0_pcm_pointer, 13268c2ecf20Sopenharmony_ci}; 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_cistatic const struct snd_pcm_ops snd_intel8x0_capture_ops = { 13298c2ecf20Sopenharmony_ci .open = snd_intel8x0_capture_open, 13308c2ecf20Sopenharmony_ci .close = snd_intel8x0_capture_close, 13318c2ecf20Sopenharmony_ci .hw_params = snd_intel8x0_hw_params, 13328c2ecf20Sopenharmony_ci .hw_free = snd_intel8x0_hw_free, 13338c2ecf20Sopenharmony_ci .prepare = snd_intel8x0_pcm_prepare, 13348c2ecf20Sopenharmony_ci .trigger = snd_intel8x0_pcm_trigger, 13358c2ecf20Sopenharmony_ci .pointer = snd_intel8x0_pcm_pointer, 13368c2ecf20Sopenharmony_ci}; 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_cistatic const struct snd_pcm_ops snd_intel8x0_capture_mic_ops = { 13398c2ecf20Sopenharmony_ci .open = snd_intel8x0_mic_open, 13408c2ecf20Sopenharmony_ci .close = snd_intel8x0_mic_close, 13418c2ecf20Sopenharmony_ci .hw_params = snd_intel8x0_hw_params, 13428c2ecf20Sopenharmony_ci .hw_free = snd_intel8x0_hw_free, 13438c2ecf20Sopenharmony_ci .prepare = snd_intel8x0_pcm_prepare, 13448c2ecf20Sopenharmony_ci .trigger = snd_intel8x0_pcm_trigger, 13458c2ecf20Sopenharmony_ci .pointer = snd_intel8x0_pcm_pointer, 13468c2ecf20Sopenharmony_ci}; 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_cistatic const struct snd_pcm_ops snd_intel8x0_capture_mic2_ops = { 13498c2ecf20Sopenharmony_ci .open = snd_intel8x0_mic2_open, 13508c2ecf20Sopenharmony_ci .close = snd_intel8x0_mic2_close, 13518c2ecf20Sopenharmony_ci .hw_params = snd_intel8x0_hw_params, 13528c2ecf20Sopenharmony_ci .hw_free = snd_intel8x0_hw_free, 13538c2ecf20Sopenharmony_ci .prepare = snd_intel8x0_pcm_prepare, 13548c2ecf20Sopenharmony_ci .trigger = snd_intel8x0_pcm_trigger, 13558c2ecf20Sopenharmony_ci .pointer = snd_intel8x0_pcm_pointer, 13568c2ecf20Sopenharmony_ci}; 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_cistatic const struct snd_pcm_ops snd_intel8x0_capture2_ops = { 13598c2ecf20Sopenharmony_ci .open = snd_intel8x0_capture2_open, 13608c2ecf20Sopenharmony_ci .close = snd_intel8x0_capture2_close, 13618c2ecf20Sopenharmony_ci .hw_params = snd_intel8x0_hw_params, 13628c2ecf20Sopenharmony_ci .hw_free = snd_intel8x0_hw_free, 13638c2ecf20Sopenharmony_ci .prepare = snd_intel8x0_pcm_prepare, 13648c2ecf20Sopenharmony_ci .trigger = snd_intel8x0_pcm_trigger, 13658c2ecf20Sopenharmony_ci .pointer = snd_intel8x0_pcm_pointer, 13668c2ecf20Sopenharmony_ci}; 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_cistatic const struct snd_pcm_ops snd_intel8x0_spdif_ops = { 13698c2ecf20Sopenharmony_ci .open = snd_intel8x0_spdif_open, 13708c2ecf20Sopenharmony_ci .close = snd_intel8x0_spdif_close, 13718c2ecf20Sopenharmony_ci .hw_params = snd_intel8x0_hw_params, 13728c2ecf20Sopenharmony_ci .hw_free = snd_intel8x0_hw_free, 13738c2ecf20Sopenharmony_ci .prepare = snd_intel8x0_pcm_prepare, 13748c2ecf20Sopenharmony_ci .trigger = snd_intel8x0_pcm_trigger, 13758c2ecf20Sopenharmony_ci .pointer = snd_intel8x0_pcm_pointer, 13768c2ecf20Sopenharmony_ci}; 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_cistatic const struct snd_pcm_ops snd_intel8x0_ali_playback_ops = { 13798c2ecf20Sopenharmony_ci .open = snd_intel8x0_playback_open, 13808c2ecf20Sopenharmony_ci .close = snd_intel8x0_playback_close, 13818c2ecf20Sopenharmony_ci .hw_params = snd_intel8x0_hw_params, 13828c2ecf20Sopenharmony_ci .hw_free = snd_intel8x0_hw_free, 13838c2ecf20Sopenharmony_ci .prepare = snd_intel8x0_pcm_prepare, 13848c2ecf20Sopenharmony_ci .trigger = snd_intel8x0_ali_trigger, 13858c2ecf20Sopenharmony_ci .pointer = snd_intel8x0_pcm_pointer, 13868c2ecf20Sopenharmony_ci}; 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_cistatic const struct snd_pcm_ops snd_intel8x0_ali_capture_ops = { 13898c2ecf20Sopenharmony_ci .open = snd_intel8x0_capture_open, 13908c2ecf20Sopenharmony_ci .close = snd_intel8x0_capture_close, 13918c2ecf20Sopenharmony_ci .hw_params = snd_intel8x0_hw_params, 13928c2ecf20Sopenharmony_ci .hw_free = snd_intel8x0_hw_free, 13938c2ecf20Sopenharmony_ci .prepare = snd_intel8x0_pcm_prepare, 13948c2ecf20Sopenharmony_ci .trigger = snd_intel8x0_ali_trigger, 13958c2ecf20Sopenharmony_ci .pointer = snd_intel8x0_pcm_pointer, 13968c2ecf20Sopenharmony_ci}; 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_cistatic const struct snd_pcm_ops snd_intel8x0_ali_capture_mic_ops = { 13998c2ecf20Sopenharmony_ci .open = snd_intel8x0_mic_open, 14008c2ecf20Sopenharmony_ci .close = snd_intel8x0_mic_close, 14018c2ecf20Sopenharmony_ci .hw_params = snd_intel8x0_hw_params, 14028c2ecf20Sopenharmony_ci .hw_free = snd_intel8x0_hw_free, 14038c2ecf20Sopenharmony_ci .prepare = snd_intel8x0_pcm_prepare, 14048c2ecf20Sopenharmony_ci .trigger = snd_intel8x0_ali_trigger, 14058c2ecf20Sopenharmony_ci .pointer = snd_intel8x0_pcm_pointer, 14068c2ecf20Sopenharmony_ci}; 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_cistatic const struct snd_pcm_ops snd_intel8x0_ali_ac97spdifout_ops = { 14098c2ecf20Sopenharmony_ci .open = snd_intel8x0_ali_ac97spdifout_open, 14108c2ecf20Sopenharmony_ci .close = snd_intel8x0_ali_ac97spdifout_close, 14118c2ecf20Sopenharmony_ci .hw_params = snd_intel8x0_hw_params, 14128c2ecf20Sopenharmony_ci .hw_free = snd_intel8x0_hw_free, 14138c2ecf20Sopenharmony_ci .prepare = snd_intel8x0_pcm_prepare, 14148c2ecf20Sopenharmony_ci .trigger = snd_intel8x0_ali_trigger, 14158c2ecf20Sopenharmony_ci .pointer = snd_intel8x0_pcm_pointer, 14168c2ecf20Sopenharmony_ci}; 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ci#if 0 // NYI 14198c2ecf20Sopenharmony_cistatic struct snd_pcm_ops snd_intel8x0_ali_spdifin_ops = { 14208c2ecf20Sopenharmony_ci .open = snd_intel8x0_ali_spdifin_open, 14218c2ecf20Sopenharmony_ci .close = snd_intel8x0_ali_spdifin_close, 14228c2ecf20Sopenharmony_ci .hw_params = snd_intel8x0_hw_params, 14238c2ecf20Sopenharmony_ci .hw_free = snd_intel8x0_hw_free, 14248c2ecf20Sopenharmony_ci .prepare = snd_intel8x0_pcm_prepare, 14258c2ecf20Sopenharmony_ci .trigger = snd_intel8x0_pcm_trigger, 14268c2ecf20Sopenharmony_ci .pointer = snd_intel8x0_pcm_pointer, 14278c2ecf20Sopenharmony_ci}; 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_cistatic struct snd_pcm_ops snd_intel8x0_ali_spdifout_ops = { 14308c2ecf20Sopenharmony_ci .open = snd_intel8x0_ali_spdifout_open, 14318c2ecf20Sopenharmony_ci .close = snd_intel8x0_ali_spdifout_close, 14328c2ecf20Sopenharmony_ci .hw_params = snd_intel8x0_hw_params, 14338c2ecf20Sopenharmony_ci .hw_free = snd_intel8x0_hw_free, 14348c2ecf20Sopenharmony_ci .prepare = snd_intel8x0_pcm_prepare, 14358c2ecf20Sopenharmony_ci .trigger = snd_intel8x0_pcm_trigger, 14368c2ecf20Sopenharmony_ci .pointer = snd_intel8x0_pcm_pointer, 14378c2ecf20Sopenharmony_ci}; 14388c2ecf20Sopenharmony_ci#endif // NYI 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_cistruct ich_pcm_table { 14418c2ecf20Sopenharmony_ci char *suffix; 14428c2ecf20Sopenharmony_ci const struct snd_pcm_ops *playback_ops; 14438c2ecf20Sopenharmony_ci const struct snd_pcm_ops *capture_ops; 14448c2ecf20Sopenharmony_ci size_t prealloc_size; 14458c2ecf20Sopenharmony_ci size_t prealloc_max_size; 14468c2ecf20Sopenharmony_ci int ac97_idx; 14478c2ecf20Sopenharmony_ci}; 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_ci#define intel8x0_dma_type(chip) \ 14508c2ecf20Sopenharmony_ci ((chip)->fix_nocache ? SNDRV_DMA_TYPE_DEV_UC : SNDRV_DMA_TYPE_DEV) 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_cistatic int snd_intel8x0_pcm1(struct intel8x0 *chip, int device, 14538c2ecf20Sopenharmony_ci const struct ich_pcm_table *rec) 14548c2ecf20Sopenharmony_ci{ 14558c2ecf20Sopenharmony_ci struct snd_pcm *pcm; 14568c2ecf20Sopenharmony_ci int err; 14578c2ecf20Sopenharmony_ci char name[32]; 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_ci if (rec->suffix) 14608c2ecf20Sopenharmony_ci sprintf(name, "Intel ICH - %s", rec->suffix); 14618c2ecf20Sopenharmony_ci else 14628c2ecf20Sopenharmony_ci strcpy(name, "Intel ICH"); 14638c2ecf20Sopenharmony_ci err = snd_pcm_new(chip->card, name, device, 14648c2ecf20Sopenharmony_ci rec->playback_ops ? 1 : 0, 14658c2ecf20Sopenharmony_ci rec->capture_ops ? 1 : 0, &pcm); 14668c2ecf20Sopenharmony_ci if (err < 0) 14678c2ecf20Sopenharmony_ci return err; 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_ci if (rec->playback_ops) 14708c2ecf20Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, rec->playback_ops); 14718c2ecf20Sopenharmony_ci if (rec->capture_ops) 14728c2ecf20Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, rec->capture_ops); 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_ci pcm->private_data = chip; 14758c2ecf20Sopenharmony_ci pcm->info_flags = 0; 14768c2ecf20Sopenharmony_ci if (rec->suffix) 14778c2ecf20Sopenharmony_ci sprintf(pcm->name, "%s - %s", chip->card->shortname, rec->suffix); 14788c2ecf20Sopenharmony_ci else 14798c2ecf20Sopenharmony_ci strcpy(pcm->name, chip->card->shortname); 14808c2ecf20Sopenharmony_ci chip->pcm[device] = pcm; 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci snd_pcm_set_managed_buffer_all(pcm, intel8x0_dma_type(chip), 14838c2ecf20Sopenharmony_ci &chip->pci->dev, 14848c2ecf20Sopenharmony_ci rec->prealloc_size, rec->prealloc_max_size); 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci if (rec->playback_ops && 14878c2ecf20Sopenharmony_ci rec->playback_ops->open == snd_intel8x0_playback_open) { 14888c2ecf20Sopenharmony_ci struct snd_pcm_chmap *chmap; 14898c2ecf20Sopenharmony_ci int chs = 2; 14908c2ecf20Sopenharmony_ci if (chip->multi8) 14918c2ecf20Sopenharmony_ci chs = 8; 14928c2ecf20Sopenharmony_ci else if (chip->multi6) 14938c2ecf20Sopenharmony_ci chs = 6; 14948c2ecf20Sopenharmony_ci else if (chip->multi4) 14958c2ecf20Sopenharmony_ci chs = 4; 14968c2ecf20Sopenharmony_ci err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, 14978c2ecf20Sopenharmony_ci snd_pcm_alt_chmaps, chs, 0, 14988c2ecf20Sopenharmony_ci &chmap); 14998c2ecf20Sopenharmony_ci if (err < 0) 15008c2ecf20Sopenharmony_ci return err; 15018c2ecf20Sopenharmony_ci chmap->channel_mask = SND_PCM_CHMAP_MASK_2468; 15028c2ecf20Sopenharmony_ci chip->ac97[0]->chmaps[SNDRV_PCM_STREAM_PLAYBACK] = chmap; 15038c2ecf20Sopenharmony_ci } 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_ci return 0; 15068c2ecf20Sopenharmony_ci} 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_cistatic const struct ich_pcm_table intel_pcms[] = { 15098c2ecf20Sopenharmony_ci { 15108c2ecf20Sopenharmony_ci .playback_ops = &snd_intel8x0_playback_ops, 15118c2ecf20Sopenharmony_ci .capture_ops = &snd_intel8x0_capture_ops, 15128c2ecf20Sopenharmony_ci .prealloc_size = 64 * 1024, 15138c2ecf20Sopenharmony_ci .prealloc_max_size = 128 * 1024, 15148c2ecf20Sopenharmony_ci }, 15158c2ecf20Sopenharmony_ci { 15168c2ecf20Sopenharmony_ci .suffix = "MIC ADC", 15178c2ecf20Sopenharmony_ci .capture_ops = &snd_intel8x0_capture_mic_ops, 15188c2ecf20Sopenharmony_ci .prealloc_size = 0, 15198c2ecf20Sopenharmony_ci .prealloc_max_size = 128 * 1024, 15208c2ecf20Sopenharmony_ci .ac97_idx = ICHD_MIC, 15218c2ecf20Sopenharmony_ci }, 15228c2ecf20Sopenharmony_ci { 15238c2ecf20Sopenharmony_ci .suffix = "MIC2 ADC", 15248c2ecf20Sopenharmony_ci .capture_ops = &snd_intel8x0_capture_mic2_ops, 15258c2ecf20Sopenharmony_ci .prealloc_size = 0, 15268c2ecf20Sopenharmony_ci .prealloc_max_size = 128 * 1024, 15278c2ecf20Sopenharmony_ci .ac97_idx = ICHD_MIC2, 15288c2ecf20Sopenharmony_ci }, 15298c2ecf20Sopenharmony_ci { 15308c2ecf20Sopenharmony_ci .suffix = "ADC2", 15318c2ecf20Sopenharmony_ci .capture_ops = &snd_intel8x0_capture2_ops, 15328c2ecf20Sopenharmony_ci .prealloc_size = 0, 15338c2ecf20Sopenharmony_ci .prealloc_max_size = 128 * 1024, 15348c2ecf20Sopenharmony_ci .ac97_idx = ICHD_PCM2IN, 15358c2ecf20Sopenharmony_ci }, 15368c2ecf20Sopenharmony_ci { 15378c2ecf20Sopenharmony_ci .suffix = "IEC958", 15388c2ecf20Sopenharmony_ci .playback_ops = &snd_intel8x0_spdif_ops, 15398c2ecf20Sopenharmony_ci .prealloc_size = 64 * 1024, 15408c2ecf20Sopenharmony_ci .prealloc_max_size = 128 * 1024, 15418c2ecf20Sopenharmony_ci .ac97_idx = ICHD_SPBAR, 15428c2ecf20Sopenharmony_ci }, 15438c2ecf20Sopenharmony_ci}; 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_cistatic const struct ich_pcm_table nforce_pcms[] = { 15468c2ecf20Sopenharmony_ci { 15478c2ecf20Sopenharmony_ci .playback_ops = &snd_intel8x0_playback_ops, 15488c2ecf20Sopenharmony_ci .capture_ops = &snd_intel8x0_capture_ops, 15498c2ecf20Sopenharmony_ci .prealloc_size = 64 * 1024, 15508c2ecf20Sopenharmony_ci .prealloc_max_size = 128 * 1024, 15518c2ecf20Sopenharmony_ci }, 15528c2ecf20Sopenharmony_ci { 15538c2ecf20Sopenharmony_ci .suffix = "MIC ADC", 15548c2ecf20Sopenharmony_ci .capture_ops = &snd_intel8x0_capture_mic_ops, 15558c2ecf20Sopenharmony_ci .prealloc_size = 0, 15568c2ecf20Sopenharmony_ci .prealloc_max_size = 128 * 1024, 15578c2ecf20Sopenharmony_ci .ac97_idx = NVD_MIC, 15588c2ecf20Sopenharmony_ci }, 15598c2ecf20Sopenharmony_ci { 15608c2ecf20Sopenharmony_ci .suffix = "IEC958", 15618c2ecf20Sopenharmony_ci .playback_ops = &snd_intel8x0_spdif_ops, 15628c2ecf20Sopenharmony_ci .prealloc_size = 64 * 1024, 15638c2ecf20Sopenharmony_ci .prealloc_max_size = 128 * 1024, 15648c2ecf20Sopenharmony_ci .ac97_idx = NVD_SPBAR, 15658c2ecf20Sopenharmony_ci }, 15668c2ecf20Sopenharmony_ci}; 15678c2ecf20Sopenharmony_ci 15688c2ecf20Sopenharmony_cistatic const struct ich_pcm_table ali_pcms[] = { 15698c2ecf20Sopenharmony_ci { 15708c2ecf20Sopenharmony_ci .playback_ops = &snd_intel8x0_ali_playback_ops, 15718c2ecf20Sopenharmony_ci .capture_ops = &snd_intel8x0_ali_capture_ops, 15728c2ecf20Sopenharmony_ci .prealloc_size = 64 * 1024, 15738c2ecf20Sopenharmony_ci .prealloc_max_size = 128 * 1024, 15748c2ecf20Sopenharmony_ci }, 15758c2ecf20Sopenharmony_ci { 15768c2ecf20Sopenharmony_ci .suffix = "MIC ADC", 15778c2ecf20Sopenharmony_ci .capture_ops = &snd_intel8x0_ali_capture_mic_ops, 15788c2ecf20Sopenharmony_ci .prealloc_size = 0, 15798c2ecf20Sopenharmony_ci .prealloc_max_size = 128 * 1024, 15808c2ecf20Sopenharmony_ci .ac97_idx = ALID_MIC, 15818c2ecf20Sopenharmony_ci }, 15828c2ecf20Sopenharmony_ci { 15838c2ecf20Sopenharmony_ci .suffix = "IEC958", 15848c2ecf20Sopenharmony_ci .playback_ops = &snd_intel8x0_ali_ac97spdifout_ops, 15858c2ecf20Sopenharmony_ci /* .capture_ops = &snd_intel8x0_ali_spdifin_ops, */ 15868c2ecf20Sopenharmony_ci .prealloc_size = 64 * 1024, 15878c2ecf20Sopenharmony_ci .prealloc_max_size = 128 * 1024, 15888c2ecf20Sopenharmony_ci .ac97_idx = ALID_AC97SPDIFOUT, 15898c2ecf20Sopenharmony_ci }, 15908c2ecf20Sopenharmony_ci#if 0 // NYI 15918c2ecf20Sopenharmony_ci { 15928c2ecf20Sopenharmony_ci .suffix = "HW IEC958", 15938c2ecf20Sopenharmony_ci .playback_ops = &snd_intel8x0_ali_spdifout_ops, 15948c2ecf20Sopenharmony_ci .prealloc_size = 64 * 1024, 15958c2ecf20Sopenharmony_ci .prealloc_max_size = 128 * 1024, 15968c2ecf20Sopenharmony_ci }, 15978c2ecf20Sopenharmony_ci#endif 15988c2ecf20Sopenharmony_ci}; 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_cistatic int snd_intel8x0_pcm(struct intel8x0 *chip) 16018c2ecf20Sopenharmony_ci{ 16028c2ecf20Sopenharmony_ci int i, tblsize, device, err; 16038c2ecf20Sopenharmony_ci const struct ich_pcm_table *tbl, *rec; 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci switch (chip->device_type) { 16068c2ecf20Sopenharmony_ci case DEVICE_INTEL_ICH4: 16078c2ecf20Sopenharmony_ci tbl = intel_pcms; 16088c2ecf20Sopenharmony_ci tblsize = ARRAY_SIZE(intel_pcms); 16098c2ecf20Sopenharmony_ci if (spdif_aclink) 16108c2ecf20Sopenharmony_ci tblsize--; 16118c2ecf20Sopenharmony_ci break; 16128c2ecf20Sopenharmony_ci case DEVICE_NFORCE: 16138c2ecf20Sopenharmony_ci tbl = nforce_pcms; 16148c2ecf20Sopenharmony_ci tblsize = ARRAY_SIZE(nforce_pcms); 16158c2ecf20Sopenharmony_ci if (spdif_aclink) 16168c2ecf20Sopenharmony_ci tblsize--; 16178c2ecf20Sopenharmony_ci break; 16188c2ecf20Sopenharmony_ci case DEVICE_ALI: 16198c2ecf20Sopenharmony_ci tbl = ali_pcms; 16208c2ecf20Sopenharmony_ci tblsize = ARRAY_SIZE(ali_pcms); 16218c2ecf20Sopenharmony_ci break; 16228c2ecf20Sopenharmony_ci default: 16238c2ecf20Sopenharmony_ci tbl = intel_pcms; 16248c2ecf20Sopenharmony_ci tblsize = 2; 16258c2ecf20Sopenharmony_ci break; 16268c2ecf20Sopenharmony_ci } 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci device = 0; 16298c2ecf20Sopenharmony_ci for (i = 0; i < tblsize; i++) { 16308c2ecf20Sopenharmony_ci rec = tbl + i; 16318c2ecf20Sopenharmony_ci if (i > 0 && rec->ac97_idx) { 16328c2ecf20Sopenharmony_ci /* activate PCM only when associated AC'97 codec */ 16338c2ecf20Sopenharmony_ci if (! chip->ichd[rec->ac97_idx].pcm) 16348c2ecf20Sopenharmony_ci continue; 16358c2ecf20Sopenharmony_ci } 16368c2ecf20Sopenharmony_ci err = snd_intel8x0_pcm1(chip, device, rec); 16378c2ecf20Sopenharmony_ci if (err < 0) 16388c2ecf20Sopenharmony_ci return err; 16398c2ecf20Sopenharmony_ci device++; 16408c2ecf20Sopenharmony_ci } 16418c2ecf20Sopenharmony_ci 16428c2ecf20Sopenharmony_ci chip->pcm_devs = device; 16438c2ecf20Sopenharmony_ci return 0; 16448c2ecf20Sopenharmony_ci} 16458c2ecf20Sopenharmony_ci 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci/* 16488c2ecf20Sopenharmony_ci * Mixer part 16498c2ecf20Sopenharmony_ci */ 16508c2ecf20Sopenharmony_ci 16518c2ecf20Sopenharmony_cistatic void snd_intel8x0_mixer_free_ac97_bus(struct snd_ac97_bus *bus) 16528c2ecf20Sopenharmony_ci{ 16538c2ecf20Sopenharmony_ci struct intel8x0 *chip = bus->private_data; 16548c2ecf20Sopenharmony_ci chip->ac97_bus = NULL; 16558c2ecf20Sopenharmony_ci} 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_cistatic void snd_intel8x0_mixer_free_ac97(struct snd_ac97 *ac97) 16588c2ecf20Sopenharmony_ci{ 16598c2ecf20Sopenharmony_ci struct intel8x0 *chip = ac97->private_data; 16608c2ecf20Sopenharmony_ci chip->ac97[ac97->num] = NULL; 16618c2ecf20Sopenharmony_ci} 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_cistatic const struct ac97_pcm ac97_pcm_defs[] = { 16648c2ecf20Sopenharmony_ci /* front PCM */ 16658c2ecf20Sopenharmony_ci { 16668c2ecf20Sopenharmony_ci .exclusive = 1, 16678c2ecf20Sopenharmony_ci .r = { { 16688c2ecf20Sopenharmony_ci .slots = (1 << AC97_SLOT_PCM_LEFT) | 16698c2ecf20Sopenharmony_ci (1 << AC97_SLOT_PCM_RIGHT) | 16708c2ecf20Sopenharmony_ci (1 << AC97_SLOT_PCM_CENTER) | 16718c2ecf20Sopenharmony_ci (1 << AC97_SLOT_PCM_SLEFT) | 16728c2ecf20Sopenharmony_ci (1 << AC97_SLOT_PCM_SRIGHT) | 16738c2ecf20Sopenharmony_ci (1 << AC97_SLOT_LFE) 16748c2ecf20Sopenharmony_ci }, 16758c2ecf20Sopenharmony_ci { 16768c2ecf20Sopenharmony_ci .slots = (1 << AC97_SLOT_PCM_LEFT) | 16778c2ecf20Sopenharmony_ci (1 << AC97_SLOT_PCM_RIGHT) | 16788c2ecf20Sopenharmony_ci (1 << AC97_SLOT_PCM_LEFT_0) | 16798c2ecf20Sopenharmony_ci (1 << AC97_SLOT_PCM_RIGHT_0) 16808c2ecf20Sopenharmony_ci } 16818c2ecf20Sopenharmony_ci } 16828c2ecf20Sopenharmony_ci }, 16838c2ecf20Sopenharmony_ci /* PCM IN #1 */ 16848c2ecf20Sopenharmony_ci { 16858c2ecf20Sopenharmony_ci .stream = 1, 16868c2ecf20Sopenharmony_ci .exclusive = 1, 16878c2ecf20Sopenharmony_ci .r = { { 16888c2ecf20Sopenharmony_ci .slots = (1 << AC97_SLOT_PCM_LEFT) | 16898c2ecf20Sopenharmony_ci (1 << AC97_SLOT_PCM_RIGHT) 16908c2ecf20Sopenharmony_ci } 16918c2ecf20Sopenharmony_ci } 16928c2ecf20Sopenharmony_ci }, 16938c2ecf20Sopenharmony_ci /* MIC IN #1 */ 16948c2ecf20Sopenharmony_ci { 16958c2ecf20Sopenharmony_ci .stream = 1, 16968c2ecf20Sopenharmony_ci .exclusive = 1, 16978c2ecf20Sopenharmony_ci .r = { { 16988c2ecf20Sopenharmony_ci .slots = (1 << AC97_SLOT_MIC) 16998c2ecf20Sopenharmony_ci } 17008c2ecf20Sopenharmony_ci } 17018c2ecf20Sopenharmony_ci }, 17028c2ecf20Sopenharmony_ci /* S/PDIF PCM */ 17038c2ecf20Sopenharmony_ci { 17048c2ecf20Sopenharmony_ci .exclusive = 1, 17058c2ecf20Sopenharmony_ci .spdif = 1, 17068c2ecf20Sopenharmony_ci .r = { { 17078c2ecf20Sopenharmony_ci .slots = (1 << AC97_SLOT_SPDIF_LEFT2) | 17088c2ecf20Sopenharmony_ci (1 << AC97_SLOT_SPDIF_RIGHT2) 17098c2ecf20Sopenharmony_ci } 17108c2ecf20Sopenharmony_ci } 17118c2ecf20Sopenharmony_ci }, 17128c2ecf20Sopenharmony_ci /* PCM IN #2 */ 17138c2ecf20Sopenharmony_ci { 17148c2ecf20Sopenharmony_ci .stream = 1, 17158c2ecf20Sopenharmony_ci .exclusive = 1, 17168c2ecf20Sopenharmony_ci .r = { { 17178c2ecf20Sopenharmony_ci .slots = (1 << AC97_SLOT_PCM_LEFT) | 17188c2ecf20Sopenharmony_ci (1 << AC97_SLOT_PCM_RIGHT) 17198c2ecf20Sopenharmony_ci } 17208c2ecf20Sopenharmony_ci } 17218c2ecf20Sopenharmony_ci }, 17228c2ecf20Sopenharmony_ci /* MIC IN #2 */ 17238c2ecf20Sopenharmony_ci { 17248c2ecf20Sopenharmony_ci .stream = 1, 17258c2ecf20Sopenharmony_ci .exclusive = 1, 17268c2ecf20Sopenharmony_ci .r = { { 17278c2ecf20Sopenharmony_ci .slots = (1 << AC97_SLOT_MIC) 17288c2ecf20Sopenharmony_ci } 17298c2ecf20Sopenharmony_ci } 17308c2ecf20Sopenharmony_ci }, 17318c2ecf20Sopenharmony_ci}; 17328c2ecf20Sopenharmony_ci 17338c2ecf20Sopenharmony_cistatic const struct ac97_quirk ac97_quirks[] = { 17348c2ecf20Sopenharmony_ci { 17358c2ecf20Sopenharmony_ci .subvendor = 0x0e11, 17368c2ecf20Sopenharmony_ci .subdevice = 0x000e, 17378c2ecf20Sopenharmony_ci .name = "Compaq Deskpro EN", /* AD1885 */ 17388c2ecf20Sopenharmony_ci .type = AC97_TUNE_HP_ONLY 17398c2ecf20Sopenharmony_ci }, 17408c2ecf20Sopenharmony_ci { 17418c2ecf20Sopenharmony_ci .subvendor = 0x0e11, 17428c2ecf20Sopenharmony_ci .subdevice = 0x008a, 17438c2ecf20Sopenharmony_ci .name = "Compaq Evo W4000", /* AD1885 */ 17448c2ecf20Sopenharmony_ci .type = AC97_TUNE_HP_ONLY 17458c2ecf20Sopenharmony_ci }, 17468c2ecf20Sopenharmony_ci { 17478c2ecf20Sopenharmony_ci .subvendor = 0x0e11, 17488c2ecf20Sopenharmony_ci .subdevice = 0x00b8, 17498c2ecf20Sopenharmony_ci .name = "Compaq Evo D510C", 17508c2ecf20Sopenharmony_ci .type = AC97_TUNE_HP_ONLY 17518c2ecf20Sopenharmony_ci }, 17528c2ecf20Sopenharmony_ci { 17538c2ecf20Sopenharmony_ci .subvendor = 0x0e11, 17548c2ecf20Sopenharmony_ci .subdevice = 0x0860, 17558c2ecf20Sopenharmony_ci .name = "HP/Compaq nx7010", 17568c2ecf20Sopenharmony_ci .type = AC97_TUNE_MUTE_LED 17578c2ecf20Sopenharmony_ci }, 17588c2ecf20Sopenharmony_ci { 17598c2ecf20Sopenharmony_ci .subvendor = 0x1014, 17608c2ecf20Sopenharmony_ci .subdevice = 0x0534, 17618c2ecf20Sopenharmony_ci .name = "ThinkPad X31", 17628c2ecf20Sopenharmony_ci .type = AC97_TUNE_INV_EAPD 17638c2ecf20Sopenharmony_ci }, 17648c2ecf20Sopenharmony_ci { 17658c2ecf20Sopenharmony_ci .subvendor = 0x1014, 17668c2ecf20Sopenharmony_ci .subdevice = 0x1f00, 17678c2ecf20Sopenharmony_ci .name = "MS-9128", 17688c2ecf20Sopenharmony_ci .type = AC97_TUNE_ALC_JACK 17698c2ecf20Sopenharmony_ci }, 17708c2ecf20Sopenharmony_ci { 17718c2ecf20Sopenharmony_ci .subvendor = 0x1014, 17728c2ecf20Sopenharmony_ci .subdevice = 0x0267, 17738c2ecf20Sopenharmony_ci .name = "IBM NetVista A30p", /* AD1981B */ 17748c2ecf20Sopenharmony_ci .type = AC97_TUNE_HP_ONLY 17758c2ecf20Sopenharmony_ci }, 17768c2ecf20Sopenharmony_ci { 17778c2ecf20Sopenharmony_ci .subvendor = 0x1025, 17788c2ecf20Sopenharmony_ci .subdevice = 0x0082, 17798c2ecf20Sopenharmony_ci .name = "Acer Travelmate 2310", 17808c2ecf20Sopenharmony_ci .type = AC97_TUNE_HP_ONLY 17818c2ecf20Sopenharmony_ci }, 17828c2ecf20Sopenharmony_ci { 17838c2ecf20Sopenharmony_ci .subvendor = 0x1025, 17848c2ecf20Sopenharmony_ci .subdevice = 0x0083, 17858c2ecf20Sopenharmony_ci .name = "Acer Aspire 3003LCi", 17868c2ecf20Sopenharmony_ci .type = AC97_TUNE_HP_ONLY 17878c2ecf20Sopenharmony_ci }, 17888c2ecf20Sopenharmony_ci { 17898c2ecf20Sopenharmony_ci .subvendor = 0x1028, 17908c2ecf20Sopenharmony_ci .subdevice = 0x00d8, 17918c2ecf20Sopenharmony_ci .name = "Dell Precision 530", /* AD1885 */ 17928c2ecf20Sopenharmony_ci .type = AC97_TUNE_HP_ONLY 17938c2ecf20Sopenharmony_ci }, 17948c2ecf20Sopenharmony_ci { 17958c2ecf20Sopenharmony_ci .subvendor = 0x1028, 17968c2ecf20Sopenharmony_ci .subdevice = 0x010d, 17978c2ecf20Sopenharmony_ci .name = "Dell", /* which model? AD1885 */ 17988c2ecf20Sopenharmony_ci .type = AC97_TUNE_HP_ONLY 17998c2ecf20Sopenharmony_ci }, 18008c2ecf20Sopenharmony_ci { 18018c2ecf20Sopenharmony_ci .subvendor = 0x1028, 18028c2ecf20Sopenharmony_ci .subdevice = 0x0126, 18038c2ecf20Sopenharmony_ci .name = "Dell Optiplex GX260", /* AD1981A */ 18048c2ecf20Sopenharmony_ci .type = AC97_TUNE_HP_ONLY 18058c2ecf20Sopenharmony_ci }, 18068c2ecf20Sopenharmony_ci { 18078c2ecf20Sopenharmony_ci .subvendor = 0x1028, 18088c2ecf20Sopenharmony_ci .subdevice = 0x012c, 18098c2ecf20Sopenharmony_ci .name = "Dell Precision 650", /* AD1981A */ 18108c2ecf20Sopenharmony_ci .type = AC97_TUNE_HP_ONLY 18118c2ecf20Sopenharmony_ci }, 18128c2ecf20Sopenharmony_ci { 18138c2ecf20Sopenharmony_ci .subvendor = 0x1028, 18148c2ecf20Sopenharmony_ci .subdevice = 0x012d, 18158c2ecf20Sopenharmony_ci .name = "Dell Precision 450", /* AD1981B*/ 18168c2ecf20Sopenharmony_ci .type = AC97_TUNE_HP_ONLY 18178c2ecf20Sopenharmony_ci }, 18188c2ecf20Sopenharmony_ci { 18198c2ecf20Sopenharmony_ci .subvendor = 0x1028, 18208c2ecf20Sopenharmony_ci .subdevice = 0x0147, 18218c2ecf20Sopenharmony_ci .name = "Dell", /* which model? AD1981B*/ 18228c2ecf20Sopenharmony_ci .type = AC97_TUNE_HP_ONLY 18238c2ecf20Sopenharmony_ci }, 18248c2ecf20Sopenharmony_ci { 18258c2ecf20Sopenharmony_ci .subvendor = 0x1028, 18268c2ecf20Sopenharmony_ci .subdevice = 0x0151, 18278c2ecf20Sopenharmony_ci .name = "Dell Optiplex GX270", /* AD1981B */ 18288c2ecf20Sopenharmony_ci .type = AC97_TUNE_HP_ONLY 18298c2ecf20Sopenharmony_ci }, 18308c2ecf20Sopenharmony_ci { 18318c2ecf20Sopenharmony_ci .subvendor = 0x1028, 18328c2ecf20Sopenharmony_ci .subdevice = 0x014e, 18338c2ecf20Sopenharmony_ci .name = "Dell D800", /* STAC9750/51 */ 18348c2ecf20Sopenharmony_ci .type = AC97_TUNE_HP_ONLY 18358c2ecf20Sopenharmony_ci }, 18368c2ecf20Sopenharmony_ci { 18378c2ecf20Sopenharmony_ci .subvendor = 0x1028, 18388c2ecf20Sopenharmony_ci .subdevice = 0x0163, 18398c2ecf20Sopenharmony_ci .name = "Dell Unknown", /* STAC9750/51 */ 18408c2ecf20Sopenharmony_ci .type = AC97_TUNE_HP_ONLY 18418c2ecf20Sopenharmony_ci }, 18428c2ecf20Sopenharmony_ci { 18438c2ecf20Sopenharmony_ci .subvendor = 0x1028, 18448c2ecf20Sopenharmony_ci .subdevice = 0x016a, 18458c2ecf20Sopenharmony_ci .name = "Dell Inspiron 8600", /* STAC9750/51 */ 18468c2ecf20Sopenharmony_ci .type = AC97_TUNE_HP_ONLY 18478c2ecf20Sopenharmony_ci }, 18488c2ecf20Sopenharmony_ci { 18498c2ecf20Sopenharmony_ci .subvendor = 0x1028, 18508c2ecf20Sopenharmony_ci .subdevice = 0x0182, 18518c2ecf20Sopenharmony_ci .name = "Dell Latitude D610", /* STAC9750/51 */ 18528c2ecf20Sopenharmony_ci .type = AC97_TUNE_HP_ONLY 18538c2ecf20Sopenharmony_ci }, 18548c2ecf20Sopenharmony_ci { 18558c2ecf20Sopenharmony_ci .subvendor = 0x1028, 18568c2ecf20Sopenharmony_ci .subdevice = 0x0186, 18578c2ecf20Sopenharmony_ci .name = "Dell Latitude D810", /* cf. Malone #41015 */ 18588c2ecf20Sopenharmony_ci .type = AC97_TUNE_HP_MUTE_LED 18598c2ecf20Sopenharmony_ci }, 18608c2ecf20Sopenharmony_ci { 18618c2ecf20Sopenharmony_ci .subvendor = 0x1028, 18628c2ecf20Sopenharmony_ci .subdevice = 0x0188, 18638c2ecf20Sopenharmony_ci .name = "Dell Inspiron 6000", 18648c2ecf20Sopenharmony_ci .type = AC97_TUNE_HP_MUTE_LED /* cf. Malone #41015 */ 18658c2ecf20Sopenharmony_ci }, 18668c2ecf20Sopenharmony_ci { 18678c2ecf20Sopenharmony_ci .subvendor = 0x1028, 18688c2ecf20Sopenharmony_ci .subdevice = 0x0189, 18698c2ecf20Sopenharmony_ci .name = "Dell Inspiron 9300", 18708c2ecf20Sopenharmony_ci .type = AC97_TUNE_HP_MUTE_LED 18718c2ecf20Sopenharmony_ci }, 18728c2ecf20Sopenharmony_ci { 18738c2ecf20Sopenharmony_ci .subvendor = 0x1028, 18748c2ecf20Sopenharmony_ci .subdevice = 0x0191, 18758c2ecf20Sopenharmony_ci .name = "Dell Inspiron 8600", 18768c2ecf20Sopenharmony_ci .type = AC97_TUNE_HP_ONLY 18778c2ecf20Sopenharmony_ci }, 18788c2ecf20Sopenharmony_ci { 18798c2ecf20Sopenharmony_ci .subvendor = 0x103c, 18808c2ecf20Sopenharmony_ci .subdevice = 0x006d, 18818c2ecf20Sopenharmony_ci .name = "HP zv5000", 18828c2ecf20Sopenharmony_ci .type = AC97_TUNE_MUTE_LED /*AD1981B*/ 18838c2ecf20Sopenharmony_ci }, 18848c2ecf20Sopenharmony_ci { /* FIXME: which codec? */ 18858c2ecf20Sopenharmony_ci .subvendor = 0x103c, 18868c2ecf20Sopenharmony_ci .subdevice = 0x00c3, 18878c2ecf20Sopenharmony_ci .name = "HP xw6000", 18888c2ecf20Sopenharmony_ci .type = AC97_TUNE_HP_ONLY 18898c2ecf20Sopenharmony_ci }, 18908c2ecf20Sopenharmony_ci { 18918c2ecf20Sopenharmony_ci .subvendor = 0x103c, 18928c2ecf20Sopenharmony_ci .subdevice = 0x088c, 18938c2ecf20Sopenharmony_ci .name = "HP nc8000", 18948c2ecf20Sopenharmony_ci .type = AC97_TUNE_HP_MUTE_LED 18958c2ecf20Sopenharmony_ci }, 18968c2ecf20Sopenharmony_ci { 18978c2ecf20Sopenharmony_ci .subvendor = 0x103c, 18988c2ecf20Sopenharmony_ci .subdevice = 0x0890, 18998c2ecf20Sopenharmony_ci .name = "HP nc6000", 19008c2ecf20Sopenharmony_ci .type = AC97_TUNE_MUTE_LED 19018c2ecf20Sopenharmony_ci }, 19028c2ecf20Sopenharmony_ci { 19038c2ecf20Sopenharmony_ci .subvendor = 0x103c, 19048c2ecf20Sopenharmony_ci .subdevice = 0x129d, 19058c2ecf20Sopenharmony_ci .name = "HP xw8000", 19068c2ecf20Sopenharmony_ci .type = AC97_TUNE_HP_ONLY 19078c2ecf20Sopenharmony_ci }, 19088c2ecf20Sopenharmony_ci { 19098c2ecf20Sopenharmony_ci .subvendor = 0x103c, 19108c2ecf20Sopenharmony_ci .subdevice = 0x0938, 19118c2ecf20Sopenharmony_ci .name = "HP nc4200", 19128c2ecf20Sopenharmony_ci .type = AC97_TUNE_HP_MUTE_LED 19138c2ecf20Sopenharmony_ci }, 19148c2ecf20Sopenharmony_ci { 19158c2ecf20Sopenharmony_ci .subvendor = 0x103c, 19168c2ecf20Sopenharmony_ci .subdevice = 0x099c, 19178c2ecf20Sopenharmony_ci .name = "HP nx6110/nc6120", 19188c2ecf20Sopenharmony_ci .type = AC97_TUNE_HP_MUTE_LED 19198c2ecf20Sopenharmony_ci }, 19208c2ecf20Sopenharmony_ci { 19218c2ecf20Sopenharmony_ci .subvendor = 0x103c, 19228c2ecf20Sopenharmony_ci .subdevice = 0x0944, 19238c2ecf20Sopenharmony_ci .name = "HP nc6220", 19248c2ecf20Sopenharmony_ci .type = AC97_TUNE_HP_MUTE_LED 19258c2ecf20Sopenharmony_ci }, 19268c2ecf20Sopenharmony_ci { 19278c2ecf20Sopenharmony_ci .subvendor = 0x103c, 19288c2ecf20Sopenharmony_ci .subdevice = 0x0934, 19298c2ecf20Sopenharmony_ci .name = "HP nc8220", 19308c2ecf20Sopenharmony_ci .type = AC97_TUNE_HP_MUTE_LED 19318c2ecf20Sopenharmony_ci }, 19328c2ecf20Sopenharmony_ci { 19338c2ecf20Sopenharmony_ci .subvendor = 0x103c, 19348c2ecf20Sopenharmony_ci .subdevice = 0x12f1, 19358c2ecf20Sopenharmony_ci .name = "HP xw8200", /* AD1981B*/ 19368c2ecf20Sopenharmony_ci .type = AC97_TUNE_HP_ONLY 19378c2ecf20Sopenharmony_ci }, 19388c2ecf20Sopenharmony_ci { 19398c2ecf20Sopenharmony_ci .subvendor = 0x103c, 19408c2ecf20Sopenharmony_ci .subdevice = 0x12f2, 19418c2ecf20Sopenharmony_ci .name = "HP xw6200", 19428c2ecf20Sopenharmony_ci .type = AC97_TUNE_HP_ONLY 19438c2ecf20Sopenharmony_ci }, 19448c2ecf20Sopenharmony_ci { 19458c2ecf20Sopenharmony_ci .subvendor = 0x103c, 19468c2ecf20Sopenharmony_ci .subdevice = 0x3008, 19478c2ecf20Sopenharmony_ci .name = "HP xw4200", /* AD1981B*/ 19488c2ecf20Sopenharmony_ci .type = AC97_TUNE_HP_ONLY 19498c2ecf20Sopenharmony_ci }, 19508c2ecf20Sopenharmony_ci { 19518c2ecf20Sopenharmony_ci .subvendor = 0x104d, 19528c2ecf20Sopenharmony_ci .subdevice = 0x8144, 19538c2ecf20Sopenharmony_ci .name = "Sony", 19548c2ecf20Sopenharmony_ci .type = AC97_TUNE_INV_EAPD 19558c2ecf20Sopenharmony_ci }, 19568c2ecf20Sopenharmony_ci { 19578c2ecf20Sopenharmony_ci .subvendor = 0x104d, 19588c2ecf20Sopenharmony_ci .subdevice = 0x8197, 19598c2ecf20Sopenharmony_ci .name = "Sony S1XP", 19608c2ecf20Sopenharmony_ci .type = AC97_TUNE_INV_EAPD 19618c2ecf20Sopenharmony_ci }, 19628c2ecf20Sopenharmony_ci { 19638c2ecf20Sopenharmony_ci .subvendor = 0x104d, 19648c2ecf20Sopenharmony_ci .subdevice = 0x81c0, 19658c2ecf20Sopenharmony_ci .name = "Sony VAIO VGN-T350P", /*AD1981B*/ 19668c2ecf20Sopenharmony_ci .type = AC97_TUNE_INV_EAPD 19678c2ecf20Sopenharmony_ci }, 19688c2ecf20Sopenharmony_ci { 19698c2ecf20Sopenharmony_ci .subvendor = 0x104d, 19708c2ecf20Sopenharmony_ci .subdevice = 0x81c5, 19718c2ecf20Sopenharmony_ci .name = "Sony VAIO VGN-B1VP", /*AD1981B*/ 19728c2ecf20Sopenharmony_ci .type = AC97_TUNE_INV_EAPD 19738c2ecf20Sopenharmony_ci }, 19748c2ecf20Sopenharmony_ci { 19758c2ecf20Sopenharmony_ci .subvendor = 0x1043, 19768c2ecf20Sopenharmony_ci .subdevice = 0x80f3, 19778c2ecf20Sopenharmony_ci .name = "ASUS ICH5/AD1985", 19788c2ecf20Sopenharmony_ci .type = AC97_TUNE_AD_SHARING 19798c2ecf20Sopenharmony_ci }, 19808c2ecf20Sopenharmony_ci { 19818c2ecf20Sopenharmony_ci .subvendor = 0x10cf, 19828c2ecf20Sopenharmony_ci .subdevice = 0x11c3, 19838c2ecf20Sopenharmony_ci .name = "Fujitsu-Siemens E4010", 19848c2ecf20Sopenharmony_ci .type = AC97_TUNE_HP_ONLY 19858c2ecf20Sopenharmony_ci }, 19868c2ecf20Sopenharmony_ci { 19878c2ecf20Sopenharmony_ci .subvendor = 0x10cf, 19888c2ecf20Sopenharmony_ci .subdevice = 0x1225, 19898c2ecf20Sopenharmony_ci .name = "Fujitsu-Siemens T3010", 19908c2ecf20Sopenharmony_ci .type = AC97_TUNE_HP_ONLY 19918c2ecf20Sopenharmony_ci }, 19928c2ecf20Sopenharmony_ci { 19938c2ecf20Sopenharmony_ci .subvendor = 0x10cf, 19948c2ecf20Sopenharmony_ci .subdevice = 0x1253, 19958c2ecf20Sopenharmony_ci .name = "Fujitsu S6210", /* STAC9750/51 */ 19968c2ecf20Sopenharmony_ci .type = AC97_TUNE_HP_ONLY 19978c2ecf20Sopenharmony_ci }, 19988c2ecf20Sopenharmony_ci { 19998c2ecf20Sopenharmony_ci .subvendor = 0x10cf, 20008c2ecf20Sopenharmony_ci .subdevice = 0x127d, 20018c2ecf20Sopenharmony_ci .name = "Fujitsu Lifebook P7010", 20028c2ecf20Sopenharmony_ci .type = AC97_TUNE_HP_ONLY 20038c2ecf20Sopenharmony_ci }, 20048c2ecf20Sopenharmony_ci { 20058c2ecf20Sopenharmony_ci .subvendor = 0x10cf, 20068c2ecf20Sopenharmony_ci .subdevice = 0x127e, 20078c2ecf20Sopenharmony_ci .name = "Fujitsu Lifebook C1211D", 20088c2ecf20Sopenharmony_ci .type = AC97_TUNE_HP_ONLY 20098c2ecf20Sopenharmony_ci }, 20108c2ecf20Sopenharmony_ci { 20118c2ecf20Sopenharmony_ci .subvendor = 0x10cf, 20128c2ecf20Sopenharmony_ci .subdevice = 0x12ec, 20138c2ecf20Sopenharmony_ci .name = "Fujitsu-Siemens 4010", 20148c2ecf20Sopenharmony_ci .type = AC97_TUNE_HP_ONLY 20158c2ecf20Sopenharmony_ci }, 20168c2ecf20Sopenharmony_ci { 20178c2ecf20Sopenharmony_ci .subvendor = 0x10cf, 20188c2ecf20Sopenharmony_ci .subdevice = 0x12f2, 20198c2ecf20Sopenharmony_ci .name = "Fujitsu-Siemens Celsius H320", 20208c2ecf20Sopenharmony_ci .type = AC97_TUNE_SWAP_HP 20218c2ecf20Sopenharmony_ci }, 20228c2ecf20Sopenharmony_ci { 20238c2ecf20Sopenharmony_ci .subvendor = 0x10f1, 20248c2ecf20Sopenharmony_ci .subdevice = 0x2665, 20258c2ecf20Sopenharmony_ci .name = "Fujitsu-Siemens Celsius", /* AD1981? */ 20268c2ecf20Sopenharmony_ci .type = AC97_TUNE_HP_ONLY 20278c2ecf20Sopenharmony_ci }, 20288c2ecf20Sopenharmony_ci { 20298c2ecf20Sopenharmony_ci .subvendor = 0x10f1, 20308c2ecf20Sopenharmony_ci .subdevice = 0x2885, 20318c2ecf20Sopenharmony_ci .name = "AMD64 Mobo", /* ALC650 */ 20328c2ecf20Sopenharmony_ci .type = AC97_TUNE_HP_ONLY 20338c2ecf20Sopenharmony_ci }, 20348c2ecf20Sopenharmony_ci { 20358c2ecf20Sopenharmony_ci .subvendor = 0x10f1, 20368c2ecf20Sopenharmony_ci .subdevice = 0x2895, 20378c2ecf20Sopenharmony_ci .name = "Tyan Thunder K8WE", 20388c2ecf20Sopenharmony_ci .type = AC97_TUNE_HP_ONLY 20398c2ecf20Sopenharmony_ci }, 20408c2ecf20Sopenharmony_ci { 20418c2ecf20Sopenharmony_ci .subvendor = 0x10f7, 20428c2ecf20Sopenharmony_ci .subdevice = 0x834c, 20438c2ecf20Sopenharmony_ci .name = "Panasonic CF-R4", 20448c2ecf20Sopenharmony_ci .type = AC97_TUNE_HP_ONLY, 20458c2ecf20Sopenharmony_ci }, 20468c2ecf20Sopenharmony_ci { 20478c2ecf20Sopenharmony_ci .subvendor = 0x110a, 20488c2ecf20Sopenharmony_ci .subdevice = 0x0056, 20498c2ecf20Sopenharmony_ci .name = "Fujitsu-Siemens Scenic", /* AD1981? */ 20508c2ecf20Sopenharmony_ci .type = AC97_TUNE_HP_ONLY 20518c2ecf20Sopenharmony_ci }, 20528c2ecf20Sopenharmony_ci { 20538c2ecf20Sopenharmony_ci .subvendor = 0x11d4, 20548c2ecf20Sopenharmony_ci .subdevice = 0x5375, 20558c2ecf20Sopenharmony_ci .name = "ADI AD1985 (discrete)", 20568c2ecf20Sopenharmony_ci .type = AC97_TUNE_HP_ONLY 20578c2ecf20Sopenharmony_ci }, 20588c2ecf20Sopenharmony_ci { 20598c2ecf20Sopenharmony_ci .subvendor = 0x1462, 20608c2ecf20Sopenharmony_ci .subdevice = 0x5470, 20618c2ecf20Sopenharmony_ci .name = "MSI P4 ATX 645 Ultra", 20628c2ecf20Sopenharmony_ci .type = AC97_TUNE_HP_ONLY 20638c2ecf20Sopenharmony_ci }, 20648c2ecf20Sopenharmony_ci { 20658c2ecf20Sopenharmony_ci .subvendor = 0x161f, 20668c2ecf20Sopenharmony_ci .subdevice = 0x202f, 20678c2ecf20Sopenharmony_ci .name = "Gateway M520", 20688c2ecf20Sopenharmony_ci .type = AC97_TUNE_INV_EAPD 20698c2ecf20Sopenharmony_ci }, 20708c2ecf20Sopenharmony_ci { 20718c2ecf20Sopenharmony_ci .subvendor = 0x161f, 20728c2ecf20Sopenharmony_ci .subdevice = 0x203a, 20738c2ecf20Sopenharmony_ci .name = "Gateway 4525GZ", /* AD1981B */ 20748c2ecf20Sopenharmony_ci .type = AC97_TUNE_INV_EAPD 20758c2ecf20Sopenharmony_ci }, 20768c2ecf20Sopenharmony_ci { 20778c2ecf20Sopenharmony_ci .subvendor = 0x1734, 20788c2ecf20Sopenharmony_ci .subdevice = 0x0088, 20798c2ecf20Sopenharmony_ci .name = "Fujitsu-Siemens D1522", /* AD1981 */ 20808c2ecf20Sopenharmony_ci .type = AC97_TUNE_HP_ONLY 20818c2ecf20Sopenharmony_ci }, 20828c2ecf20Sopenharmony_ci { 20838c2ecf20Sopenharmony_ci .subvendor = 0x8086, 20848c2ecf20Sopenharmony_ci .subdevice = 0x2000, 20858c2ecf20Sopenharmony_ci .mask = 0xfff0, 20868c2ecf20Sopenharmony_ci .name = "Intel ICH5/AD1985", 20878c2ecf20Sopenharmony_ci .type = AC97_TUNE_AD_SHARING 20888c2ecf20Sopenharmony_ci }, 20898c2ecf20Sopenharmony_ci { 20908c2ecf20Sopenharmony_ci .subvendor = 0x8086, 20918c2ecf20Sopenharmony_ci .subdevice = 0x4000, 20928c2ecf20Sopenharmony_ci .mask = 0xfff0, 20938c2ecf20Sopenharmony_ci .name = "Intel ICH5/AD1985", 20948c2ecf20Sopenharmony_ci .type = AC97_TUNE_AD_SHARING 20958c2ecf20Sopenharmony_ci }, 20968c2ecf20Sopenharmony_ci { 20978c2ecf20Sopenharmony_ci .subvendor = 0x8086, 20988c2ecf20Sopenharmony_ci .subdevice = 0x4856, 20998c2ecf20Sopenharmony_ci .name = "Intel D845WN (82801BA)", 21008c2ecf20Sopenharmony_ci .type = AC97_TUNE_SWAP_HP 21018c2ecf20Sopenharmony_ci }, 21028c2ecf20Sopenharmony_ci { 21038c2ecf20Sopenharmony_ci .subvendor = 0x8086, 21048c2ecf20Sopenharmony_ci .subdevice = 0x4d44, 21058c2ecf20Sopenharmony_ci .name = "Intel D850EMV2", /* AD1885 */ 21068c2ecf20Sopenharmony_ci .type = AC97_TUNE_HP_ONLY 21078c2ecf20Sopenharmony_ci }, 21088c2ecf20Sopenharmony_ci { 21098c2ecf20Sopenharmony_ci .subvendor = 0x8086, 21108c2ecf20Sopenharmony_ci .subdevice = 0x4d56, 21118c2ecf20Sopenharmony_ci .name = "Intel ICH/AD1885", 21128c2ecf20Sopenharmony_ci .type = AC97_TUNE_HP_ONLY 21138c2ecf20Sopenharmony_ci }, 21148c2ecf20Sopenharmony_ci { 21158c2ecf20Sopenharmony_ci .subvendor = 0x8086, 21168c2ecf20Sopenharmony_ci .subdevice = 0x6000, 21178c2ecf20Sopenharmony_ci .mask = 0xfff0, 21188c2ecf20Sopenharmony_ci .name = "Intel ICH5/AD1985", 21198c2ecf20Sopenharmony_ci .type = AC97_TUNE_AD_SHARING 21208c2ecf20Sopenharmony_ci }, 21218c2ecf20Sopenharmony_ci { 21228c2ecf20Sopenharmony_ci .subvendor = 0x8086, 21238c2ecf20Sopenharmony_ci .subdevice = 0xe000, 21248c2ecf20Sopenharmony_ci .mask = 0xfff0, 21258c2ecf20Sopenharmony_ci .name = "Intel ICH5/AD1985", 21268c2ecf20Sopenharmony_ci .type = AC97_TUNE_AD_SHARING 21278c2ecf20Sopenharmony_ci }, 21288c2ecf20Sopenharmony_ci#if 0 /* FIXME: this seems wrong on most boards */ 21298c2ecf20Sopenharmony_ci { 21308c2ecf20Sopenharmony_ci .subvendor = 0x8086, 21318c2ecf20Sopenharmony_ci .subdevice = 0xa000, 21328c2ecf20Sopenharmony_ci .mask = 0xfff0, 21338c2ecf20Sopenharmony_ci .name = "Intel ICH5/AD1985", 21348c2ecf20Sopenharmony_ci .type = AC97_TUNE_HP_ONLY 21358c2ecf20Sopenharmony_ci }, 21368c2ecf20Sopenharmony_ci#endif 21378c2ecf20Sopenharmony_ci { } /* terminator */ 21388c2ecf20Sopenharmony_ci}; 21398c2ecf20Sopenharmony_ci 21408c2ecf20Sopenharmony_cistatic int snd_intel8x0_mixer(struct intel8x0 *chip, int ac97_clock, 21418c2ecf20Sopenharmony_ci const char *quirk_override) 21428c2ecf20Sopenharmony_ci{ 21438c2ecf20Sopenharmony_ci struct snd_ac97_bus *pbus; 21448c2ecf20Sopenharmony_ci struct snd_ac97_template ac97; 21458c2ecf20Sopenharmony_ci int err; 21468c2ecf20Sopenharmony_ci unsigned int i, codecs; 21478c2ecf20Sopenharmony_ci unsigned int glob_sta = 0; 21488c2ecf20Sopenharmony_ci const struct snd_ac97_bus_ops *ops; 21498c2ecf20Sopenharmony_ci static const struct snd_ac97_bus_ops standard_bus_ops = { 21508c2ecf20Sopenharmony_ci .write = snd_intel8x0_codec_write, 21518c2ecf20Sopenharmony_ci .read = snd_intel8x0_codec_read, 21528c2ecf20Sopenharmony_ci }; 21538c2ecf20Sopenharmony_ci static const struct snd_ac97_bus_ops ali_bus_ops = { 21548c2ecf20Sopenharmony_ci .write = snd_intel8x0_ali_codec_write, 21558c2ecf20Sopenharmony_ci .read = snd_intel8x0_ali_codec_read, 21568c2ecf20Sopenharmony_ci }; 21578c2ecf20Sopenharmony_ci 21588c2ecf20Sopenharmony_ci chip->spdif_idx = -1; /* use PCMOUT (or disabled) */ 21598c2ecf20Sopenharmony_ci if (!spdif_aclink) { 21608c2ecf20Sopenharmony_ci switch (chip->device_type) { 21618c2ecf20Sopenharmony_ci case DEVICE_NFORCE: 21628c2ecf20Sopenharmony_ci chip->spdif_idx = NVD_SPBAR; 21638c2ecf20Sopenharmony_ci break; 21648c2ecf20Sopenharmony_ci case DEVICE_ALI: 21658c2ecf20Sopenharmony_ci chip->spdif_idx = ALID_AC97SPDIFOUT; 21668c2ecf20Sopenharmony_ci break; 21678c2ecf20Sopenharmony_ci case DEVICE_INTEL_ICH4: 21688c2ecf20Sopenharmony_ci chip->spdif_idx = ICHD_SPBAR; 21698c2ecf20Sopenharmony_ci break; 21708c2ecf20Sopenharmony_ci } 21718c2ecf20Sopenharmony_ci } 21728c2ecf20Sopenharmony_ci 21738c2ecf20Sopenharmony_ci chip->in_ac97_init = 1; 21748c2ecf20Sopenharmony_ci 21758c2ecf20Sopenharmony_ci memset(&ac97, 0, sizeof(ac97)); 21768c2ecf20Sopenharmony_ci ac97.private_data = chip; 21778c2ecf20Sopenharmony_ci ac97.private_free = snd_intel8x0_mixer_free_ac97; 21788c2ecf20Sopenharmony_ci ac97.scaps = AC97_SCAP_SKIP_MODEM | AC97_SCAP_POWER_SAVE; 21798c2ecf20Sopenharmony_ci if (chip->xbox) 21808c2ecf20Sopenharmony_ci ac97.scaps |= AC97_SCAP_DETECT_BY_VENDOR; 21818c2ecf20Sopenharmony_ci if (chip->device_type != DEVICE_ALI) { 21828c2ecf20Sopenharmony_ci glob_sta = igetdword(chip, ICHREG(GLOB_STA)); 21838c2ecf20Sopenharmony_ci ops = &standard_bus_ops; 21848c2ecf20Sopenharmony_ci chip->in_sdin_init = 1; 21858c2ecf20Sopenharmony_ci codecs = 0; 21868c2ecf20Sopenharmony_ci for (i = 0; i < chip->max_codecs; i++) { 21878c2ecf20Sopenharmony_ci if (! (glob_sta & chip->codec_bit[i])) 21888c2ecf20Sopenharmony_ci continue; 21898c2ecf20Sopenharmony_ci if (chip->device_type == DEVICE_INTEL_ICH4) { 21908c2ecf20Sopenharmony_ci snd_intel8x0_codec_read_test(chip, codecs); 21918c2ecf20Sopenharmony_ci chip->ac97_sdin[codecs] = 21928c2ecf20Sopenharmony_ci igetbyte(chip, ICHREG(SDM)) & ICH_LDI_MASK; 21938c2ecf20Sopenharmony_ci if (snd_BUG_ON(chip->ac97_sdin[codecs] >= 3)) 21948c2ecf20Sopenharmony_ci chip->ac97_sdin[codecs] = 0; 21958c2ecf20Sopenharmony_ci } else 21968c2ecf20Sopenharmony_ci chip->ac97_sdin[codecs] = i; 21978c2ecf20Sopenharmony_ci codecs++; 21988c2ecf20Sopenharmony_ci } 21998c2ecf20Sopenharmony_ci chip->in_sdin_init = 0; 22008c2ecf20Sopenharmony_ci if (! codecs) 22018c2ecf20Sopenharmony_ci codecs = 1; 22028c2ecf20Sopenharmony_ci } else { 22038c2ecf20Sopenharmony_ci ops = &ali_bus_ops; 22048c2ecf20Sopenharmony_ci codecs = 1; 22058c2ecf20Sopenharmony_ci /* detect the secondary codec */ 22068c2ecf20Sopenharmony_ci for (i = 0; i < 100; i++) { 22078c2ecf20Sopenharmony_ci unsigned int reg = igetdword(chip, ICHREG(ALI_RTSR)); 22088c2ecf20Sopenharmony_ci if (reg & 0x40) { 22098c2ecf20Sopenharmony_ci codecs = 2; 22108c2ecf20Sopenharmony_ci break; 22118c2ecf20Sopenharmony_ci } 22128c2ecf20Sopenharmony_ci iputdword(chip, ICHREG(ALI_RTSR), reg | 0x40); 22138c2ecf20Sopenharmony_ci udelay(1); 22148c2ecf20Sopenharmony_ci } 22158c2ecf20Sopenharmony_ci } 22168c2ecf20Sopenharmony_ci if ((err = snd_ac97_bus(chip->card, 0, ops, chip, &pbus)) < 0) 22178c2ecf20Sopenharmony_ci goto __err; 22188c2ecf20Sopenharmony_ci pbus->private_free = snd_intel8x0_mixer_free_ac97_bus; 22198c2ecf20Sopenharmony_ci if (ac97_clock >= 8000 && ac97_clock <= 48000) 22208c2ecf20Sopenharmony_ci pbus->clock = ac97_clock; 22218c2ecf20Sopenharmony_ci /* FIXME: my test board doesn't work well with VRA... */ 22228c2ecf20Sopenharmony_ci if (chip->device_type == DEVICE_ALI) 22238c2ecf20Sopenharmony_ci pbus->no_vra = 1; 22248c2ecf20Sopenharmony_ci else 22258c2ecf20Sopenharmony_ci pbus->dra = 1; 22268c2ecf20Sopenharmony_ci chip->ac97_bus = pbus; 22278c2ecf20Sopenharmony_ci chip->ncodecs = codecs; 22288c2ecf20Sopenharmony_ci 22298c2ecf20Sopenharmony_ci ac97.pci = chip->pci; 22308c2ecf20Sopenharmony_ci for (i = 0; i < codecs; i++) { 22318c2ecf20Sopenharmony_ci ac97.num = i; 22328c2ecf20Sopenharmony_ci if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97[i])) < 0) { 22338c2ecf20Sopenharmony_ci if (err != -EACCES) 22348c2ecf20Sopenharmony_ci dev_err(chip->card->dev, 22358c2ecf20Sopenharmony_ci "Unable to initialize codec #%d\n", i); 22368c2ecf20Sopenharmony_ci if (i == 0) 22378c2ecf20Sopenharmony_ci goto __err; 22388c2ecf20Sopenharmony_ci } 22398c2ecf20Sopenharmony_ci } 22408c2ecf20Sopenharmony_ci /* tune up the primary codec */ 22418c2ecf20Sopenharmony_ci snd_ac97_tune_hardware(chip->ac97[0], ac97_quirks, quirk_override); 22428c2ecf20Sopenharmony_ci /* enable separate SDINs for ICH4 */ 22438c2ecf20Sopenharmony_ci if (chip->device_type == DEVICE_INTEL_ICH4) 22448c2ecf20Sopenharmony_ci pbus->isdin = 1; 22458c2ecf20Sopenharmony_ci /* find the available PCM streams */ 22468c2ecf20Sopenharmony_ci i = ARRAY_SIZE(ac97_pcm_defs); 22478c2ecf20Sopenharmony_ci if (chip->device_type != DEVICE_INTEL_ICH4) 22488c2ecf20Sopenharmony_ci i -= 2; /* do not allocate PCM2IN and MIC2 */ 22498c2ecf20Sopenharmony_ci if (chip->spdif_idx < 0) 22508c2ecf20Sopenharmony_ci i--; /* do not allocate S/PDIF */ 22518c2ecf20Sopenharmony_ci err = snd_ac97_pcm_assign(pbus, i, ac97_pcm_defs); 22528c2ecf20Sopenharmony_ci if (err < 0) 22538c2ecf20Sopenharmony_ci goto __err; 22548c2ecf20Sopenharmony_ci chip->ichd[ICHD_PCMOUT].pcm = &pbus->pcms[0]; 22558c2ecf20Sopenharmony_ci chip->ichd[ICHD_PCMIN].pcm = &pbus->pcms[1]; 22568c2ecf20Sopenharmony_ci chip->ichd[ICHD_MIC].pcm = &pbus->pcms[2]; 22578c2ecf20Sopenharmony_ci if (chip->spdif_idx >= 0) 22588c2ecf20Sopenharmony_ci chip->ichd[chip->spdif_idx].pcm = &pbus->pcms[3]; 22598c2ecf20Sopenharmony_ci if (chip->device_type == DEVICE_INTEL_ICH4) { 22608c2ecf20Sopenharmony_ci chip->ichd[ICHD_PCM2IN].pcm = &pbus->pcms[4]; 22618c2ecf20Sopenharmony_ci chip->ichd[ICHD_MIC2].pcm = &pbus->pcms[5]; 22628c2ecf20Sopenharmony_ci } 22638c2ecf20Sopenharmony_ci /* enable separate SDINs for ICH4 */ 22648c2ecf20Sopenharmony_ci if (chip->device_type == DEVICE_INTEL_ICH4) { 22658c2ecf20Sopenharmony_ci struct ac97_pcm *pcm = chip->ichd[ICHD_PCM2IN].pcm; 22668c2ecf20Sopenharmony_ci u8 tmp = igetbyte(chip, ICHREG(SDM)); 22678c2ecf20Sopenharmony_ci tmp &= ~(ICH_DI2L_MASK|ICH_DI1L_MASK); 22688c2ecf20Sopenharmony_ci if (pcm) { 22698c2ecf20Sopenharmony_ci tmp |= ICH_SE; /* steer enable for multiple SDINs */ 22708c2ecf20Sopenharmony_ci tmp |= chip->ac97_sdin[0] << ICH_DI1L_SHIFT; 22718c2ecf20Sopenharmony_ci for (i = 1; i < 4; i++) { 22728c2ecf20Sopenharmony_ci if (pcm->r[0].codec[i]) { 22738c2ecf20Sopenharmony_ci tmp |= chip->ac97_sdin[pcm->r[0].codec[1]->num] << ICH_DI2L_SHIFT; 22748c2ecf20Sopenharmony_ci break; 22758c2ecf20Sopenharmony_ci } 22768c2ecf20Sopenharmony_ci } 22778c2ecf20Sopenharmony_ci } else { 22788c2ecf20Sopenharmony_ci tmp &= ~ICH_SE; /* steer disable */ 22798c2ecf20Sopenharmony_ci } 22808c2ecf20Sopenharmony_ci iputbyte(chip, ICHREG(SDM), tmp); 22818c2ecf20Sopenharmony_ci } 22828c2ecf20Sopenharmony_ci if (pbus->pcms[0].r[0].slots & (1 << AC97_SLOT_PCM_SLEFT)) { 22838c2ecf20Sopenharmony_ci chip->multi4 = 1; 22848c2ecf20Sopenharmony_ci if (pbus->pcms[0].r[0].slots & (1 << AC97_SLOT_LFE)) { 22858c2ecf20Sopenharmony_ci chip->multi6 = 1; 22868c2ecf20Sopenharmony_ci if (chip->ac97[0]->flags & AC97_HAS_8CH) 22878c2ecf20Sopenharmony_ci chip->multi8 = 1; 22888c2ecf20Sopenharmony_ci } 22898c2ecf20Sopenharmony_ci } 22908c2ecf20Sopenharmony_ci if (pbus->pcms[0].r[1].rslots[0]) { 22918c2ecf20Sopenharmony_ci chip->dra = 1; 22928c2ecf20Sopenharmony_ci } 22938c2ecf20Sopenharmony_ci if (chip->device_type == DEVICE_INTEL_ICH4) { 22948c2ecf20Sopenharmony_ci if ((igetdword(chip, ICHREG(GLOB_STA)) & ICH_SAMPLE_CAP) == ICH_SAMPLE_16_20) 22958c2ecf20Sopenharmony_ci chip->smp20bit = 1; 22968c2ecf20Sopenharmony_ci } 22978c2ecf20Sopenharmony_ci if (chip->device_type == DEVICE_NFORCE && !spdif_aclink) { 22988c2ecf20Sopenharmony_ci /* 48kHz only */ 22998c2ecf20Sopenharmony_ci chip->ichd[chip->spdif_idx].pcm->rates = SNDRV_PCM_RATE_48000; 23008c2ecf20Sopenharmony_ci } 23018c2ecf20Sopenharmony_ci if (chip->device_type == DEVICE_INTEL_ICH4 && !spdif_aclink) { 23028c2ecf20Sopenharmony_ci /* use slot 10/11 for SPDIF */ 23038c2ecf20Sopenharmony_ci u32 val; 23048c2ecf20Sopenharmony_ci val = igetdword(chip, ICHREG(GLOB_CNT)) & ~ICH_PCM_SPDIF_MASK; 23058c2ecf20Sopenharmony_ci val |= ICH_PCM_SPDIF_1011; 23068c2ecf20Sopenharmony_ci iputdword(chip, ICHREG(GLOB_CNT), val); 23078c2ecf20Sopenharmony_ci snd_ac97_update_bits(chip->ac97[0], AC97_EXTENDED_STATUS, 0x03 << 4, 0x03 << 4); 23088c2ecf20Sopenharmony_ci } 23098c2ecf20Sopenharmony_ci chip->in_ac97_init = 0; 23108c2ecf20Sopenharmony_ci return 0; 23118c2ecf20Sopenharmony_ci 23128c2ecf20Sopenharmony_ci __err: 23138c2ecf20Sopenharmony_ci /* clear the cold-reset bit for the next chance */ 23148c2ecf20Sopenharmony_ci if (chip->device_type != DEVICE_ALI) 23158c2ecf20Sopenharmony_ci iputdword(chip, ICHREG(GLOB_CNT), 23168c2ecf20Sopenharmony_ci igetdword(chip, ICHREG(GLOB_CNT)) & ~ICH_AC97COLD); 23178c2ecf20Sopenharmony_ci return err; 23188c2ecf20Sopenharmony_ci} 23198c2ecf20Sopenharmony_ci 23208c2ecf20Sopenharmony_ci 23218c2ecf20Sopenharmony_ci/* 23228c2ecf20Sopenharmony_ci * 23238c2ecf20Sopenharmony_ci */ 23248c2ecf20Sopenharmony_ci 23258c2ecf20Sopenharmony_cistatic void do_ali_reset(struct intel8x0 *chip) 23268c2ecf20Sopenharmony_ci{ 23278c2ecf20Sopenharmony_ci iputdword(chip, ICHREG(ALI_SCR), ICH_ALI_SC_RESET); 23288c2ecf20Sopenharmony_ci iputdword(chip, ICHREG(ALI_FIFOCR1), 0x83838383); 23298c2ecf20Sopenharmony_ci iputdword(chip, ICHREG(ALI_FIFOCR2), 0x83838383); 23308c2ecf20Sopenharmony_ci iputdword(chip, ICHREG(ALI_FIFOCR3), 0x83838383); 23318c2ecf20Sopenharmony_ci iputdword(chip, ICHREG(ALI_INTERFACECR), 23328c2ecf20Sopenharmony_ci ICH_ALI_IF_PI|ICH_ALI_IF_PO); 23338c2ecf20Sopenharmony_ci iputdword(chip, ICHREG(ALI_INTERRUPTCR), 0x00000000); 23348c2ecf20Sopenharmony_ci iputdword(chip, ICHREG(ALI_INTERRUPTSR), 0x00000000); 23358c2ecf20Sopenharmony_ci} 23368c2ecf20Sopenharmony_ci 23378c2ecf20Sopenharmony_ci#ifdef CONFIG_SND_AC97_POWER_SAVE 23388c2ecf20Sopenharmony_cistatic const struct snd_pci_quirk ich_chip_reset_mode[] = { 23398c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x1014, 0x051f, "Thinkpad R32", 1), 23408c2ecf20Sopenharmony_ci { } /* end */ 23418c2ecf20Sopenharmony_ci}; 23428c2ecf20Sopenharmony_ci 23438c2ecf20Sopenharmony_cistatic int snd_intel8x0_ich_chip_cold_reset(struct intel8x0 *chip) 23448c2ecf20Sopenharmony_ci{ 23458c2ecf20Sopenharmony_ci unsigned int cnt; 23468c2ecf20Sopenharmony_ci /* ACLink on, 2 channels */ 23478c2ecf20Sopenharmony_ci 23488c2ecf20Sopenharmony_ci if (snd_pci_quirk_lookup(chip->pci, ich_chip_reset_mode)) 23498c2ecf20Sopenharmony_ci return -EIO; 23508c2ecf20Sopenharmony_ci 23518c2ecf20Sopenharmony_ci cnt = igetdword(chip, ICHREG(GLOB_CNT)); 23528c2ecf20Sopenharmony_ci cnt &= ~(ICH_ACLINK | ICH_PCM_246_MASK); 23538c2ecf20Sopenharmony_ci 23548c2ecf20Sopenharmony_ci /* do cold reset - the full ac97 powerdown may leave the controller 23558c2ecf20Sopenharmony_ci * in a warm state but actually it cannot communicate with the codec. 23568c2ecf20Sopenharmony_ci */ 23578c2ecf20Sopenharmony_ci iputdword(chip, ICHREG(GLOB_CNT), cnt & ~ICH_AC97COLD); 23588c2ecf20Sopenharmony_ci cnt = igetdword(chip, ICHREG(GLOB_CNT)); 23598c2ecf20Sopenharmony_ci udelay(10); 23608c2ecf20Sopenharmony_ci iputdword(chip, ICHREG(GLOB_CNT), cnt | ICH_AC97COLD); 23618c2ecf20Sopenharmony_ci msleep(1); 23628c2ecf20Sopenharmony_ci return 0; 23638c2ecf20Sopenharmony_ci} 23648c2ecf20Sopenharmony_ci#define snd_intel8x0_ich_chip_can_cold_reset(chip) \ 23658c2ecf20Sopenharmony_ci (!snd_pci_quirk_lookup(chip->pci, ich_chip_reset_mode)) 23668c2ecf20Sopenharmony_ci#else 23678c2ecf20Sopenharmony_ci#define snd_intel8x0_ich_chip_cold_reset(chip) 0 23688c2ecf20Sopenharmony_ci#define snd_intel8x0_ich_chip_can_cold_reset(chip) (0) 23698c2ecf20Sopenharmony_ci#endif 23708c2ecf20Sopenharmony_ci 23718c2ecf20Sopenharmony_cistatic int snd_intel8x0_ich_chip_reset(struct intel8x0 *chip) 23728c2ecf20Sopenharmony_ci{ 23738c2ecf20Sopenharmony_ci unsigned long end_time; 23748c2ecf20Sopenharmony_ci unsigned int cnt; 23758c2ecf20Sopenharmony_ci /* ACLink on, 2 channels */ 23768c2ecf20Sopenharmony_ci cnt = igetdword(chip, ICHREG(GLOB_CNT)); 23778c2ecf20Sopenharmony_ci cnt &= ~(ICH_ACLINK | ICH_PCM_246_MASK); 23788c2ecf20Sopenharmony_ci /* finish cold or do warm reset */ 23798c2ecf20Sopenharmony_ci cnt |= (cnt & ICH_AC97COLD) == 0 ? ICH_AC97COLD : ICH_AC97WARM; 23808c2ecf20Sopenharmony_ci iputdword(chip, ICHREG(GLOB_CNT), cnt); 23818c2ecf20Sopenharmony_ci end_time = (jiffies + (HZ / 4)) + 1; 23828c2ecf20Sopenharmony_ci do { 23838c2ecf20Sopenharmony_ci if ((igetdword(chip, ICHREG(GLOB_CNT)) & ICH_AC97WARM) == 0) 23848c2ecf20Sopenharmony_ci return 0; 23858c2ecf20Sopenharmony_ci schedule_timeout_uninterruptible(1); 23868c2ecf20Sopenharmony_ci } while (time_after_eq(end_time, jiffies)); 23878c2ecf20Sopenharmony_ci dev_err(chip->card->dev, "AC'97 warm reset still in progress? [0x%x]\n", 23888c2ecf20Sopenharmony_ci igetdword(chip, ICHREG(GLOB_CNT))); 23898c2ecf20Sopenharmony_ci return -EIO; 23908c2ecf20Sopenharmony_ci} 23918c2ecf20Sopenharmony_ci 23928c2ecf20Sopenharmony_cistatic int snd_intel8x0_ich_chip_init(struct intel8x0 *chip, int probing) 23938c2ecf20Sopenharmony_ci{ 23948c2ecf20Sopenharmony_ci unsigned long end_time; 23958c2ecf20Sopenharmony_ci unsigned int status, nstatus; 23968c2ecf20Sopenharmony_ci unsigned int cnt; 23978c2ecf20Sopenharmony_ci int err; 23988c2ecf20Sopenharmony_ci 23998c2ecf20Sopenharmony_ci /* put logic to right state */ 24008c2ecf20Sopenharmony_ci /* first clear status bits */ 24018c2ecf20Sopenharmony_ci status = ICH_RCS | ICH_MCINT | ICH_POINT | ICH_PIINT; 24028c2ecf20Sopenharmony_ci if (chip->device_type == DEVICE_NFORCE) 24038c2ecf20Sopenharmony_ci status |= ICH_NVSPINT; 24048c2ecf20Sopenharmony_ci cnt = igetdword(chip, ICHREG(GLOB_STA)); 24058c2ecf20Sopenharmony_ci iputdword(chip, ICHREG(GLOB_STA), cnt & status); 24068c2ecf20Sopenharmony_ci 24078c2ecf20Sopenharmony_ci if (snd_intel8x0_ich_chip_can_cold_reset(chip)) 24088c2ecf20Sopenharmony_ci err = snd_intel8x0_ich_chip_cold_reset(chip); 24098c2ecf20Sopenharmony_ci else 24108c2ecf20Sopenharmony_ci err = snd_intel8x0_ich_chip_reset(chip); 24118c2ecf20Sopenharmony_ci if (err < 0) 24128c2ecf20Sopenharmony_ci return err; 24138c2ecf20Sopenharmony_ci 24148c2ecf20Sopenharmony_ci if (probing) { 24158c2ecf20Sopenharmony_ci /* wait for any codec ready status. 24168c2ecf20Sopenharmony_ci * Once it becomes ready it should remain ready 24178c2ecf20Sopenharmony_ci * as long as we do not disable the ac97 link. 24188c2ecf20Sopenharmony_ci */ 24198c2ecf20Sopenharmony_ci end_time = jiffies + HZ; 24208c2ecf20Sopenharmony_ci do { 24218c2ecf20Sopenharmony_ci status = igetdword(chip, ICHREG(GLOB_STA)) & 24228c2ecf20Sopenharmony_ci chip->codec_isr_bits; 24238c2ecf20Sopenharmony_ci if (status) 24248c2ecf20Sopenharmony_ci break; 24258c2ecf20Sopenharmony_ci schedule_timeout_uninterruptible(1); 24268c2ecf20Sopenharmony_ci } while (time_after_eq(end_time, jiffies)); 24278c2ecf20Sopenharmony_ci if (! status) { 24288c2ecf20Sopenharmony_ci /* no codec is found */ 24298c2ecf20Sopenharmony_ci dev_err(chip->card->dev, 24308c2ecf20Sopenharmony_ci "codec_ready: codec is not ready [0x%x]\n", 24318c2ecf20Sopenharmony_ci igetdword(chip, ICHREG(GLOB_STA))); 24328c2ecf20Sopenharmony_ci return -EIO; 24338c2ecf20Sopenharmony_ci } 24348c2ecf20Sopenharmony_ci 24358c2ecf20Sopenharmony_ci /* wait for other codecs ready status. */ 24368c2ecf20Sopenharmony_ci end_time = jiffies + HZ / 4; 24378c2ecf20Sopenharmony_ci while (status != chip->codec_isr_bits && 24388c2ecf20Sopenharmony_ci time_after_eq(end_time, jiffies)) { 24398c2ecf20Sopenharmony_ci schedule_timeout_uninterruptible(1); 24408c2ecf20Sopenharmony_ci status |= igetdword(chip, ICHREG(GLOB_STA)) & 24418c2ecf20Sopenharmony_ci chip->codec_isr_bits; 24428c2ecf20Sopenharmony_ci } 24438c2ecf20Sopenharmony_ci 24448c2ecf20Sopenharmony_ci } else { 24458c2ecf20Sopenharmony_ci /* resume phase */ 24468c2ecf20Sopenharmony_ci int i; 24478c2ecf20Sopenharmony_ci status = 0; 24488c2ecf20Sopenharmony_ci for (i = 0; i < chip->ncodecs; i++) 24498c2ecf20Sopenharmony_ci if (chip->ac97[i]) 24508c2ecf20Sopenharmony_ci status |= chip->codec_bit[chip->ac97_sdin[i]]; 24518c2ecf20Sopenharmony_ci /* wait until all the probed codecs are ready */ 24528c2ecf20Sopenharmony_ci end_time = jiffies + HZ; 24538c2ecf20Sopenharmony_ci do { 24548c2ecf20Sopenharmony_ci nstatus = igetdword(chip, ICHREG(GLOB_STA)) & 24558c2ecf20Sopenharmony_ci chip->codec_isr_bits; 24568c2ecf20Sopenharmony_ci if (status == nstatus) 24578c2ecf20Sopenharmony_ci break; 24588c2ecf20Sopenharmony_ci schedule_timeout_uninterruptible(1); 24598c2ecf20Sopenharmony_ci } while (time_after_eq(end_time, jiffies)); 24608c2ecf20Sopenharmony_ci } 24618c2ecf20Sopenharmony_ci 24628c2ecf20Sopenharmony_ci if (chip->device_type == DEVICE_SIS) { 24638c2ecf20Sopenharmony_ci /* unmute the output on SIS7012 */ 24648c2ecf20Sopenharmony_ci iputword(chip, 0x4c, igetword(chip, 0x4c) | 1); 24658c2ecf20Sopenharmony_ci } 24668c2ecf20Sopenharmony_ci if (chip->device_type == DEVICE_NFORCE && !spdif_aclink) { 24678c2ecf20Sopenharmony_ci /* enable SPDIF interrupt */ 24688c2ecf20Sopenharmony_ci unsigned int val; 24698c2ecf20Sopenharmony_ci pci_read_config_dword(chip->pci, 0x4c, &val); 24708c2ecf20Sopenharmony_ci val |= 0x1000000; 24718c2ecf20Sopenharmony_ci pci_write_config_dword(chip->pci, 0x4c, val); 24728c2ecf20Sopenharmony_ci } 24738c2ecf20Sopenharmony_ci return 0; 24748c2ecf20Sopenharmony_ci} 24758c2ecf20Sopenharmony_ci 24768c2ecf20Sopenharmony_cistatic int snd_intel8x0_ali_chip_init(struct intel8x0 *chip, int probing) 24778c2ecf20Sopenharmony_ci{ 24788c2ecf20Sopenharmony_ci u32 reg; 24798c2ecf20Sopenharmony_ci int i = 0; 24808c2ecf20Sopenharmony_ci 24818c2ecf20Sopenharmony_ci reg = igetdword(chip, ICHREG(ALI_SCR)); 24828c2ecf20Sopenharmony_ci if ((reg & 2) == 0) /* Cold required */ 24838c2ecf20Sopenharmony_ci reg |= 2; 24848c2ecf20Sopenharmony_ci else 24858c2ecf20Sopenharmony_ci reg |= 1; /* Warm */ 24868c2ecf20Sopenharmony_ci reg &= ~0x80000000; /* ACLink on */ 24878c2ecf20Sopenharmony_ci iputdword(chip, ICHREG(ALI_SCR), reg); 24888c2ecf20Sopenharmony_ci 24898c2ecf20Sopenharmony_ci for (i = 0; i < HZ / 2; i++) { 24908c2ecf20Sopenharmony_ci if (! (igetdword(chip, ICHREG(ALI_INTERRUPTSR)) & ALI_INT_GPIO)) 24918c2ecf20Sopenharmony_ci goto __ok; 24928c2ecf20Sopenharmony_ci schedule_timeout_uninterruptible(1); 24938c2ecf20Sopenharmony_ci } 24948c2ecf20Sopenharmony_ci dev_err(chip->card->dev, "AC'97 reset failed.\n"); 24958c2ecf20Sopenharmony_ci if (probing) 24968c2ecf20Sopenharmony_ci return -EIO; 24978c2ecf20Sopenharmony_ci 24988c2ecf20Sopenharmony_ci __ok: 24998c2ecf20Sopenharmony_ci for (i = 0; i < HZ / 2; i++) { 25008c2ecf20Sopenharmony_ci reg = igetdword(chip, ICHREG(ALI_RTSR)); 25018c2ecf20Sopenharmony_ci if (reg & 0x80) /* primary codec */ 25028c2ecf20Sopenharmony_ci break; 25038c2ecf20Sopenharmony_ci iputdword(chip, ICHREG(ALI_RTSR), reg | 0x80); 25048c2ecf20Sopenharmony_ci schedule_timeout_uninterruptible(1); 25058c2ecf20Sopenharmony_ci } 25068c2ecf20Sopenharmony_ci 25078c2ecf20Sopenharmony_ci do_ali_reset(chip); 25088c2ecf20Sopenharmony_ci return 0; 25098c2ecf20Sopenharmony_ci} 25108c2ecf20Sopenharmony_ci 25118c2ecf20Sopenharmony_cistatic int snd_intel8x0_chip_init(struct intel8x0 *chip, int probing) 25128c2ecf20Sopenharmony_ci{ 25138c2ecf20Sopenharmony_ci unsigned int i, timeout; 25148c2ecf20Sopenharmony_ci int err; 25158c2ecf20Sopenharmony_ci 25168c2ecf20Sopenharmony_ci if (chip->device_type != DEVICE_ALI) { 25178c2ecf20Sopenharmony_ci if ((err = snd_intel8x0_ich_chip_init(chip, probing)) < 0) 25188c2ecf20Sopenharmony_ci return err; 25198c2ecf20Sopenharmony_ci iagetword(chip, 0); /* clear semaphore flag */ 25208c2ecf20Sopenharmony_ci } else { 25218c2ecf20Sopenharmony_ci if ((err = snd_intel8x0_ali_chip_init(chip, probing)) < 0) 25228c2ecf20Sopenharmony_ci return err; 25238c2ecf20Sopenharmony_ci } 25248c2ecf20Sopenharmony_ci 25258c2ecf20Sopenharmony_ci /* disable interrupts */ 25268c2ecf20Sopenharmony_ci for (i = 0; i < chip->bdbars_count; i++) 25278c2ecf20Sopenharmony_ci iputbyte(chip, ICH_REG_OFF_CR + chip->ichd[i].reg_offset, 0x00); 25288c2ecf20Sopenharmony_ci /* reset channels */ 25298c2ecf20Sopenharmony_ci for (i = 0; i < chip->bdbars_count; i++) 25308c2ecf20Sopenharmony_ci iputbyte(chip, ICH_REG_OFF_CR + chip->ichd[i].reg_offset, ICH_RESETREGS); 25318c2ecf20Sopenharmony_ci for (i = 0; i < chip->bdbars_count; i++) { 25328c2ecf20Sopenharmony_ci timeout = 100000; 25338c2ecf20Sopenharmony_ci while (--timeout != 0) { 25348c2ecf20Sopenharmony_ci if ((igetbyte(chip, ICH_REG_OFF_CR + chip->ichd[i].reg_offset) & ICH_RESETREGS) == 0) 25358c2ecf20Sopenharmony_ci break; 25368c2ecf20Sopenharmony_ci } 25378c2ecf20Sopenharmony_ci if (timeout == 0) 25388c2ecf20Sopenharmony_ci dev_err(chip->card->dev, "reset of registers failed?\n"); 25398c2ecf20Sopenharmony_ci } 25408c2ecf20Sopenharmony_ci /* initialize Buffer Descriptor Lists */ 25418c2ecf20Sopenharmony_ci for (i = 0; i < chip->bdbars_count; i++) 25428c2ecf20Sopenharmony_ci iputdword(chip, ICH_REG_OFF_BDBAR + chip->ichd[i].reg_offset, 25438c2ecf20Sopenharmony_ci chip->ichd[i].bdbar_addr); 25448c2ecf20Sopenharmony_ci return 0; 25458c2ecf20Sopenharmony_ci} 25468c2ecf20Sopenharmony_ci 25478c2ecf20Sopenharmony_cistatic int snd_intel8x0_free(struct intel8x0 *chip) 25488c2ecf20Sopenharmony_ci{ 25498c2ecf20Sopenharmony_ci unsigned int i; 25508c2ecf20Sopenharmony_ci 25518c2ecf20Sopenharmony_ci if (chip->irq < 0) 25528c2ecf20Sopenharmony_ci goto __hw_end; 25538c2ecf20Sopenharmony_ci /* disable interrupts */ 25548c2ecf20Sopenharmony_ci for (i = 0; i < chip->bdbars_count; i++) 25558c2ecf20Sopenharmony_ci iputbyte(chip, ICH_REG_OFF_CR + chip->ichd[i].reg_offset, 0x00); 25568c2ecf20Sopenharmony_ci /* reset channels */ 25578c2ecf20Sopenharmony_ci for (i = 0; i < chip->bdbars_count; i++) 25588c2ecf20Sopenharmony_ci iputbyte(chip, ICH_REG_OFF_CR + chip->ichd[i].reg_offset, ICH_RESETREGS); 25598c2ecf20Sopenharmony_ci if (chip->device_type == DEVICE_NFORCE && !spdif_aclink) { 25608c2ecf20Sopenharmony_ci /* stop the spdif interrupt */ 25618c2ecf20Sopenharmony_ci unsigned int val; 25628c2ecf20Sopenharmony_ci pci_read_config_dword(chip->pci, 0x4c, &val); 25638c2ecf20Sopenharmony_ci val &= ~0x1000000; 25648c2ecf20Sopenharmony_ci pci_write_config_dword(chip->pci, 0x4c, val); 25658c2ecf20Sopenharmony_ci } 25668c2ecf20Sopenharmony_ci /* --- */ 25678c2ecf20Sopenharmony_ci 25688c2ecf20Sopenharmony_ci __hw_end: 25698c2ecf20Sopenharmony_ci if (chip->irq >= 0) 25708c2ecf20Sopenharmony_ci free_irq(chip->irq, chip); 25718c2ecf20Sopenharmony_ci if (chip->bdbars.area) 25728c2ecf20Sopenharmony_ci snd_dma_free_pages(&chip->bdbars); 25738c2ecf20Sopenharmony_ci if (chip->addr) 25748c2ecf20Sopenharmony_ci pci_iounmap(chip->pci, chip->addr); 25758c2ecf20Sopenharmony_ci if (chip->bmaddr) 25768c2ecf20Sopenharmony_ci pci_iounmap(chip->pci, chip->bmaddr); 25778c2ecf20Sopenharmony_ci pci_release_regions(chip->pci); 25788c2ecf20Sopenharmony_ci pci_disable_device(chip->pci); 25798c2ecf20Sopenharmony_ci kfree(chip); 25808c2ecf20Sopenharmony_ci return 0; 25818c2ecf20Sopenharmony_ci} 25828c2ecf20Sopenharmony_ci 25838c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 25848c2ecf20Sopenharmony_ci/* 25858c2ecf20Sopenharmony_ci * power management 25868c2ecf20Sopenharmony_ci */ 25878c2ecf20Sopenharmony_cistatic int intel8x0_suspend(struct device *dev) 25888c2ecf20Sopenharmony_ci{ 25898c2ecf20Sopenharmony_ci struct snd_card *card = dev_get_drvdata(dev); 25908c2ecf20Sopenharmony_ci struct intel8x0 *chip = card->private_data; 25918c2ecf20Sopenharmony_ci int i; 25928c2ecf20Sopenharmony_ci 25938c2ecf20Sopenharmony_ci snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); 25948c2ecf20Sopenharmony_ci for (i = 0; i < chip->ncodecs; i++) 25958c2ecf20Sopenharmony_ci snd_ac97_suspend(chip->ac97[i]); 25968c2ecf20Sopenharmony_ci if (chip->device_type == DEVICE_INTEL_ICH4) 25978c2ecf20Sopenharmony_ci chip->sdm_saved = igetbyte(chip, ICHREG(SDM)); 25988c2ecf20Sopenharmony_ci 25998c2ecf20Sopenharmony_ci if (chip->irq >= 0) { 26008c2ecf20Sopenharmony_ci free_irq(chip->irq, chip); 26018c2ecf20Sopenharmony_ci chip->irq = -1; 26028c2ecf20Sopenharmony_ci card->sync_irq = -1; 26038c2ecf20Sopenharmony_ci } 26048c2ecf20Sopenharmony_ci return 0; 26058c2ecf20Sopenharmony_ci} 26068c2ecf20Sopenharmony_ci 26078c2ecf20Sopenharmony_cistatic int intel8x0_resume(struct device *dev) 26088c2ecf20Sopenharmony_ci{ 26098c2ecf20Sopenharmony_ci struct pci_dev *pci = to_pci_dev(dev); 26108c2ecf20Sopenharmony_ci struct snd_card *card = dev_get_drvdata(dev); 26118c2ecf20Sopenharmony_ci struct intel8x0 *chip = card->private_data; 26128c2ecf20Sopenharmony_ci int i; 26138c2ecf20Sopenharmony_ci 26148c2ecf20Sopenharmony_ci snd_intel8x0_chip_init(chip, 0); 26158c2ecf20Sopenharmony_ci if (request_irq(pci->irq, snd_intel8x0_interrupt, 26168c2ecf20Sopenharmony_ci IRQF_SHARED, KBUILD_MODNAME, chip)) { 26178c2ecf20Sopenharmony_ci dev_err(dev, "unable to grab IRQ %d, disabling device\n", 26188c2ecf20Sopenharmony_ci pci->irq); 26198c2ecf20Sopenharmony_ci snd_card_disconnect(card); 26208c2ecf20Sopenharmony_ci return -EIO; 26218c2ecf20Sopenharmony_ci } 26228c2ecf20Sopenharmony_ci chip->irq = pci->irq; 26238c2ecf20Sopenharmony_ci card->sync_irq = chip->irq; 26248c2ecf20Sopenharmony_ci 26258c2ecf20Sopenharmony_ci /* re-initialize mixer stuff */ 26268c2ecf20Sopenharmony_ci if (chip->device_type == DEVICE_INTEL_ICH4 && !spdif_aclink) { 26278c2ecf20Sopenharmony_ci /* enable separate SDINs for ICH4 */ 26288c2ecf20Sopenharmony_ci iputbyte(chip, ICHREG(SDM), chip->sdm_saved); 26298c2ecf20Sopenharmony_ci /* use slot 10/11 for SPDIF */ 26308c2ecf20Sopenharmony_ci iputdword(chip, ICHREG(GLOB_CNT), 26318c2ecf20Sopenharmony_ci (igetdword(chip, ICHREG(GLOB_CNT)) & ~ICH_PCM_SPDIF_MASK) | 26328c2ecf20Sopenharmony_ci ICH_PCM_SPDIF_1011); 26338c2ecf20Sopenharmony_ci } 26348c2ecf20Sopenharmony_ci 26358c2ecf20Sopenharmony_ci for (i = 0; i < chip->ncodecs; i++) 26368c2ecf20Sopenharmony_ci snd_ac97_resume(chip->ac97[i]); 26378c2ecf20Sopenharmony_ci 26388c2ecf20Sopenharmony_ci /* resume status */ 26398c2ecf20Sopenharmony_ci for (i = 0; i < chip->bdbars_count; i++) { 26408c2ecf20Sopenharmony_ci struct ichdev *ichdev = &chip->ichd[i]; 26418c2ecf20Sopenharmony_ci unsigned long port = ichdev->reg_offset; 26428c2ecf20Sopenharmony_ci if (! ichdev->substream || ! ichdev->suspended) 26438c2ecf20Sopenharmony_ci continue; 26448c2ecf20Sopenharmony_ci if (ichdev->ichd == ICHD_PCMOUT) 26458c2ecf20Sopenharmony_ci snd_intel8x0_setup_pcm_out(chip, ichdev->substream->runtime); 26468c2ecf20Sopenharmony_ci iputdword(chip, port + ICH_REG_OFF_BDBAR, ichdev->bdbar_addr); 26478c2ecf20Sopenharmony_ci iputbyte(chip, port + ICH_REG_OFF_LVI, ichdev->lvi); 26488c2ecf20Sopenharmony_ci iputbyte(chip, port + ICH_REG_OFF_CIV, ichdev->civ); 26498c2ecf20Sopenharmony_ci iputbyte(chip, port + ichdev->roff_sr, ICH_FIFOE | ICH_BCIS | ICH_LVBCI); 26508c2ecf20Sopenharmony_ci } 26518c2ecf20Sopenharmony_ci 26528c2ecf20Sopenharmony_ci snd_power_change_state(card, SNDRV_CTL_POWER_D0); 26538c2ecf20Sopenharmony_ci return 0; 26548c2ecf20Sopenharmony_ci} 26558c2ecf20Sopenharmony_ci 26568c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(intel8x0_pm, intel8x0_suspend, intel8x0_resume); 26578c2ecf20Sopenharmony_ci#define INTEL8X0_PM_OPS &intel8x0_pm 26588c2ecf20Sopenharmony_ci#else 26598c2ecf20Sopenharmony_ci#define INTEL8X0_PM_OPS NULL 26608c2ecf20Sopenharmony_ci#endif /* CONFIG_PM_SLEEP */ 26618c2ecf20Sopenharmony_ci 26628c2ecf20Sopenharmony_ci#define INTEL8X0_TESTBUF_SIZE 32768 /* enough large for one shot */ 26638c2ecf20Sopenharmony_ci 26648c2ecf20Sopenharmony_cistatic void intel8x0_measure_ac97_clock(struct intel8x0 *chip) 26658c2ecf20Sopenharmony_ci{ 26668c2ecf20Sopenharmony_ci struct snd_pcm_substream *subs; 26678c2ecf20Sopenharmony_ci struct ichdev *ichdev; 26688c2ecf20Sopenharmony_ci unsigned long port; 26698c2ecf20Sopenharmony_ci unsigned long pos, pos1, t; 26708c2ecf20Sopenharmony_ci int civ, timeout = 1000, attempt = 1; 26718c2ecf20Sopenharmony_ci ktime_t start_time, stop_time; 26728c2ecf20Sopenharmony_ci 26738c2ecf20Sopenharmony_ci if (chip->ac97_bus->clock != 48000) 26748c2ecf20Sopenharmony_ci return; /* specified in module option */ 26758c2ecf20Sopenharmony_ci 26768c2ecf20Sopenharmony_ci __again: 26778c2ecf20Sopenharmony_ci subs = chip->pcm[0]->streams[0].substream; 26788c2ecf20Sopenharmony_ci if (! subs || subs->dma_buffer.bytes < INTEL8X0_TESTBUF_SIZE) { 26798c2ecf20Sopenharmony_ci dev_warn(chip->card->dev, 26808c2ecf20Sopenharmony_ci "no playback buffer allocated - aborting measure ac97 clock\n"); 26818c2ecf20Sopenharmony_ci return; 26828c2ecf20Sopenharmony_ci } 26838c2ecf20Sopenharmony_ci ichdev = &chip->ichd[ICHD_PCMOUT]; 26848c2ecf20Sopenharmony_ci ichdev->physbuf = subs->dma_buffer.addr; 26858c2ecf20Sopenharmony_ci ichdev->size = ichdev->fragsize = INTEL8X0_TESTBUF_SIZE; 26868c2ecf20Sopenharmony_ci ichdev->substream = NULL; /* don't process interrupts */ 26878c2ecf20Sopenharmony_ci 26888c2ecf20Sopenharmony_ci /* set rate */ 26898c2ecf20Sopenharmony_ci if (snd_ac97_set_rate(chip->ac97[0], AC97_PCM_FRONT_DAC_RATE, 48000) < 0) { 26908c2ecf20Sopenharmony_ci dev_err(chip->card->dev, "cannot set ac97 rate: clock = %d\n", 26918c2ecf20Sopenharmony_ci chip->ac97_bus->clock); 26928c2ecf20Sopenharmony_ci return; 26938c2ecf20Sopenharmony_ci } 26948c2ecf20Sopenharmony_ci snd_intel8x0_setup_periods(chip, ichdev); 26958c2ecf20Sopenharmony_ci port = ichdev->reg_offset; 26968c2ecf20Sopenharmony_ci spin_lock_irq(&chip->reg_lock); 26978c2ecf20Sopenharmony_ci chip->in_measurement = 1; 26988c2ecf20Sopenharmony_ci /* trigger */ 26998c2ecf20Sopenharmony_ci if (chip->device_type != DEVICE_ALI) 27008c2ecf20Sopenharmony_ci iputbyte(chip, port + ICH_REG_OFF_CR, ICH_IOCE | ICH_STARTBM); 27018c2ecf20Sopenharmony_ci else { 27028c2ecf20Sopenharmony_ci iputbyte(chip, port + ICH_REG_OFF_CR, ICH_IOCE); 27038c2ecf20Sopenharmony_ci iputdword(chip, ICHREG(ALI_DMACR), 1 << ichdev->ali_slot); 27048c2ecf20Sopenharmony_ci } 27058c2ecf20Sopenharmony_ci start_time = ktime_get(); 27068c2ecf20Sopenharmony_ci spin_unlock_irq(&chip->reg_lock); 27078c2ecf20Sopenharmony_ci msleep(50); 27088c2ecf20Sopenharmony_ci spin_lock_irq(&chip->reg_lock); 27098c2ecf20Sopenharmony_ci /* check the position */ 27108c2ecf20Sopenharmony_ci do { 27118c2ecf20Sopenharmony_ci civ = igetbyte(chip, ichdev->reg_offset + ICH_REG_OFF_CIV); 27128c2ecf20Sopenharmony_ci pos1 = igetword(chip, ichdev->reg_offset + ichdev->roff_picb); 27138c2ecf20Sopenharmony_ci if (pos1 == 0) { 27148c2ecf20Sopenharmony_ci udelay(10); 27158c2ecf20Sopenharmony_ci continue; 27168c2ecf20Sopenharmony_ci } 27178c2ecf20Sopenharmony_ci if (civ == igetbyte(chip, ichdev->reg_offset + ICH_REG_OFF_CIV) && 27188c2ecf20Sopenharmony_ci pos1 == igetword(chip, ichdev->reg_offset + ichdev->roff_picb)) 27198c2ecf20Sopenharmony_ci break; 27208c2ecf20Sopenharmony_ci } while (timeout--); 27218c2ecf20Sopenharmony_ci if (pos1 == 0) { /* oops, this value is not reliable */ 27228c2ecf20Sopenharmony_ci pos = 0; 27238c2ecf20Sopenharmony_ci } else { 27248c2ecf20Sopenharmony_ci pos = ichdev->fragsize1; 27258c2ecf20Sopenharmony_ci pos -= pos1 << ichdev->pos_shift; 27268c2ecf20Sopenharmony_ci pos += ichdev->position; 27278c2ecf20Sopenharmony_ci } 27288c2ecf20Sopenharmony_ci chip->in_measurement = 0; 27298c2ecf20Sopenharmony_ci stop_time = ktime_get(); 27308c2ecf20Sopenharmony_ci /* stop */ 27318c2ecf20Sopenharmony_ci if (chip->device_type == DEVICE_ALI) { 27328c2ecf20Sopenharmony_ci iputdword(chip, ICHREG(ALI_DMACR), 1 << (ichdev->ali_slot + 16)); 27338c2ecf20Sopenharmony_ci iputbyte(chip, port + ICH_REG_OFF_CR, 0); 27348c2ecf20Sopenharmony_ci while (igetbyte(chip, port + ICH_REG_OFF_CR)) 27358c2ecf20Sopenharmony_ci ; 27368c2ecf20Sopenharmony_ci } else { 27378c2ecf20Sopenharmony_ci iputbyte(chip, port + ICH_REG_OFF_CR, 0); 27388c2ecf20Sopenharmony_ci while (!(igetbyte(chip, port + ichdev->roff_sr) & ICH_DCH)) 27398c2ecf20Sopenharmony_ci ; 27408c2ecf20Sopenharmony_ci } 27418c2ecf20Sopenharmony_ci iputbyte(chip, port + ICH_REG_OFF_CR, ICH_RESETREGS); 27428c2ecf20Sopenharmony_ci spin_unlock_irq(&chip->reg_lock); 27438c2ecf20Sopenharmony_ci 27448c2ecf20Sopenharmony_ci if (pos == 0) { 27458c2ecf20Sopenharmony_ci dev_err(chip->card->dev, 27468c2ecf20Sopenharmony_ci "measure - unreliable DMA position..\n"); 27478c2ecf20Sopenharmony_ci __retry: 27488c2ecf20Sopenharmony_ci if (attempt < 3) { 27498c2ecf20Sopenharmony_ci msleep(300); 27508c2ecf20Sopenharmony_ci attempt++; 27518c2ecf20Sopenharmony_ci goto __again; 27528c2ecf20Sopenharmony_ci } 27538c2ecf20Sopenharmony_ci goto __end; 27548c2ecf20Sopenharmony_ci } 27558c2ecf20Sopenharmony_ci 27568c2ecf20Sopenharmony_ci pos /= 4; 27578c2ecf20Sopenharmony_ci t = ktime_us_delta(stop_time, start_time); 27588c2ecf20Sopenharmony_ci dev_info(chip->card->dev, 27598c2ecf20Sopenharmony_ci "%s: measured %lu usecs (%lu samples)\n", __func__, t, pos); 27608c2ecf20Sopenharmony_ci if (t == 0) { 27618c2ecf20Sopenharmony_ci dev_err(chip->card->dev, "?? calculation error..\n"); 27628c2ecf20Sopenharmony_ci goto __retry; 27638c2ecf20Sopenharmony_ci } 27648c2ecf20Sopenharmony_ci pos *= 1000; 27658c2ecf20Sopenharmony_ci pos = (pos / t) * 1000 + ((pos % t) * 1000) / t; 27668c2ecf20Sopenharmony_ci if (pos < 40000 || pos >= 60000) { 27678c2ecf20Sopenharmony_ci /* abnormal value. hw problem? */ 27688c2ecf20Sopenharmony_ci dev_info(chip->card->dev, "measured clock %ld rejected\n", pos); 27698c2ecf20Sopenharmony_ci goto __retry; 27708c2ecf20Sopenharmony_ci } else if (pos > 40500 && pos < 41500) 27718c2ecf20Sopenharmony_ci /* first exception - 41000Hz reference clock */ 27728c2ecf20Sopenharmony_ci chip->ac97_bus->clock = 41000; 27738c2ecf20Sopenharmony_ci else if (pos > 43600 && pos < 44600) 27748c2ecf20Sopenharmony_ci /* second exception - 44100HZ reference clock */ 27758c2ecf20Sopenharmony_ci chip->ac97_bus->clock = 44100; 27768c2ecf20Sopenharmony_ci else if (pos < 47500 || pos > 48500) 27778c2ecf20Sopenharmony_ci /* not 48000Hz, tuning the clock.. */ 27788c2ecf20Sopenharmony_ci chip->ac97_bus->clock = (chip->ac97_bus->clock * 48000) / pos; 27798c2ecf20Sopenharmony_ci __end: 27808c2ecf20Sopenharmony_ci dev_info(chip->card->dev, "clocking to %d\n", chip->ac97_bus->clock); 27818c2ecf20Sopenharmony_ci snd_ac97_update_power(chip->ac97[0], AC97_PCM_FRONT_DAC_RATE, 0); 27828c2ecf20Sopenharmony_ci} 27838c2ecf20Sopenharmony_ci 27848c2ecf20Sopenharmony_cistatic const struct snd_pci_quirk intel8x0_clock_list[] = { 27858c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x0e11, 0x008a, "AD1885", 41000), 27868c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x1014, 0x0581, "AD1981B", 48000), 27878c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x1028, 0x00be, "AD1885", 44100), 27888c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x1028, 0x0177, "AD1980", 48000), 27898c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x1028, 0x01ad, "AD1981B", 48000), 27908c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x1043, 0x80f3, "AD1985", 48000), 27918c2ecf20Sopenharmony_ci { } /* terminator */ 27928c2ecf20Sopenharmony_ci}; 27938c2ecf20Sopenharmony_ci 27948c2ecf20Sopenharmony_cistatic int intel8x0_in_clock_list(struct intel8x0 *chip) 27958c2ecf20Sopenharmony_ci{ 27968c2ecf20Sopenharmony_ci struct pci_dev *pci = chip->pci; 27978c2ecf20Sopenharmony_ci const struct snd_pci_quirk *wl; 27988c2ecf20Sopenharmony_ci 27998c2ecf20Sopenharmony_ci wl = snd_pci_quirk_lookup(pci, intel8x0_clock_list); 28008c2ecf20Sopenharmony_ci if (!wl) 28018c2ecf20Sopenharmony_ci return 0; 28028c2ecf20Sopenharmony_ci dev_info(chip->card->dev, "allow list rate for %04x:%04x is %i\n", 28038c2ecf20Sopenharmony_ci pci->subsystem_vendor, pci->subsystem_device, wl->value); 28048c2ecf20Sopenharmony_ci chip->ac97_bus->clock = wl->value; 28058c2ecf20Sopenharmony_ci return 1; 28068c2ecf20Sopenharmony_ci} 28078c2ecf20Sopenharmony_ci 28088c2ecf20Sopenharmony_cistatic void snd_intel8x0_proc_read(struct snd_info_entry * entry, 28098c2ecf20Sopenharmony_ci struct snd_info_buffer *buffer) 28108c2ecf20Sopenharmony_ci{ 28118c2ecf20Sopenharmony_ci struct intel8x0 *chip = entry->private_data; 28128c2ecf20Sopenharmony_ci unsigned int tmp; 28138c2ecf20Sopenharmony_ci 28148c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Intel8x0\n\n"); 28158c2ecf20Sopenharmony_ci if (chip->device_type == DEVICE_ALI) 28168c2ecf20Sopenharmony_ci return; 28178c2ecf20Sopenharmony_ci tmp = igetdword(chip, ICHREG(GLOB_STA)); 28188c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Global control : 0x%08x\n", igetdword(chip, ICHREG(GLOB_CNT))); 28198c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Global status : 0x%08x\n", tmp); 28208c2ecf20Sopenharmony_ci if (chip->device_type == DEVICE_INTEL_ICH4) 28218c2ecf20Sopenharmony_ci snd_iprintf(buffer, "SDM : 0x%08x\n", igetdword(chip, ICHREG(SDM))); 28228c2ecf20Sopenharmony_ci snd_iprintf(buffer, "AC'97 codecs ready :"); 28238c2ecf20Sopenharmony_ci if (tmp & chip->codec_isr_bits) { 28248c2ecf20Sopenharmony_ci int i; 28258c2ecf20Sopenharmony_ci static const char *codecs[3] = { 28268c2ecf20Sopenharmony_ci "primary", "secondary", "tertiary" 28278c2ecf20Sopenharmony_ci }; 28288c2ecf20Sopenharmony_ci for (i = 0; i < chip->max_codecs; i++) 28298c2ecf20Sopenharmony_ci if (tmp & chip->codec_bit[i]) 28308c2ecf20Sopenharmony_ci snd_iprintf(buffer, " %s", codecs[i]); 28318c2ecf20Sopenharmony_ci } else 28328c2ecf20Sopenharmony_ci snd_iprintf(buffer, " none"); 28338c2ecf20Sopenharmony_ci snd_iprintf(buffer, "\n"); 28348c2ecf20Sopenharmony_ci if (chip->device_type == DEVICE_INTEL_ICH4 || 28358c2ecf20Sopenharmony_ci chip->device_type == DEVICE_SIS) 28368c2ecf20Sopenharmony_ci snd_iprintf(buffer, "AC'97 codecs SDIN : %i %i %i\n", 28378c2ecf20Sopenharmony_ci chip->ac97_sdin[0], 28388c2ecf20Sopenharmony_ci chip->ac97_sdin[1], 28398c2ecf20Sopenharmony_ci chip->ac97_sdin[2]); 28408c2ecf20Sopenharmony_ci} 28418c2ecf20Sopenharmony_ci 28428c2ecf20Sopenharmony_cistatic void snd_intel8x0_proc_init(struct intel8x0 *chip) 28438c2ecf20Sopenharmony_ci{ 28448c2ecf20Sopenharmony_ci snd_card_ro_proc_new(chip->card, "intel8x0", chip, 28458c2ecf20Sopenharmony_ci snd_intel8x0_proc_read); 28468c2ecf20Sopenharmony_ci} 28478c2ecf20Sopenharmony_ci 28488c2ecf20Sopenharmony_cistatic int snd_intel8x0_dev_free(struct snd_device *device) 28498c2ecf20Sopenharmony_ci{ 28508c2ecf20Sopenharmony_ci struct intel8x0 *chip = device->device_data; 28518c2ecf20Sopenharmony_ci return snd_intel8x0_free(chip); 28528c2ecf20Sopenharmony_ci} 28538c2ecf20Sopenharmony_ci 28548c2ecf20Sopenharmony_cistruct ich_reg_info { 28558c2ecf20Sopenharmony_ci unsigned int int_sta_mask; 28568c2ecf20Sopenharmony_ci unsigned int offset; 28578c2ecf20Sopenharmony_ci}; 28588c2ecf20Sopenharmony_ci 28598c2ecf20Sopenharmony_cistatic const unsigned int ich_codec_bits[3] = { 28608c2ecf20Sopenharmony_ci ICH_PCR, ICH_SCR, ICH_TCR 28618c2ecf20Sopenharmony_ci}; 28628c2ecf20Sopenharmony_cistatic const unsigned int sis_codec_bits[3] = { 28638c2ecf20Sopenharmony_ci ICH_PCR, ICH_SCR, ICH_SIS_TCR 28648c2ecf20Sopenharmony_ci}; 28658c2ecf20Sopenharmony_ci 28668c2ecf20Sopenharmony_cistatic int snd_intel8x0_inside_vm(struct pci_dev *pci) 28678c2ecf20Sopenharmony_ci{ 28688c2ecf20Sopenharmony_ci int result = inside_vm; 28698c2ecf20Sopenharmony_ci char *msg = NULL; 28708c2ecf20Sopenharmony_ci 28718c2ecf20Sopenharmony_ci /* check module parameter first (override detection) */ 28728c2ecf20Sopenharmony_ci if (result >= 0) { 28738c2ecf20Sopenharmony_ci msg = result ? "enable (forced) VM" : "disable (forced) VM"; 28748c2ecf20Sopenharmony_ci goto fini; 28758c2ecf20Sopenharmony_ci } 28768c2ecf20Sopenharmony_ci 28778c2ecf20Sopenharmony_ci /* check for known (emulated) devices */ 28788c2ecf20Sopenharmony_ci result = 0; 28798c2ecf20Sopenharmony_ci if (pci->subsystem_vendor == PCI_SUBVENDOR_ID_REDHAT_QUMRANET && 28808c2ecf20Sopenharmony_ci pci->subsystem_device == PCI_SUBDEVICE_ID_QEMU) { 28818c2ecf20Sopenharmony_ci /* KVM emulated sound, PCI SSID: 1af4:1100 */ 28828c2ecf20Sopenharmony_ci msg = "enable KVM"; 28838c2ecf20Sopenharmony_ci result = 1; 28848c2ecf20Sopenharmony_ci } else if (pci->subsystem_vendor == 0x1ab8) { 28858c2ecf20Sopenharmony_ci /* Parallels VM emulated sound, PCI SSID: 1ab8:xxxx */ 28868c2ecf20Sopenharmony_ci msg = "enable Parallels VM"; 28878c2ecf20Sopenharmony_ci result = 1; 28888c2ecf20Sopenharmony_ci } 28898c2ecf20Sopenharmony_ci 28908c2ecf20Sopenharmony_cifini: 28918c2ecf20Sopenharmony_ci if (msg != NULL) 28928c2ecf20Sopenharmony_ci dev_info(&pci->dev, "%s optimization\n", msg); 28938c2ecf20Sopenharmony_ci 28948c2ecf20Sopenharmony_ci return result; 28958c2ecf20Sopenharmony_ci} 28968c2ecf20Sopenharmony_ci 28978c2ecf20Sopenharmony_cistatic int snd_intel8x0_create(struct snd_card *card, 28988c2ecf20Sopenharmony_ci struct pci_dev *pci, 28998c2ecf20Sopenharmony_ci unsigned long device_type, 29008c2ecf20Sopenharmony_ci struct intel8x0 **r_intel8x0) 29018c2ecf20Sopenharmony_ci{ 29028c2ecf20Sopenharmony_ci struct intel8x0 *chip; 29038c2ecf20Sopenharmony_ci int err; 29048c2ecf20Sopenharmony_ci unsigned int i; 29058c2ecf20Sopenharmony_ci unsigned int int_sta_masks; 29068c2ecf20Sopenharmony_ci struct ichdev *ichdev; 29078c2ecf20Sopenharmony_ci static const struct snd_device_ops ops = { 29088c2ecf20Sopenharmony_ci .dev_free = snd_intel8x0_dev_free, 29098c2ecf20Sopenharmony_ci }; 29108c2ecf20Sopenharmony_ci 29118c2ecf20Sopenharmony_ci static const unsigned int bdbars[] = { 29128c2ecf20Sopenharmony_ci 3, /* DEVICE_INTEL */ 29138c2ecf20Sopenharmony_ci 6, /* DEVICE_INTEL_ICH4 */ 29148c2ecf20Sopenharmony_ci 3, /* DEVICE_SIS */ 29158c2ecf20Sopenharmony_ci 6, /* DEVICE_ALI */ 29168c2ecf20Sopenharmony_ci 4, /* DEVICE_NFORCE */ 29178c2ecf20Sopenharmony_ci }; 29188c2ecf20Sopenharmony_ci static const struct ich_reg_info intel_regs[6] = { 29198c2ecf20Sopenharmony_ci { ICH_PIINT, 0 }, 29208c2ecf20Sopenharmony_ci { ICH_POINT, 0x10 }, 29218c2ecf20Sopenharmony_ci { ICH_MCINT, 0x20 }, 29228c2ecf20Sopenharmony_ci { ICH_M2INT, 0x40 }, 29238c2ecf20Sopenharmony_ci { ICH_P2INT, 0x50 }, 29248c2ecf20Sopenharmony_ci { ICH_SPINT, 0x60 }, 29258c2ecf20Sopenharmony_ci }; 29268c2ecf20Sopenharmony_ci static const struct ich_reg_info nforce_regs[4] = { 29278c2ecf20Sopenharmony_ci { ICH_PIINT, 0 }, 29288c2ecf20Sopenharmony_ci { ICH_POINT, 0x10 }, 29298c2ecf20Sopenharmony_ci { ICH_MCINT, 0x20 }, 29308c2ecf20Sopenharmony_ci { ICH_NVSPINT, 0x70 }, 29318c2ecf20Sopenharmony_ci }; 29328c2ecf20Sopenharmony_ci static const struct ich_reg_info ali_regs[6] = { 29338c2ecf20Sopenharmony_ci { ALI_INT_PCMIN, 0x40 }, 29348c2ecf20Sopenharmony_ci { ALI_INT_PCMOUT, 0x50 }, 29358c2ecf20Sopenharmony_ci { ALI_INT_MICIN, 0x60 }, 29368c2ecf20Sopenharmony_ci { ALI_INT_CODECSPDIFOUT, 0x70 }, 29378c2ecf20Sopenharmony_ci { ALI_INT_SPDIFIN, 0xa0 }, 29388c2ecf20Sopenharmony_ci { ALI_INT_SPDIFOUT, 0xb0 }, 29398c2ecf20Sopenharmony_ci }; 29408c2ecf20Sopenharmony_ci const struct ich_reg_info *tbl; 29418c2ecf20Sopenharmony_ci 29428c2ecf20Sopenharmony_ci *r_intel8x0 = NULL; 29438c2ecf20Sopenharmony_ci 29448c2ecf20Sopenharmony_ci if ((err = pci_enable_device(pci)) < 0) 29458c2ecf20Sopenharmony_ci return err; 29468c2ecf20Sopenharmony_ci 29478c2ecf20Sopenharmony_ci chip = kzalloc(sizeof(*chip), GFP_KERNEL); 29488c2ecf20Sopenharmony_ci if (chip == NULL) { 29498c2ecf20Sopenharmony_ci pci_disable_device(pci); 29508c2ecf20Sopenharmony_ci return -ENOMEM; 29518c2ecf20Sopenharmony_ci } 29528c2ecf20Sopenharmony_ci spin_lock_init(&chip->reg_lock); 29538c2ecf20Sopenharmony_ci chip->device_type = device_type; 29548c2ecf20Sopenharmony_ci chip->card = card; 29558c2ecf20Sopenharmony_ci chip->pci = pci; 29568c2ecf20Sopenharmony_ci chip->irq = -1; 29578c2ecf20Sopenharmony_ci 29588c2ecf20Sopenharmony_ci /* module parameters */ 29598c2ecf20Sopenharmony_ci chip->buggy_irq = buggy_irq; 29608c2ecf20Sopenharmony_ci chip->buggy_semaphore = buggy_semaphore; 29618c2ecf20Sopenharmony_ci if (xbox) 29628c2ecf20Sopenharmony_ci chip->xbox = 1; 29638c2ecf20Sopenharmony_ci 29648c2ecf20Sopenharmony_ci chip->inside_vm = snd_intel8x0_inside_vm(pci); 29658c2ecf20Sopenharmony_ci 29668c2ecf20Sopenharmony_ci /* 29678c2ecf20Sopenharmony_ci * Intel 82443MX running a 100MHz processor system bus has a hardware 29688c2ecf20Sopenharmony_ci * bug, which aborts PCI busmaster for audio transfer. A workaround 29698c2ecf20Sopenharmony_ci * is to set the pages as non-cached. For details, see the errata in 29708c2ecf20Sopenharmony_ci * http://download.intel.com/design/chipsets/specupdt/24505108.pdf 29718c2ecf20Sopenharmony_ci */ 29728c2ecf20Sopenharmony_ci if (pci->vendor == PCI_VENDOR_ID_INTEL && 29738c2ecf20Sopenharmony_ci pci->device == PCI_DEVICE_ID_INTEL_440MX) 29748c2ecf20Sopenharmony_ci chip->fix_nocache = 1; /* enable workaround */ 29758c2ecf20Sopenharmony_ci 29768c2ecf20Sopenharmony_ci if ((err = pci_request_regions(pci, card->shortname)) < 0) { 29778c2ecf20Sopenharmony_ci kfree(chip); 29788c2ecf20Sopenharmony_ci pci_disable_device(pci); 29798c2ecf20Sopenharmony_ci return err; 29808c2ecf20Sopenharmony_ci } 29818c2ecf20Sopenharmony_ci 29828c2ecf20Sopenharmony_ci if (device_type == DEVICE_ALI) { 29838c2ecf20Sopenharmony_ci /* ALI5455 has no ac97 region */ 29848c2ecf20Sopenharmony_ci chip->bmaddr = pci_iomap(pci, 0, 0); 29858c2ecf20Sopenharmony_ci goto port_inited; 29868c2ecf20Sopenharmony_ci } 29878c2ecf20Sopenharmony_ci 29888c2ecf20Sopenharmony_ci if (pci_resource_flags(pci, 2) & IORESOURCE_MEM) /* ICH4 and Nforce */ 29898c2ecf20Sopenharmony_ci chip->addr = pci_iomap(pci, 2, 0); 29908c2ecf20Sopenharmony_ci else 29918c2ecf20Sopenharmony_ci chip->addr = pci_iomap(pci, 0, 0); 29928c2ecf20Sopenharmony_ci if (!chip->addr) { 29938c2ecf20Sopenharmony_ci dev_err(card->dev, "AC'97 space ioremap problem\n"); 29948c2ecf20Sopenharmony_ci snd_intel8x0_free(chip); 29958c2ecf20Sopenharmony_ci return -EIO; 29968c2ecf20Sopenharmony_ci } 29978c2ecf20Sopenharmony_ci if (pci_resource_flags(pci, 3) & IORESOURCE_MEM) /* ICH4 */ 29988c2ecf20Sopenharmony_ci chip->bmaddr = pci_iomap(pci, 3, 0); 29998c2ecf20Sopenharmony_ci else 30008c2ecf20Sopenharmony_ci chip->bmaddr = pci_iomap(pci, 1, 0); 30018c2ecf20Sopenharmony_ci 30028c2ecf20Sopenharmony_ci port_inited: 30038c2ecf20Sopenharmony_ci if (!chip->bmaddr) { 30048c2ecf20Sopenharmony_ci dev_err(card->dev, "Controller space ioremap problem\n"); 30058c2ecf20Sopenharmony_ci snd_intel8x0_free(chip); 30068c2ecf20Sopenharmony_ci return -EIO; 30078c2ecf20Sopenharmony_ci } 30088c2ecf20Sopenharmony_ci chip->bdbars_count = bdbars[device_type]; 30098c2ecf20Sopenharmony_ci 30108c2ecf20Sopenharmony_ci /* initialize offsets */ 30118c2ecf20Sopenharmony_ci switch (device_type) { 30128c2ecf20Sopenharmony_ci case DEVICE_NFORCE: 30138c2ecf20Sopenharmony_ci tbl = nforce_regs; 30148c2ecf20Sopenharmony_ci break; 30158c2ecf20Sopenharmony_ci case DEVICE_ALI: 30168c2ecf20Sopenharmony_ci tbl = ali_regs; 30178c2ecf20Sopenharmony_ci break; 30188c2ecf20Sopenharmony_ci default: 30198c2ecf20Sopenharmony_ci tbl = intel_regs; 30208c2ecf20Sopenharmony_ci break; 30218c2ecf20Sopenharmony_ci } 30228c2ecf20Sopenharmony_ci for (i = 0; i < chip->bdbars_count; i++) { 30238c2ecf20Sopenharmony_ci ichdev = &chip->ichd[i]; 30248c2ecf20Sopenharmony_ci ichdev->ichd = i; 30258c2ecf20Sopenharmony_ci ichdev->reg_offset = tbl[i].offset; 30268c2ecf20Sopenharmony_ci ichdev->int_sta_mask = tbl[i].int_sta_mask; 30278c2ecf20Sopenharmony_ci if (device_type == DEVICE_SIS) { 30288c2ecf20Sopenharmony_ci /* SiS 7012 swaps the registers */ 30298c2ecf20Sopenharmony_ci ichdev->roff_sr = ICH_REG_OFF_PICB; 30308c2ecf20Sopenharmony_ci ichdev->roff_picb = ICH_REG_OFF_SR; 30318c2ecf20Sopenharmony_ci } else { 30328c2ecf20Sopenharmony_ci ichdev->roff_sr = ICH_REG_OFF_SR; 30338c2ecf20Sopenharmony_ci ichdev->roff_picb = ICH_REG_OFF_PICB; 30348c2ecf20Sopenharmony_ci } 30358c2ecf20Sopenharmony_ci if (device_type == DEVICE_ALI) 30368c2ecf20Sopenharmony_ci ichdev->ali_slot = (ichdev->reg_offset - 0x40) / 0x10; 30378c2ecf20Sopenharmony_ci /* SIS7012 handles the pcm data in bytes, others are in samples */ 30388c2ecf20Sopenharmony_ci ichdev->pos_shift = (device_type == DEVICE_SIS) ? 0 : 1; 30398c2ecf20Sopenharmony_ci } 30408c2ecf20Sopenharmony_ci 30418c2ecf20Sopenharmony_ci /* allocate buffer descriptor lists */ 30428c2ecf20Sopenharmony_ci /* the start of each lists must be aligned to 8 bytes */ 30438c2ecf20Sopenharmony_ci if (snd_dma_alloc_pages(intel8x0_dma_type(chip), &pci->dev, 30448c2ecf20Sopenharmony_ci chip->bdbars_count * sizeof(u32) * ICH_MAX_FRAGS * 2, 30458c2ecf20Sopenharmony_ci &chip->bdbars) < 0) { 30468c2ecf20Sopenharmony_ci snd_intel8x0_free(chip); 30478c2ecf20Sopenharmony_ci dev_err(card->dev, "cannot allocate buffer descriptors\n"); 30488c2ecf20Sopenharmony_ci return -ENOMEM; 30498c2ecf20Sopenharmony_ci } 30508c2ecf20Sopenharmony_ci /* tables must be aligned to 8 bytes here, but the kernel pages 30518c2ecf20Sopenharmony_ci are much bigger, so we don't care (on i386) */ 30528c2ecf20Sopenharmony_ci int_sta_masks = 0; 30538c2ecf20Sopenharmony_ci for (i = 0; i < chip->bdbars_count; i++) { 30548c2ecf20Sopenharmony_ci ichdev = &chip->ichd[i]; 30558c2ecf20Sopenharmony_ci ichdev->bdbar = ((__le32 *)chip->bdbars.area) + 30568c2ecf20Sopenharmony_ci (i * ICH_MAX_FRAGS * 2); 30578c2ecf20Sopenharmony_ci ichdev->bdbar_addr = chip->bdbars.addr + 30588c2ecf20Sopenharmony_ci (i * sizeof(u32) * ICH_MAX_FRAGS * 2); 30598c2ecf20Sopenharmony_ci int_sta_masks |= ichdev->int_sta_mask; 30608c2ecf20Sopenharmony_ci } 30618c2ecf20Sopenharmony_ci chip->int_sta_reg = device_type == DEVICE_ALI ? 30628c2ecf20Sopenharmony_ci ICH_REG_ALI_INTERRUPTSR : ICH_REG_GLOB_STA; 30638c2ecf20Sopenharmony_ci chip->int_sta_mask = int_sta_masks; 30648c2ecf20Sopenharmony_ci 30658c2ecf20Sopenharmony_ci pci_set_master(pci); 30668c2ecf20Sopenharmony_ci 30678c2ecf20Sopenharmony_ci switch(chip->device_type) { 30688c2ecf20Sopenharmony_ci case DEVICE_INTEL_ICH4: 30698c2ecf20Sopenharmony_ci /* ICH4 can have three codecs */ 30708c2ecf20Sopenharmony_ci chip->max_codecs = 3; 30718c2ecf20Sopenharmony_ci chip->codec_bit = ich_codec_bits; 30728c2ecf20Sopenharmony_ci chip->codec_ready_bits = ICH_PRI | ICH_SRI | ICH_TRI; 30738c2ecf20Sopenharmony_ci break; 30748c2ecf20Sopenharmony_ci case DEVICE_SIS: 30758c2ecf20Sopenharmony_ci /* recent SIS7012 can have three codecs */ 30768c2ecf20Sopenharmony_ci chip->max_codecs = 3; 30778c2ecf20Sopenharmony_ci chip->codec_bit = sis_codec_bits; 30788c2ecf20Sopenharmony_ci chip->codec_ready_bits = ICH_PRI | ICH_SRI | ICH_SIS_TRI; 30798c2ecf20Sopenharmony_ci break; 30808c2ecf20Sopenharmony_ci default: 30818c2ecf20Sopenharmony_ci /* others up to two codecs */ 30828c2ecf20Sopenharmony_ci chip->max_codecs = 2; 30838c2ecf20Sopenharmony_ci chip->codec_bit = ich_codec_bits; 30848c2ecf20Sopenharmony_ci chip->codec_ready_bits = ICH_PRI | ICH_SRI; 30858c2ecf20Sopenharmony_ci break; 30868c2ecf20Sopenharmony_ci } 30878c2ecf20Sopenharmony_ci for (i = 0; i < chip->max_codecs; i++) 30888c2ecf20Sopenharmony_ci chip->codec_isr_bits |= chip->codec_bit[i]; 30898c2ecf20Sopenharmony_ci 30908c2ecf20Sopenharmony_ci if ((err = snd_intel8x0_chip_init(chip, 1)) < 0) { 30918c2ecf20Sopenharmony_ci snd_intel8x0_free(chip); 30928c2ecf20Sopenharmony_ci return err; 30938c2ecf20Sopenharmony_ci } 30948c2ecf20Sopenharmony_ci 30958c2ecf20Sopenharmony_ci /* request irq after initializaing int_sta_mask, etc */ 30968c2ecf20Sopenharmony_ci if (request_irq(pci->irq, snd_intel8x0_interrupt, 30978c2ecf20Sopenharmony_ci IRQF_SHARED, KBUILD_MODNAME, chip)) { 30988c2ecf20Sopenharmony_ci dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq); 30998c2ecf20Sopenharmony_ci snd_intel8x0_free(chip); 31008c2ecf20Sopenharmony_ci return -EBUSY; 31018c2ecf20Sopenharmony_ci } 31028c2ecf20Sopenharmony_ci chip->irq = pci->irq; 31038c2ecf20Sopenharmony_ci card->sync_irq = chip->irq; 31048c2ecf20Sopenharmony_ci 31058c2ecf20Sopenharmony_ci if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { 31068c2ecf20Sopenharmony_ci snd_intel8x0_free(chip); 31078c2ecf20Sopenharmony_ci return err; 31088c2ecf20Sopenharmony_ci } 31098c2ecf20Sopenharmony_ci 31108c2ecf20Sopenharmony_ci *r_intel8x0 = chip; 31118c2ecf20Sopenharmony_ci return 0; 31128c2ecf20Sopenharmony_ci} 31138c2ecf20Sopenharmony_ci 31148c2ecf20Sopenharmony_cistatic struct shortname_table { 31158c2ecf20Sopenharmony_ci unsigned int id; 31168c2ecf20Sopenharmony_ci const char *s; 31178c2ecf20Sopenharmony_ci} shortnames[] = { 31188c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_INTEL_82801AA_5, "Intel 82801AA-ICH" }, 31198c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_INTEL_82801AB_5, "Intel 82901AB-ICH0" }, 31208c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_INTEL_82801BA_4, "Intel 82801BA-ICH2" }, 31218c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_INTEL_440MX, "Intel 440MX" }, 31228c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_INTEL_82801CA_5, "Intel 82801CA-ICH3" }, 31238c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_INTEL_82801DB_5, "Intel 82801DB-ICH4" }, 31248c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_INTEL_82801EB_5, "Intel ICH5" }, 31258c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_INTEL_ESB_5, "Intel 6300ESB" }, 31268c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_INTEL_ICH6_18, "Intel ICH6" }, 31278c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_INTEL_ICH7_20, "Intel ICH7" }, 31288c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_INTEL_ESB2_14, "Intel ESB2" }, 31298c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_SI_7012, "SiS SI7012" }, 31308c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_NVIDIA_MCP1_AUDIO, "NVidia nForce" }, 31318c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_NVIDIA_MCP2_AUDIO, "NVidia nForce2" }, 31328c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO, "NVidia nForce3" }, 31338c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_NVIDIA_CK8S_AUDIO, "NVidia CK8S" }, 31348c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_NVIDIA_CK804_AUDIO, "NVidia CK804" }, 31358c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_NVIDIA_CK8_AUDIO, "NVidia CK8" }, 31368c2ecf20Sopenharmony_ci { 0x003a, "NVidia MCP04" }, 31378c2ecf20Sopenharmony_ci { 0x746d, "AMD AMD8111" }, 31388c2ecf20Sopenharmony_ci { 0x7445, "AMD AMD768" }, 31398c2ecf20Sopenharmony_ci { 0x5455, "ALi M5455" }, 31408c2ecf20Sopenharmony_ci { 0, NULL }, 31418c2ecf20Sopenharmony_ci}; 31428c2ecf20Sopenharmony_ci 31438c2ecf20Sopenharmony_cistatic const struct snd_pci_quirk spdif_aclink_defaults[] = { 31448c2ecf20Sopenharmony_ci SND_PCI_QUIRK(0x147b, 0x1c1a, "ASUS KN8", 1), 31458c2ecf20Sopenharmony_ci { } /* end */ 31468c2ecf20Sopenharmony_ci}; 31478c2ecf20Sopenharmony_ci 31488c2ecf20Sopenharmony_ci/* look up allow/deny list for SPDIF over ac-link */ 31498c2ecf20Sopenharmony_cistatic int check_default_spdif_aclink(struct pci_dev *pci) 31508c2ecf20Sopenharmony_ci{ 31518c2ecf20Sopenharmony_ci const struct snd_pci_quirk *w; 31528c2ecf20Sopenharmony_ci 31538c2ecf20Sopenharmony_ci w = snd_pci_quirk_lookup(pci, spdif_aclink_defaults); 31548c2ecf20Sopenharmony_ci if (w) { 31558c2ecf20Sopenharmony_ci if (w->value) 31568c2ecf20Sopenharmony_ci dev_dbg(&pci->dev, 31578c2ecf20Sopenharmony_ci "Using SPDIF over AC-Link for %s\n", 31588c2ecf20Sopenharmony_ci snd_pci_quirk_name(w)); 31598c2ecf20Sopenharmony_ci else 31608c2ecf20Sopenharmony_ci dev_dbg(&pci->dev, 31618c2ecf20Sopenharmony_ci "Using integrated SPDIF DMA for %s\n", 31628c2ecf20Sopenharmony_ci snd_pci_quirk_name(w)); 31638c2ecf20Sopenharmony_ci return w->value; 31648c2ecf20Sopenharmony_ci } 31658c2ecf20Sopenharmony_ci return 0; 31668c2ecf20Sopenharmony_ci} 31678c2ecf20Sopenharmony_ci 31688c2ecf20Sopenharmony_cistatic int snd_intel8x0_probe(struct pci_dev *pci, 31698c2ecf20Sopenharmony_ci const struct pci_device_id *pci_id) 31708c2ecf20Sopenharmony_ci{ 31718c2ecf20Sopenharmony_ci struct snd_card *card; 31728c2ecf20Sopenharmony_ci struct intel8x0 *chip; 31738c2ecf20Sopenharmony_ci int err; 31748c2ecf20Sopenharmony_ci struct shortname_table *name; 31758c2ecf20Sopenharmony_ci 31768c2ecf20Sopenharmony_ci err = snd_card_new(&pci->dev, index, id, THIS_MODULE, 0, &card); 31778c2ecf20Sopenharmony_ci if (err < 0) 31788c2ecf20Sopenharmony_ci return err; 31798c2ecf20Sopenharmony_ci 31808c2ecf20Sopenharmony_ci if (spdif_aclink < 0) 31818c2ecf20Sopenharmony_ci spdif_aclink = check_default_spdif_aclink(pci); 31828c2ecf20Sopenharmony_ci 31838c2ecf20Sopenharmony_ci strcpy(card->driver, "ICH"); 31848c2ecf20Sopenharmony_ci if (!spdif_aclink) { 31858c2ecf20Sopenharmony_ci switch (pci_id->driver_data) { 31868c2ecf20Sopenharmony_ci case DEVICE_NFORCE: 31878c2ecf20Sopenharmony_ci strcpy(card->driver, "NFORCE"); 31888c2ecf20Sopenharmony_ci break; 31898c2ecf20Sopenharmony_ci case DEVICE_INTEL_ICH4: 31908c2ecf20Sopenharmony_ci strcpy(card->driver, "ICH4"); 31918c2ecf20Sopenharmony_ci } 31928c2ecf20Sopenharmony_ci } 31938c2ecf20Sopenharmony_ci 31948c2ecf20Sopenharmony_ci strcpy(card->shortname, "Intel ICH"); 31958c2ecf20Sopenharmony_ci for (name = shortnames; name->id; name++) { 31968c2ecf20Sopenharmony_ci if (pci->device == name->id) { 31978c2ecf20Sopenharmony_ci strcpy(card->shortname, name->s); 31988c2ecf20Sopenharmony_ci break; 31998c2ecf20Sopenharmony_ci } 32008c2ecf20Sopenharmony_ci } 32018c2ecf20Sopenharmony_ci 32028c2ecf20Sopenharmony_ci if (buggy_irq < 0) { 32038c2ecf20Sopenharmony_ci /* some Nforce[2] and ICH boards have problems with IRQ handling. 32048c2ecf20Sopenharmony_ci * Needs to return IRQ_HANDLED for unknown irqs. 32058c2ecf20Sopenharmony_ci */ 32068c2ecf20Sopenharmony_ci if (pci_id->driver_data == DEVICE_NFORCE) 32078c2ecf20Sopenharmony_ci buggy_irq = 1; 32088c2ecf20Sopenharmony_ci else 32098c2ecf20Sopenharmony_ci buggy_irq = 0; 32108c2ecf20Sopenharmony_ci } 32118c2ecf20Sopenharmony_ci 32128c2ecf20Sopenharmony_ci if ((err = snd_intel8x0_create(card, pci, pci_id->driver_data, 32138c2ecf20Sopenharmony_ci &chip)) < 0) { 32148c2ecf20Sopenharmony_ci snd_card_free(card); 32158c2ecf20Sopenharmony_ci return err; 32168c2ecf20Sopenharmony_ci } 32178c2ecf20Sopenharmony_ci card->private_data = chip; 32188c2ecf20Sopenharmony_ci 32198c2ecf20Sopenharmony_ci if ((err = snd_intel8x0_mixer(chip, ac97_clock, ac97_quirk)) < 0) { 32208c2ecf20Sopenharmony_ci snd_card_free(card); 32218c2ecf20Sopenharmony_ci return err; 32228c2ecf20Sopenharmony_ci } 32238c2ecf20Sopenharmony_ci if ((err = snd_intel8x0_pcm(chip)) < 0) { 32248c2ecf20Sopenharmony_ci snd_card_free(card); 32258c2ecf20Sopenharmony_ci return err; 32268c2ecf20Sopenharmony_ci } 32278c2ecf20Sopenharmony_ci 32288c2ecf20Sopenharmony_ci snd_intel8x0_proc_init(chip); 32298c2ecf20Sopenharmony_ci 32308c2ecf20Sopenharmony_ci snprintf(card->longname, sizeof(card->longname), 32318c2ecf20Sopenharmony_ci "%s with %s at irq %i", card->shortname, 32328c2ecf20Sopenharmony_ci snd_ac97_get_short_name(chip->ac97[0]), chip->irq); 32338c2ecf20Sopenharmony_ci 32348c2ecf20Sopenharmony_ci if (ac97_clock == 0 || ac97_clock == 1) { 32358c2ecf20Sopenharmony_ci if (ac97_clock == 0) { 32368c2ecf20Sopenharmony_ci if (intel8x0_in_clock_list(chip) == 0) 32378c2ecf20Sopenharmony_ci intel8x0_measure_ac97_clock(chip); 32388c2ecf20Sopenharmony_ci } else { 32398c2ecf20Sopenharmony_ci intel8x0_measure_ac97_clock(chip); 32408c2ecf20Sopenharmony_ci } 32418c2ecf20Sopenharmony_ci } 32428c2ecf20Sopenharmony_ci 32438c2ecf20Sopenharmony_ci if ((err = snd_card_register(card)) < 0) { 32448c2ecf20Sopenharmony_ci snd_card_free(card); 32458c2ecf20Sopenharmony_ci return err; 32468c2ecf20Sopenharmony_ci } 32478c2ecf20Sopenharmony_ci pci_set_drvdata(pci, card); 32488c2ecf20Sopenharmony_ci return 0; 32498c2ecf20Sopenharmony_ci} 32508c2ecf20Sopenharmony_ci 32518c2ecf20Sopenharmony_cistatic void snd_intel8x0_remove(struct pci_dev *pci) 32528c2ecf20Sopenharmony_ci{ 32538c2ecf20Sopenharmony_ci snd_card_free(pci_get_drvdata(pci)); 32548c2ecf20Sopenharmony_ci} 32558c2ecf20Sopenharmony_ci 32568c2ecf20Sopenharmony_cistatic struct pci_driver intel8x0_driver = { 32578c2ecf20Sopenharmony_ci .name = KBUILD_MODNAME, 32588c2ecf20Sopenharmony_ci .id_table = snd_intel8x0_ids, 32598c2ecf20Sopenharmony_ci .probe = snd_intel8x0_probe, 32608c2ecf20Sopenharmony_ci .remove = snd_intel8x0_remove, 32618c2ecf20Sopenharmony_ci .driver = { 32628c2ecf20Sopenharmony_ci .pm = INTEL8X0_PM_OPS, 32638c2ecf20Sopenharmony_ci }, 32648c2ecf20Sopenharmony_ci}; 32658c2ecf20Sopenharmony_ci 32668c2ecf20Sopenharmony_cimodule_pci_driver(intel8x0_driver); 3267