diff options
author | Ingo Molnar <mingo@elte.hu> | 2008-10-28 16:26:12 +0100 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-10-28 16:26:12 +0100 |
commit | 7a9787e1eba95a166265e6a260cf30af04ef0a99 (patch) | |
tree | e730a4565e0318140d2fbd2f0415d18a339d7336 /sound/isa | |
parent | 41b9eb264c8407655db57b60b4457fe1b2ec9977 (diff) | |
parent | 0173a3265b228da319ceb9c1ec6a5682fd1b2d92 (diff) |
Merge commit 'v2.6.28-rc2' into x86/pci-ioapic-boot-irq-quirks
Diffstat (limited to 'sound/isa')
39 files changed, 3018 insertions, 3767 deletions
diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig index 5769a13c1d9..660beb41f76 100644 --- a/sound/isa/Kconfig +++ b/sound/isa/Kconfig @@ -1,10 +1,6 @@ # ALSA ISA drivers -config SND_AD1848_LIB - tristate - select SND_PCM - -config SND_CS4231_LIB +config SND_WSS_LIB tristate select SND_PCM @@ -55,7 +51,7 @@ config SND_AD1816A config SND_AD1848 tristate "Generic AD1848/CS4248 driver" - select SND_AD1848_LIB + select SND_WSS_LIB help Say Y here to include support for AD1848 (Analog Devices) or CS4248 (Cirrus Logic - Crystal Semiconductors) chips. @@ -86,7 +82,7 @@ config SND_AZT2320 select ISAPNP select SND_OPL3_LIB select SND_MPU401_UART - select SND_CS4231_LIB + select SND_WSS_LIB help Say Y here to include support for soundcards based on the Aztech Systems AZT2320 chip. @@ -96,7 +92,7 @@ config SND_AZT2320 config SND_CMI8330 tristate "C-Media CMI8330" - select SND_AD1848_LIB + select SND_WSS_LIB select SND_SB16_DSP help Say Y here to include support for soundcards based on the @@ -108,7 +104,7 @@ config SND_CMI8330 config SND_CS4231 tristate "Generic Cirrus Logic CS4231 driver" select SND_MPU401_UART - select SND_CS4231_LIB + select SND_WSS_LIB help Say Y here to include support for CS4231 chips from Cirrus Logic - Crystal Semiconductors. @@ -120,7 +116,7 @@ config SND_CS4232 tristate "Generic Cirrus Logic CS4232 driver" select SND_OPL3_LIB select SND_MPU401_UART - select SND_CS4231_LIB + select SND_WSS_LIB help Say Y here to include support for CS4232 chips from Cirrus Logic - Crystal Semiconductors. @@ -132,7 +128,7 @@ config SND_CS4236 tristate "Generic Cirrus Logic CS4236+ driver" select SND_OPL3_LIB select SND_MPU401_UART - select SND_CS4231_LIB + select SND_WSS_LIB help Say Y to include support for CS4235,CS4236,CS4237B,CS4238B, CS4239 chips from Cirrus Logic - Crystal Semiconductors. @@ -192,7 +188,7 @@ config SND_ES18XX config SND_SC6000 tristate "Gallant SC-6000, Audio Excel DSP 16" depends on HAS_IOPORT - select SND_AD1848_LIB + select SND_WSS_LIB select SND_OPL3_LIB select SND_MPU401_UART help @@ -228,7 +224,7 @@ config SND_GUSEXTREME config SND_GUSMAX tristate "Gravis UltraSound MAX" select SND_RAWMIDI - select SND_CS4231_LIB + select SND_WSS_LIB help Say Y here to include support for Gravis UltraSound MAX soundcards. @@ -240,7 +236,7 @@ config SND_INTERWAVE tristate "AMD InterWave, Gravis UltraSound PnP" depends on PNP select SND_RAWMIDI - select SND_CS4231_LIB + select SND_WSS_LIB help Say Y here to include support for AMD InterWave based soundcards (Gravis UltraSound Plug & Play, STB SoundRage32, @@ -253,7 +249,7 @@ config SND_INTERWAVE_STB tristate "AMD InterWave + TEA6330T (UltraSound 32-Pro)" depends on PNP select SND_RAWMIDI - select SND_CS4231_LIB + select SND_WSS_LIB help Say Y here to include support for AMD InterWave based soundcards with a TEA6330T bass and treble regulator @@ -266,7 +262,7 @@ config SND_OPL3SA2 tristate "Yamaha OPL3-SA2/SA3" select SND_OPL3_LIB select SND_MPU401_UART - select SND_CS4231_LIB + select SND_WSS_LIB help Say Y here to include support for Yamaha OPL3-SA2 and OPL3-SA3 chips. @@ -279,7 +275,7 @@ config SND_OPTI92X_AD1848 select SND_OPL3_LIB select SND_OPL4_LIB select SND_MPU401_UART - select SND_AD1848_LIB + select SND_WSS_LIB help Say Y here to include support for soundcards based on Opti 82C92x or OTI-601 chips and using an AD1848 codec. @@ -292,7 +288,7 @@ config SND_OPTI92X_CS4231 select SND_OPL3_LIB select SND_OPL4_LIB select SND_MPU401_UART - select SND_CS4231_LIB + select SND_WSS_LIB help Say Y here to include support for soundcards based on Opti 82C92x chips and using a CS4231 codec. @@ -304,7 +300,7 @@ config SND_OPTI93X tristate "OPTi 82C93x" select SND_OPL3_LIB select SND_MPU401_UART - select SND_CS4231_LIB + select SND_WSS_LIB help Say Y here to include support for soundcards based on Opti 82C93x chips. @@ -315,7 +311,7 @@ config SND_OPTI93X config SND_MIRO tristate "Miro miroSOUND PCM1pro/PCM12/PCM20radio driver" select SND_OPL4_LIB - select SND_CS4231_LIB + select SND_WSS_LIB select SND_MPU401_UART select SND_PCM help @@ -364,7 +360,7 @@ config SND_SBAWE config SND_SB16_CSP bool "Sound Blaster 16/AWE CSP support" depends on (SND_SB16 || SND_SBAWE) && (BROKEN || !PPC) - select FW_LOADER if !SND_SB16_CSP_FIRMWARE_IN_KERNEL + select FW_LOADER help Say Y here to include support for the CSP core. This special coprocessor can do variable tasks like various compression and @@ -372,7 +368,7 @@ config SND_SB16_CSP config SND_SGALAXY tristate "Aztech Sound Galaxy" - select SND_AD1848_LIB + select SND_WSS_LIB help Say Y here to include support for Aztech Sound Galaxy soundcards. @@ -384,7 +380,7 @@ config SND_SSCAPE tristate "Ensoniq SoundScape PnP driver" select SND_HWDEP select SND_MPU401_UART - select SND_CS4231_LIB + select SND_WSS_LIB help Say Y here to include support for Ensoniq SoundScape PnP soundcards. @@ -397,7 +393,7 @@ config SND_WAVEFRONT select FW_LOADER select SND_OPL3_LIB select SND_MPU401_UART - select SND_CS4231_LIB + select SND_WSS_LIB help Say Y here to include support for Turtle Beach Maui, Tropez and Tropez+ soundcards based on the Wavefront chip. diff --git a/sound/isa/Makefile b/sound/isa/Makefile index c0ce7db2a1b..63af13d901a 100644 --- a/sound/isa/Makefile +++ b/sound/isa/Makefile @@ -27,4 +27,4 @@ obj-$(CONFIG_SND_SGALAXY) += snd-sgalaxy.o obj-$(CONFIG_SND_SSCAPE) += snd-sscape.o obj-$(CONFIG_SND) += ad1816a/ ad1848/ cs423x/ es1688/ gus/ opti9xx/ \ - sb/ wavefront/ + sb/ wavefront/ wss/ diff --git a/sound/isa/ad1816a/ad1816a.c b/sound/isa/ad1816a/ad1816a.c index 68f1260b560..77524244a84 100644 --- a/sound/isa/ad1816a/ad1816a.c +++ b/sound/isa/ad1816a/ad1816a.c @@ -83,8 +83,10 @@ static struct pnp_card_device_id snd_ad1816a_pnpids[] = { { .id = "MDK1605", .devs = { { .id = "ADS7180" }, { .id = "ADS7181" } } }, /* Shark Predator ISA - added by Ken Arromdee */ { .id = "SMM7180", .devs = { { .id = "ADS7180" }, { .id = "ADS7181" } } }, - /* Analog Devices AD1816A - Terratec AudioSystem EWS64S */ + /* Analog Devices AD1816A - Terratec AudioSystem EWS64 S */ { .id = "TER1112", .devs = { { .id = "ADS7180" }, { .id = "ADS7181" } } }, + /* Analog Devices AD1816A - Terratec AudioSystem EWS64 S */ + { .id = "TER1112", .devs = { { .id = "TER1100" }, { .id = "TER1101" } } }, /* Analog Devices AD1816A - Terratec Base 64 */ { .id = "TER1411", .devs = { { .id = "ADS7180" }, { .id = "ADS7181" } } }, /* end */ diff --git a/sound/isa/ad1816a/ad1816a_lib.c b/sound/isa/ad1816a/ad1816a_lib.c index 4b8dfe2e3dc..3bfca7c59ba 100644 --- a/sound/isa/ad1816a/ad1816a_lib.c +++ b/sound/isa/ad1816a/ad1816a_lib.c @@ -394,7 +394,8 @@ static int snd_ad1816a_timer_open(struct snd_timer *timer) static unsigned long snd_ad1816a_timer_resolution(struct snd_timer *timer) { - snd_assert(timer != NULL, return 0); + if (snd_BUG_ON(!timer)) + return 0; return 10000; } @@ -961,7 +962,8 @@ int __devinit snd_ad1816a_mixer(struct snd_ad1816a *chip) unsigned int idx; int err; - snd_assert(chip != NULL && chip->card != NULL, return -EINVAL); + if (snd_BUG_ON(!chip || !chip->card)) + return -EINVAL; card = chip->card; diff --git a/sound/isa/ad1848/Makefile b/sound/isa/ad1848/Makefile index ae23331e920..3d6dea3ff92 100644 --- a/sound/isa/ad1848/Makefile +++ b/sound/isa/ad1848/Makefile @@ -3,10 +3,8 @@ # Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz> # -snd-ad1848-lib-objs := ad1848_lib.o snd-ad1848-objs := ad1848.o # Toplevel Module Dependency obj-$(CONFIG_SND_AD1848) += snd-ad1848.o -obj-$(CONFIG_SND_AD1848_LIB) += snd-ad1848-lib.o diff --git a/sound/isa/ad1848/ad1848.c b/sound/isa/ad1848/ad1848.c index 5f5271efdc5..b68d20edc20 100644 --- a/sound/isa/ad1848/ad1848.c +++ b/sound/isa/ad1848/ad1848.c @@ -28,7 +28,7 @@ #include <linux/wait.h> #include <linux/moduleparam.h> #include <sound/core.h> -#include <sound/ad1848.h> +#include <sound/wss.h> #include <sound/initval.h> #define CRD_NAME "Generic AD1848/AD1847/CS4248" @@ -87,7 +87,7 @@ static int __devinit snd_ad1848_match(struct device *dev, unsigned int n) static int __devinit snd_ad1848_probe(struct device *dev, unsigned int n) { struct snd_card *card; - struct snd_ad1848 *chip; + struct snd_wss *chip; struct snd_pcm *pcm; int error; @@ -95,18 +95,19 @@ static int __devinit snd_ad1848_probe(struct device *dev, unsigned int n) if (!card) return -EINVAL; - error = snd_ad1848_create(card, port[n], irq[n], dma1[n], - thinkpad[n] ? AD1848_HW_THINKPAD : AD1848_HW_DETECT, &chip); + error = snd_wss_create(card, port[n], -1, irq[n], dma1[n], -1, + thinkpad[n] ? WSS_HW_THINKPAD : WSS_HW_DETECT, + 0, &chip); if (error < 0) goto out; card->private_data = chip; - error = snd_ad1848_pcm(chip, 0, &pcm); + error = snd_wss_pcm(chip, 0, &pcm); if (error < 0) goto out; - error = snd_ad1848_mixer(chip); + error = snd_wss_mixer(chip); if (error < 0) goto out; @@ -142,7 +143,7 @@ static int __devexit snd_ad1848_remove(struct device *dev, unsigned int n) static int snd_ad1848_suspend(struct device *dev, unsigned int n, pm_message_t state) { struct snd_card *card = dev_get_drvdata(dev); - struct snd_ad1848 *chip = card->private_data; + struct snd_wss *chip = card->private_data; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); chip->suspend(chip); @@ -152,7 +153,7 @@ static int snd_ad1848_suspend(struct device *dev, unsigned int n, pm_message_t s static int snd_ad1848_resume(struct device *dev, unsigned int n) { struct snd_card *card = dev_get_drvdata(dev); - struct snd_ad1848 *chip = card->private_data; + struct snd_wss *chip = card->private_data; chip->resume(chip); snd_power_change_state(card, SNDRV_CTL_POWER_D0); diff --git a/sound/isa/ad1848/ad1848_lib.c b/sound/isa/ad1848/ad1848_lib.c deleted file mode 100644 index 630c90f9ee5..00000000000 --- a/sound/isa/ad1848/ad1848_lib.c +++ /dev/null @@ -1,1267 +0,0 @@ -/* - * Copyright (c) by Jaroslav Kysela <perex@perex.cz> - * Routines for control of AD1848/AD1847/CS4248 - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#define SNDRV_MAIN_OBJECT_FILE -#include <linux/delay.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/slab.h> -#include <linux/ioport.h> -#include <sound/core.h> -#include <sound/ad1848.h> -#include <sound/control.h> -#include <sound/tlv.h> -#include <sound/pcm_params.h> - -#include <asm/io.h> -#include <asm/dma.h> - -MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); -MODULE_DESCRIPTION("Routines for control of AD1848/AD1847/CS4248"); -MODULE_LICENSE("GPL"); - -#if 0 -#define SNDRV_DEBUG_MCE -#endif - -/* - * Some variables - */ - -static unsigned char freq_bits[14] = { - /* 5510 */ 0x00 | AD1848_XTAL2, - /* 6620 */ 0x0E | AD1848_XTAL2, - /* 8000 */ 0x00 | AD1848_XTAL1, - /* 9600 */ 0x0E | AD1848_XTAL1, - /* 11025 */ 0x02 | AD1848_XTAL2, - /* 16000 */ 0x02 | AD1848_XTAL1, - /* 18900 */ 0x04 | AD1848_XTAL2, - /* 22050 */ 0x06 | AD1848_XTAL2, - /* 27042 */ 0x04 | AD1848_XTAL1, - /* 32000 */ 0x06 | AD1848_XTAL1, - /* 33075 */ 0x0C | AD1848_XTAL2, - /* 37800 */ 0x08 | AD1848_XTAL2, - /* 44100 */ 0x0A | AD1848_XTAL2, - /* 48000 */ 0x0C | AD1848_XTAL1 -}; - -static unsigned int rates[14] = { - 5510, 6620, 8000, 9600, 11025, 16000, 18900, 22050, - 27042, 32000, 33075, 37800, 44100, 48000 -}; - -static struct snd_pcm_hw_constraint_list hw_constraints_rates = { - .count = ARRAY_SIZE(rates), - .list = rates, - .mask = 0, -}; - -static unsigned char snd_ad1848_original_image[16] = -{ - 0x00, /* 00 - lic */ - 0x00, /* 01 - ric */ - 0x9f, /* 02 - la1ic */ - 0x9f, /* 03 - ra1ic */ - 0x9f, /* 04 - la2ic */ - 0x9f, /* 05 - ra2ic */ - 0xbf, /* 06 - loc */ - 0xbf, /* 07 - roc */ - 0x20, /* 08 - dfr */ - AD1848_AUTOCALIB, /* 09 - ic */ - 0x00, /* 0a - pc */ - 0x00, /* 0b - ti */ - 0x00, /* 0c - mi */ - 0x00, /* 0d - lbc */ - 0x00, /* 0e - dru */ - 0x00, /* 0f - drl */ -}; - -/* - * Basic I/O functions - */ - -static void snd_ad1848_wait(struct snd_ad1848 *chip) -{ - int timeout; - - for (timeout = 250; timeout > 0; timeout--) { - if ((inb(AD1848P(chip, REGSEL)) & AD1848_INIT) == 0) - break; - udelay(100); - } -} - -void snd_ad1848_out(struct snd_ad1848 *chip, - unsigned char reg, - unsigned char value) -{ - snd_ad1848_wait(chip); -#ifdef CONFIG_SND_DEBUG - if (inb(AD1848P(chip, REGSEL)) & AD1848_INIT) - snd_printk(KERN_WARNING "auto calibration time out - " - "reg = 0x%x, value = 0x%x\n", reg, value); -#endif - outb(chip->mce_bit | reg, AD1848P(chip, REGSEL)); - outb(chip->image[reg] = value, AD1848P(chip, REG)); - mb(); - snd_printdd("codec out - reg 0x%x = 0x%x\n", - chip->mce_bit | reg, value); -} - -EXPORT_SYMBOL(snd_ad1848_out); - -static void snd_ad1848_dout(struct snd_ad1848 *chip, - unsigned char reg, unsigned char value) -{ - snd_ad1848_wait(chip); - outb(chip->mce_bit | reg, AD1848P(chip, REGSEL)); - outb(value, AD1848P(chip, REG)); - mb(); -} - -static unsigned char snd_ad1848_in(struct snd_ad1848 *chip, unsigned char reg) -{ - snd_ad1848_wait(chip); -#ifdef CONFIG_SND_DEBUG - if (inb(AD1848P(chip, REGSEL)) & AD1848_INIT) - snd_printk(KERN_WARNING "auto calibration time out - " - "reg = 0x%x\n", reg); -#endif - outb(chip->mce_bit | reg, AD1848P(chip, REGSEL)); - mb(); - return inb(AD1848P(chip, REG)); -} - -#if 0 - -static void snd_ad1848_debug(struct snd_ad1848 *chip) -{ - printk("AD1848 REGS: INDEX = 0x%02x ", inb(AD1848P(chip, REGSEL))); - printk(" STATUS = 0x%02x\n", inb(AD1848P(chip, STATUS))); - printk(" 0x00: left input = 0x%02x ", snd_ad1848_in(chip, 0x00)); - printk(" 0x08: playback format = 0x%02x\n", snd_ad1848_in(chip, 0x08)); - printk(" 0x01: right input = 0x%02x ", snd_ad1848_in(chip, 0x01)); - printk(" 0x09: iface (CFIG 1) = 0x%02x\n", snd_ad1848_in(chip, 0x09)); - printk(" 0x02: AUXA left = 0x%02x ", snd_ad1848_in(chip, 0x02)); - printk(" 0x0a: pin control = 0x%02x\n", snd_ad1848_in(chip, 0x0a)); - printk(" 0x03: AUXA right = 0x%02x ", snd_ad1848_in(chip, 0x03)); - printk(" 0x0b: init & status = 0x%02x\n", snd_ad1848_in(chip, 0x0b)); - printk(" 0x04: AUXB left = 0x%02x ", snd_ad1848_in(chip, 0x04)); - printk(" 0x0c: revision & mode = 0x%02x\n", snd_ad1848_in(chip, 0x0c)); - printk(" 0x05: AUXB right = 0x%02x ", snd_ad1848_in(chip, 0x05)); - printk(" 0x0d: loopback = 0x%02x\n", snd_ad1848_in(chip, 0x0d)); - printk(" 0x06: left output = 0x%02x ", snd_ad1848_in(chip, 0x06)); - printk(" 0x0e: data upr count = 0x%02x\n", snd_ad1848_in(chip, 0x0e)); - printk(" 0x07: right output = 0x%02x ", snd_ad1848_in(chip, 0x07)); - printk(" 0x0f: data lwr count = 0x%02x\n", snd_ad1848_in(chip, 0x0f)); -} - -#endif - -/* - * AD1848 detection / MCE routines - */ - -static void snd_ad1848_mce_up(struct snd_ad1848 *chip) -{ - unsigned long flags; - int timeout; - - snd_ad1848_wait(chip); -#ifdef CONFIG_SND_DEBUG - if (inb(AD1848P(chip, REGSEL)) & AD1848_INIT) - snd_printk(KERN_WARNING "mce_up - auto calibration time out (0)\n"); -#endif - spin_lock_irqsave(&chip->reg_lock, flags); - chip->mce_bit |= AD1848_MCE; - timeout = inb(AD1848P(chip, REGSEL)); - if (timeout == 0x80) - snd_printk(KERN_WARNING "mce_up [0x%lx]: serious init problem - codec still busy\n", chip->port); - if (!(timeout & AD1848_MCE)) - outb(chip->mce_bit | (timeout & 0x1f), AD1848P(chip, REGSEL)); - spin_unlock_irqrestore(&chip->reg_lock, flags); -} - -static void snd_ad1848_mce_down(struct snd_ad1848 *chip) -{ - unsigned long flags, timeout; - int reg; - - spin_lock_irqsave(&chip->reg_lock, flags); - for (timeout = 5; timeout > 0; timeout--) - inb(AD1848P(chip, REGSEL)); - /* end of cleanup sequence */ - for (timeout = 12000; timeout > 0 && (inb(AD1848P(chip, REGSEL)) & AD1848_INIT); timeout--) - udelay(100); - - snd_printdd("(1) timeout = %ld\n", timeout); - -#ifdef CONFIG_SND_DEBUG - if (inb(AD1848P(chip, REGSEL)) & AD1848_INIT) - snd_printk(KERN_WARNING "mce_down [0x%lx] - auto calibration time out (0)\n", AD1848P(chip, REGSEL)); -#endif - - chip->mce_bit &= ~AD1848_MCE; - reg = inb(AD1848P(chip, REGSEL)); - outb(chip->mce_bit | (reg & 0x1f), AD1848P(chip, REGSEL)); - if (reg == 0x80) - snd_printk(KERN_WARNING "mce_down [0x%lx]: serious init problem - codec still busy\n", chip->port); - if ((reg & AD1848_MCE) == 0) { - spin_unlock_irqrestore(&chip->reg_lock, flags); - return; - } - - /* - * Wait for auto-calibration (AC) process to finish, i.e. ACI to go low. - * It may take up to 5 sample periods (at most 907 us @ 5.5125 kHz) for - * the process to _start_, so it is important to wait at least that long - * before checking. Otherwise we might think AC has finished when it - * has in fact not begun. It could take 128 (no AC) or 384 (AC) cycles - * for ACI to drop. This gives a wait of at most 70 ms with a more - * typical value of 3-9 ms. - */ - timeout = jiffies + msecs_to_jiffies(250); - do { - spin_unlock_irqrestore(&chip->reg_lock, flags); - msleep(1); - spin_lock_irqsave(&chip->reg_lock, flags); - reg = snd_ad1848_in(chip, AD1848_TEST_INIT) & - AD1848_CALIB_IN_PROGRESS; - } while (reg && time_before(jiffies, timeout)); - spin_unlock_irqrestore(&chip->reg_lock, flags); - if (reg) - snd_printk(KERN_ERR - "mce_down - auto calibration time out (2)\n"); - - snd_printdd("(4) jiffies = %lu\n", jiffies); - snd_printd("mce_down - exit = 0x%x\n", inb(AD1848P(chip, REGSEL))); -} - -static unsigned int snd_ad1848_get_count(unsigned char format, - unsigned int size) -{ - switch (format & 0xe0) { - case AD1848_LINEAR_16: - size >>= 1; - break; - } - if (format & AD1848_STEREO) - size >>= 1; - return size; -} - -static int snd_ad1848_trigger(struct snd_ad1848 *chip, unsigned char what, - int channel, int cmd) -{ - int result = 0; - -#if 0 - printk("codec trigger!!! - what = %i, enable = %i, status = 0x%x\n", what, enable, inb(AD1848P(card, STATUS))); -#endif - spin_lock(&chip->reg_lock); - if (cmd == SNDRV_PCM_TRIGGER_START) { - if (chip->image[AD1848_IFACE_CTRL] & what) { - spin_unlock(&chip->reg_lock); - return 0; - } - snd_ad1848_out(chip, AD1848_IFACE_CTRL, chip->image[AD1848_IFACE_CTRL] |= what); - chip->mode |= AD1848_MODE_RUNNING; - } else if (cmd == SNDRV_PCM_TRIGGER_STOP) { - if (!(chip->image[AD1848_IFACE_CTRL] & what)) { - spin_unlock(&chip->reg_lock); - return 0; - } - snd_ad1848_out(chip, AD1848_IFACE_CTRL, chip->image[AD1848_IFACE_CTRL] &= ~what); - chip->mode &= ~AD1848_MODE_RUNNING; - } else { - result = -EINVAL; - } - spin_unlock(&chip->reg_lock); - return result; -} - -/* - * CODEC I/O - */ - -static unsigned char snd_ad1848_get_rate(unsigned int rate) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(rates); i++) - if (rate == rates[i]) - return freq_bits[i]; - snd_BUG(); - return freq_bits[ARRAY_SIZE(rates) - 1]; -} - -static int snd_ad1848_ioctl(struct snd_pcm_substream *substream, - unsigned int cmd, void *arg) -{ - return snd_pcm_lib_ioctl(substream, cmd, arg); -} - -static unsigned char snd_ad1848_get_format(int format, int channels) -{ - unsigned char rformat; - - rformat = AD1848_LINEAR_8; - switch (format) { - case SNDRV_PCM_FORMAT_A_LAW: rformat = AD1848_ALAW_8; break; - case SNDRV_PCM_FORMAT_MU_LAW: rformat = AD1848_ULAW_8; break; - case SNDRV_PCM_FORMAT_S16_LE: rformat = AD1848_LINEAR_16; break; - } - if (channels > 1) - rformat |= AD1848_STEREO; -#if 0 - snd_printk("get_format: 0x%x (mode=0x%x)\n", format, mode); -#endif - return rformat; -} - -static void snd_ad1848_calibrate_mute(struct snd_ad1848 *chip, int mute) -{ - unsigned long flags; - - mute = mute ? 1 : 0; - spin_lock_irqsave(&chip->reg_lock, flags); - if (chip->calibrate_mute == mute) { - spin_unlock_irqrestore(&chip->reg_lock, flags); - return; - } - if (!mute) { - snd_ad1848_dout(chip, AD1848_LEFT_INPUT, chip->image[AD1848_LEFT_INPUT]); - snd_ad1848_dout(chip, AD1848_RIGHT_INPUT, chip->image[AD1848_RIGHT_INPUT]); - } - snd_ad1848_dout(chip, AD1848_AUX1_LEFT_INPUT, mute ? 0x80 : chip->image[AD1848_AUX1_LEFT_INPUT]); - snd_ad1848_dout(chip, AD1848_AUX1_RIGHT_INPUT, mute ? 0x80 : chip->image[AD1848_AUX1_RIGHT_INPUT]); - snd_ad1848_dout(chip, AD1848_AUX2_LEFT_INPUT, mute ? 0x80 : chip->image[AD1848_AUX2_LEFT_INPUT]); - snd_ad1848_dout(chip, AD1848_AUX2_RIGHT_INPUT, mute ? 0x80 : chip->image[AD1848_AUX2_RIGHT_INPUT]); - snd_ad1848_dout(chip, AD1848_LEFT_OUTPUT, mute ? 0x80 : chip->image[AD1848_LEFT_OUTPUT]); - snd_ad1848_dout(chip, AD1848_RIGHT_OUTPUT, mute ? 0x80 : chip->image[AD1848_RIGHT_OUTPUT]); - chip->calibrate_mute = mute; - spin_unlock_irqrestore(&chip->reg_lock, flags); -} - -static void snd_ad1848_set_data_format(struct snd_ad1848 *chip, struct snd_pcm_hw_params *hw_params) -{ - if (hw_params == NULL) { - chip->image[AD1848_DATA_FORMAT] = 0x20; - } else { - chip->image[AD1848_DATA_FORMAT] = - snd_ad1848_get_format(params_format(hw_params), params_channels(hw_params)) | - snd_ad1848_get_rate(params_rate(hw_params)); - } - // snd_printk(">>> pmode = 0x%x, dfr = 0x%x\n", pstr->mode, chip->image[AD1848_DATA_FORMAT]); -} - -static int snd_ad1848_open(struct snd_ad1848 *chip, unsigned int mode) -{ - unsigned long flags; - - if (chip->mode & AD1848_MODE_OPEN) - return -EAGAIN; - - snd_ad1848_mce_down(chip); - -#ifdef SNDRV_DEBUG_MCE - snd_printk("open: (1)\n"); -#endif - snd_ad1848_mce_up(chip); - spin_lock_irqsave(&chip->reg_lock, flags); - chip->image[AD1848_IFACE_CTRL] &= ~(AD1848_PLAYBACK_ENABLE | AD1848_PLAYBACK_PIO | - AD1848_CAPTURE_ENABLE | AD1848_CAPTURE_PIO | - AD1848_CALIB_MODE); - chip->image[AD1848_IFACE_CTRL] |= AD1848_AUTOCALIB; - snd_ad1848_out(chip, AD1848_IFACE_CTRL, chip->image[AD1848_IFACE_CTRL]); - spin_unlock_irqrestore(&chip->reg_lock, flags); - snd_ad1848_mce_down(chip); - -#ifdef SNDRV_DEBUG_MCE - snd_printk("open: (2)\n"); -#endif - - snd_ad1848_set_data_format(chip, NULL); - - snd_ad1848_mce_up(chip); - spin_lock_irqsave(&chip->reg_lock, flags); - snd_ad1848_out(chip, AD1848_DATA_FORMAT, chip->image[AD1848_DATA_FORMAT]); - spin_unlock_irqrestore(&chip->reg_lock, flags); - snd_ad1848_mce_down(chip); - -#ifdef SNDRV_DEBUG_MCE - snd_printk("open: (3)\n"); -#endif - - /* ok. now enable and ack CODEC IRQ */ - spin_lock_irqsave(&chip->reg_lock, flags); - outb(0, AD1848P(chip, STATUS)); /* clear IRQ */ - outb(0, AD1848P(chip, STATUS)); /* clear IRQ */ - chip->image[AD1848_PIN_CTRL] |= AD1848_IRQ_ENABLE; - snd_ad1848_out(chip, AD1848_PIN_CTRL, chip->image[AD1848_PIN_CTRL]); - spin_unlock_irqrestore(&chip->reg_lock, flags); - - chip->mode = mode; - - return 0; -} - -static void snd_ad1848_close(struct snd_ad1848 *chip) -{ - unsigned long flags; - - if (!chip->mode) - return; - /* disable IRQ */ - spin_lock_irqsave(&chip->reg_lock, flags); - outb(0, AD1848P(chip, STATUS)); /* clear IRQ */ - outb(0, AD1848P(chip, STATUS)); /* clear IRQ */ - chip->image[AD1848_PIN_CTRL] &= ~AD1848_IRQ_ENABLE; - snd_ad1848_out(chip, AD1848_PIN_CTRL, chip->image[AD1848_PIN_CTRL]); - spin_unlock_irqrestore(&chip->reg_lock, flags); - - /* now disable capture & playback */ - - snd_ad1848_mce_up(chip); - spin_lock_irqsave(&chip->reg_lock, flags); - chip->image[AD1848_IFACE_CTRL] &= ~(AD1848_PLAYBACK_ENABLE | AD1848_PLAYBACK_PIO | - AD1848_CAPTURE_ENABLE | AD1848_CAPTURE_PIO); - snd_ad1848_out(chip, AD1848_IFACE_CTRL, chip->image[AD1848_IFACE_CTRL]); - spin_unlock_irqrestore(&chip->reg_lock, flags); - snd_ad1848_mce_down(chip); - - /* clear IRQ again */ - spin_lock_irqsave(&chip->reg_lock, flags); - outb(0, AD1848P(chip, STATUS)); /* clear IRQ */ - outb(0, AD1848P(chip, STATUS)); /* clear IRQ */ - spin_unlock_irqrestore(&chip->reg_lock, flags); - - chip->mode = 0; -} - -/* - * ok.. exported functions.. - */ - -static int snd_ad1848_playback_trigger(struct snd_pcm_substream *substream, - int cmd) -{ - struct snd_ad1848 *chip = snd_pcm_substream_chip(substream); - return snd_ad1848_trigger(chip, AD1848_PLAYBACK_ENABLE, SNDRV_PCM_STREAM_PLAYBACK, cmd); -} - -static int snd_ad1848_capture_trigger(struct snd_pcm_substream *substream, - int cmd) -{ - struct snd_ad1848 *chip = snd_pcm_substream_chip(substream); - return snd_ad1848_trigger(chip, AD1848_CAPTURE_ENABLE, SNDRV_PCM_STREAM_CAPTURE, cmd); -} - -static int snd_ad1848_playback_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) -{ - struct snd_ad1848 *chip = snd_pcm_substream_chip(substream); - unsigned long flags; - int err; - - if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0) - return err; - snd_ad1848_calibrate_mute(chip, 1); - snd_ad1848_set_data_format(chip, hw_params); - snd_ad1848_mce_up(chip); - spin_lock_irqsave(&chip->reg_lock, flags); - snd_ad1848_out(chip, AD1848_DATA_FORMAT, chip->image[AD1848_DATA_FORMAT]); - spin_unlock_irqrestore(&chip->reg_lock, flags); - snd_ad1848_mce_down(chip); - snd_ad1848_calibrate_mute(chip, 0); - return 0; -} - -static int snd_ad1848_playback_hw_free(struct snd_pcm_substream *substream) -{ - return snd_pcm_lib_free_pages(substream); -} - -static int snd_ad1848_playback_prepare(struct snd_pcm_substream *substream) -{ - struct snd_ad1848 *chip = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - unsigned long flags; - unsigned int size = snd_pcm_lib_buffer_bytes(substream); - unsigned int count = snd_pcm_lib_period_bytes(substream); - - chip->dma_size = size; - chip->image[AD1848_IFACE_CTRL] &= ~(AD1848_PLAYBACK_ENABLE | AD1848_PLAYBACK_PIO); - snd_dma_program(chip->dma, runtime->dma_addr, size, DMA_MODE_WRITE | DMA_AUTOINIT); - count = snd_ad1848_get_count(chip->image[AD1848_DATA_FORMAT], count) - 1; - spin_lock_irqsave(&chip->reg_lock, flags); - snd_ad1848_out(chip, AD1848_DATA_LWR_CNT, (unsigned char) count); - snd_ad1848_out(chip, AD1848_DATA_UPR_CNT, (unsigned char) (count >> 8)); - spin_unlock_irqrestore(&chip->reg_lock, flags); - return 0; -} - -static int snd_ad1848_capture_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) -{ - struct snd_ad1848 *chip = snd_pcm_substream_chip(substream); - unsigned long flags; - int err; - - if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0) - return err; - snd_ad1848_calibrate_mute(chip, 1); - snd_ad1848_set_data_format(chip, hw_params); - snd_ad1848_mce_up(chip); - spin_lock_irqsave(&chip->reg_lock, flags); - snd_ad1848_out(chip, AD1848_DATA_FORMAT, chip->image[AD1848_DATA_FORMAT]); - spin_unlock_irqrestore(&chip->reg_lock, flags); - snd_ad1848_mce_down(chip); - snd_ad1848_calibrate_mute(chip, 0); - return 0; -} - -static int snd_ad1848_capture_hw_free(struct snd_pcm_substream *substream) -{ - return snd_pcm_lib_free_pages(substream); -} - -static int snd_ad1848_capture_prepare(struct snd_pcm_substream *substream) -{ - struct snd_ad1848 *chip = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - unsigned long flags; - unsigned int size = snd_pcm_lib_buffer_bytes(substream); - unsigned int count = snd_pcm_lib_period_bytes(substream); - - chip->dma_size = size; - chip->image[AD1848_IFACE_CTRL] &= ~(AD1848_CAPTURE_ENABLE | AD1848_CAPTURE_PIO); - snd_dma_program(chip->dma, runtime->dma_addr, size, DMA_MODE_READ | DMA_AUTOINIT); - count = snd_ad1848_get_count(chip->image[AD1848_DATA_FORMAT], count) - 1; - spin_lock_irqsave(&chip->reg_lock, flags); - snd_ad1848_out(chip, AD1848_DATA_LWR_CNT, (unsigned char) count); - snd_ad1848_out(chip, AD1848_DATA_UPR_CNT, (unsigned char) (count >> 8)); - spin_unlock_irqrestore(&chip->reg_lock, flags); - return 0; -} - -static irqreturn_t snd_ad1848_interrupt(int irq, void *dev_id) -{ - struct snd_ad1848 *chip = dev_id; - - if ((chip->mode & AD1848_MODE_PLAY) && chip->playback_substream && - (chip->mode & AD1848_MODE_RUNNING)) - snd_pcm_period_elapsed(chip->playback_substream); - if ((chip->mode & AD1848_MODE_CAPTURE) && chip->capture_substream && - (chip->mode & AD1848_MODE_RUNNING)) - snd_pcm_period_elapsed(chip->capture_substream); - outb(0, AD1848P(chip, STATUS)); /* clear global interrupt bit */ - return IRQ_HANDLED; -} - -static snd_pcm_uframes_t snd_ad1848_playback_pointer(struct snd_pcm_substream *substream) -{ - struct snd_ad1848 *chip = snd_pcm_substream_chip(substream); - size_t ptr; - - if (!(chip->image[AD1848_IFACE_CTRL] & AD1848_PLAYBACK_ENABLE)) - return 0; - ptr = snd_dma_pointer(chip->dma, chip->dma_size); - return bytes_to_frames(substream->runtime, ptr); -} - -static snd_pcm_uframes_t snd_ad1848_capture_pointer(struct snd_pcm_substream *substream) -{ - struct snd_ad1848 *chip = snd_pcm_substream_chip(substream); - size_t ptr; - - if (!(chip->image[AD1848_IFACE_CTRL] & AD1848_CAPTURE_ENABLE)) - return 0; - ptr = snd_dma_pointer(chip->dma, chip->dma_size); - return bytes_to_frames(substream->runtime, ptr); -} - -/* - - */ - -static void snd_ad1848_thinkpad_twiddle(struct snd_ad1848 *chip, int on) { - - int tmp; - - if (!chip->thinkpad_flag) return; - - outb(0x1c, AD1848_THINKPAD_CTL_PORT1); - tmp = inb(AD1848_THINKPAD_CTL_PORT2); - - if (on) - /* turn it on */ - tmp |= AD1848_THINKPAD_CS4248_ENABLE_BIT; - else - /* turn it off */ - tmp &= ~AD1848_THINKPAD_CS4248_ENABLE_BIT; - - outb(tmp, AD1848_THINKPAD_CTL_PORT2); - -} - -#ifdef CONFIG_PM -static void snd_ad1848_suspend(struct snd_ad1848 *chip) -{ - snd_pcm_suspend_all(chip->pcm); - if (chip->thinkpad_flag) - snd_ad1848_thinkpad_twiddle(chip, 0); -} - -static void snd_ad1848_resume(struct snd_ad1848 *chip) -{ - int i; - - if (chip->thinkpad_flag) - snd_ad1848_thinkpad_twiddle(chip, 1); - - /* clear any pendings IRQ */ - inb(AD1848P(chip, STATUS)); - outb(0, AD1848P(chip, STATUS)); - mb(); - - snd_ad1848_mce_down(chip); - for (i = 0; i < 16; i++) - snd_ad1848_out(chip, i, chip->image[i]); - snd_ad1848_mce_up(chip); - snd_ad1848_mce_down(chip); -} -#endif /* CONFIG_PM */ - -static int snd_ad1848_probe(struct snd_ad1848 * chip) -{ - unsigned long flags; - int i, id, rev, ad1847; - unsigned char *ptr; - -#if 0 - snd_ad1848_debug(chip); -#endif - id = ad1847 = 0; - for (i = 0; i < 1000; i++) { - mb(); - if (inb(AD1848P(chip, REGSEL)) & AD1848_INIT) - udelay(500); - else { - spin_lock_irqsave(&chip->reg_lock, flags); - snd_ad1848_out(chip, AD1848_MISC_INFO, 0x00); - snd_ad1848_out(chip, AD1848_LEFT_INPUT, 0xaa); - snd_ad1848_out(chip, AD1848_RIGHT_INPUT, 0x45); - rev = snd_ad1848_in(chip, AD1848_RIGHT_INPUT); - if (rev == 0x65) { - spin_unlock_irqrestore(&chip->reg_lock, flags); - id = 1; - ad1847 = 1; - break; - } - if (snd_ad1848_in(chip, AD1848_LEFT_INPUT) == 0xaa && rev == 0x45) { - spin_unlock_irqrestore(&chip->reg_lock, flags); - id = 1; - break; - } - spin_unlock_irqrestore(&chip->reg_lock, flags); - } - } - if (id != 1) - return -ENODEV; /* no valid device found */ - if (chip->hardware == AD1848_HW_DETECT) { - if (ad1847) { - chip->hardware = AD1848_HW_AD1847; - } else { - chip->hardware = AD1848_HW_AD1848; - rev = snd_ad1848_in(chip, AD1848_MISC_INFO); - if (rev & 0x80) { - chip->hardware = AD1848_HW_CS4248; - } else if ((rev & 0x0f) == 0x0a) { - snd_ad1848_out(chip, AD1848_MISC_INFO, 0x40); - for (i = 0; i < 16; ++i) { - if (snd_ad1848_in(chip, i) != snd_ad1848_in(chip, i + 16)) { - chip->hardware = AD1848_HW_CMI8330; - break; - } - } - snd_ad1848_out(chip, AD1848_MISC_INFO, 0x00); - } - } - } - spin_lock_irqsave(&chip->reg_lock, flags); - inb(AD1848P(chip, STATUS)); /* clear any pendings IRQ */ - outb(0, AD1848P(chip, STATUS)); - mb(); - spin_unlock_irqrestore(&chip->reg_lock, flags); - - chip->image[AD1848_MISC_INFO] = 0x00; - chip->image[AD1848_IFACE_CTRL] = - (chip->image[AD1848_IFACE_CTRL] & ~AD1848_SINGLE_DMA) | AD1848_SINGLE_DMA; - ptr = (unsigned char *) &chip->image; - snd_ad1848_mce_down(chip); - spin_lock_irqsave(&chip->reg_lock, flags); - for (i = 0; i < 16; i++) /* ok.. fill all AD1848 registers */ - snd_ad1848_out(chip, i, *ptr++); - spin_unlock_irqrestore(&chip->reg_lock, flags); - snd_ad1848_mce_up(chip); - snd_ad1848_mce_down(chip); - return 0; /* all things are ok.. */ -} - -/* - - */ - -static struct snd_pcm_hardware snd_ad1848_playback = -{ - .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_MMAP_VALID), - .formats = (SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | - SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE), - .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000, - .rate_min = 5510, - .rate_max = 48000, - .channels_min = 1, - .channels_max = 2, - .buffer_bytes_max = (128*1024), - .period_bytes_min = 64, - .period_bytes_max = (128*1024), - .periods_min = 1, - .periods_max = 1024, - .fifo_size = 0, -}; - -static struct snd_pcm_hardware snd_ad1848_capture = -{ - .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_MMAP_VALID), - .formats = (SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | - SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE), - .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000, - .rate_min = 5510, - .rate_max = 48000, - .channels_min = 1, - .channels_max = 2, - .buffer_bytes_max = (128*1024), - .period_bytes_min = 64, - .period_bytes_max = (128*1024), - .periods_min = 1, - .periods_max = 1024, - .fifo_size = 0, -}; - -/* - - */ - -static int snd_ad1848_playback_open(struct snd_pcm_substream *substream) -{ - struct snd_ad1848 *chip = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - int err; - - if ((err = snd_ad1848_open(chip, AD1848_MODE_PLAY)) < 0) - return err; - chip->playback_substream = substream; - runtime->hw = snd_ad1848_playback; - snd_pcm_limit_isa_dma_size(chip->dma, &runtime->hw.buffer_bytes_max); - snd_pcm_limit_isa_dma_size(chip->dma, &runtime->hw.period_bytes_max); - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); - return 0; -} - -static int snd_ad1848_capture_open(struct snd_pcm_substream *substream) -{ - struct snd_ad1848 *chip = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - int err; - - if ((err = snd_ad1848_open(chip, AD1848_MODE_CAPTURE)) < 0) - return err; - chip->capture_substream = substream; - runtime->hw = snd_ad1848_capture; - snd_pcm_limit_isa_dma_size(chip->dma, &runtime->hw.buffer_bytes_max); - snd_pcm_limit_isa_dma_size(chip->dma, &runtime->hw.period_bytes_max); - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); - return 0; -} - -static int snd_ad1848_playback_close(struct snd_pcm_substream *substream) -{ - struct snd_ad1848 *chip = snd_pcm_substream_chip(substream); - - chip->mode &= ~AD1848_MODE_PLAY; - chip->playback_substream = NULL; - snd_ad1848_close(chip); - return 0; -} - -static int snd_ad1848_capture_close(struct snd_pcm_substream *substream) -{ - struct snd_ad1848 *chip = snd_pcm_substream_chip(substream); - - chip->mode &= ~AD1848_MODE_CAPTURE; - chip->capture_substream = NULL; - snd_ad1848_close(chip); - return 0; -} - -static int snd_ad1848_free(struct snd_ad1848 *chip) -{ - release_and_free_resource(chip->res_port); - if (chip->irq >= 0) - free_irq(chip->irq, (void *) chip); - if (chip->dma >= 0) { - snd_dma_disable(chip->dma); - free_dma(chip->dma); - } - kfree(chip); - return 0; -} - -static int snd_ad1848_dev_free(struct snd_device *device) -{ - struct snd_ad1848 *chip = device->device_data; - return snd_ad1848_free(chip); -} - -static const char *snd_ad1848_chip_id(struct snd_ad1848 *chip) -{ - switch (chip->hardware) { - case AD1848_HW_AD1847: return "AD1847"; - case AD1848_HW_AD1848: return "AD1848"; - case AD1848_HW_CS4248: return "CS4248"; - case AD1848_HW_CMI8330: return "CMI8330/C3D"; - default: return "???"; - } -} - -int snd_ad1848_create(struct snd_card *card, - unsigned long port, - int irq, int dma, - unsigned short hardware, - struct snd_ad1848 ** rchip) -{ - static struct snd_device_ops ops = { - .dev_free = snd_ad1848_dev_free, - }; - struct snd_ad1848 *chip; - int err; - - *rchip = NULL; - chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (chip == NULL) - return -ENOMEM; - spin_lock_init(&chip->reg_lock); - chip->card = card; - chip->port = port; - chip->irq = -1; - chip->dma = -1; - chip->hardware = hardware; - memcpy(&chip->image, &snd_ad1848_original_image, sizeof(snd_ad1848_original_image)); - - if ((chip->res_port = request_region(port, 4, "AD1848")) == NULL) { - snd_printk(KERN_ERR "ad1848: can't grab port 0x%lx\n", port); - snd_ad1848_free(chip); - return -EBUSY; - } - if (request_irq(irq, snd_ad1848_interrupt, IRQF_DISABLED, "AD1848", (void *) chip)) { - snd_printk(KERN_ERR "ad1848: can't grab IRQ %d\n", irq); - snd_ad1848_free(chip); - return -EBUSY; - } - chip->irq = irq; - if (request_dma(dma, "AD1848")) { - snd_printk(KERN_ERR "ad1848: can't grab DMA %d\n", dma); - snd_ad1848_free(chip); - return -EBUSY; - } - chip->dma = dma; - - if (hardware == AD1848_HW_THINKPAD) { - chip->thinkpad_flag = 1; - chip->hardware = AD1848_HW_DETECT; /* reset */ - snd_ad1848_thinkpad_twiddle(chip, 1); - } - - if (snd_ad1848_probe(chip) < 0) { - snd_ad1848_free(chip); - return -ENODEV; - } - - /* Register device */ - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { - snd_ad1848_free(chip); - return err; - } - -#ifdef CONFIG_PM - chip->suspend = snd_ad1848_suspend; - chip->resume = snd_ad1848_resume; -#endif - - *rchip = chip; - return 0; -} - -EXPORT_SYMBOL(snd_ad1848_create); - -static struct snd_pcm_ops snd_ad1848_playback_ops = { - .open = snd_ad1848_playback_open, - .close = snd_ad1848_playback_close, - .ioctl = snd_ad1848_ioctl, - .hw_params = snd_ad1848_playback_hw_params, - .hw_free = snd_ad1848_playback_hw_free, - .prepare = snd_ad1848_playback_prepare, - .trigger = snd_ad1848_playback_trigger, - .pointer = snd_ad1848_playback_pointer, -}; - -static struct snd_pcm_ops snd_ad1848_capture_ops = { - .open = snd_ad1848_capture_open, - .close = snd_ad1848_capture_close, - .ioctl = snd_ad1848_ioctl, - .hw_params = snd_ad1848_capture_hw_params, - .hw_free = snd_ad1848_capture_hw_free, - .prepare = snd_ad1848_capture_prepare, - .trigger = snd_ad1848_capture_trigger, - .pointer = snd_ad1848_capture_pointer, -}; - -int snd_ad1848_pcm(struct snd_ad1848 *chip, int device, struct snd_pcm **rpcm) -{ - struct snd_pcm *pcm; - int err; - - if ((err = snd_pcm_new(chip->card, "AD1848", device, 1, 1, &pcm)) < 0) - return err; - - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ad1848_playback_ops); - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ad1848_capture_ops); - - pcm->private_data = chip; - pcm->info_flags = SNDRV_PCM_INFO_HALF_DUPLEX; - strcpy(pcm->name, snd_ad1848_chip_id(chip)); - - snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_isa_data(), - 64*1024, chip->dma > 3 ? 128*1024 : 64*1024); - - chip->pcm = pcm; - if (rpcm) - *rpcm = pcm; - return 0; -} - -EXPORT_SYMBOL(snd_ad1848_pcm); - -const struct snd_pcm_ops *snd_ad1848_get_pcm_ops(int direction) -{ - return direction == SNDRV_PCM_STREAM_PLAYBACK ? - &snd_ad1848_playback_ops : &snd_ad1848_capture_ops; -} - -EXPORT_SYMBOL(snd_ad1848_get_pcm_ops); - -/* - * MIXER part - */ - -static int snd_ad1848_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - static char *texts[4] = { - "Line", "Aux", "Mic", "Mix" - }; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 2; - uinfo->value.enumerated.items = 4; - if (uinfo->value.enumerated.item > 3) - uinfo->value.enumerated.item = 3; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; -} - -static int snd_ad1848_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct snd_ad1848 *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; - - spin_lock_irqsave(&chip->reg_lock, flags); - ucontrol->value.enumerated.item[0] = (chip->image[AD1848_LEFT_INPUT] & AD1848_MIXS_ALL) >> 6; - ucontrol->value.enumerated.item[1] = (chip->image[AD1848_RIGHT_INPUT] & AD1848_MIXS_ALL) >> 6; - spin_unlock_irqrestore(&chip->reg_lock, flags); - return 0; -} - -static int snd_ad1848_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct snd_ad1848 *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; - unsigned short left, right; - int change; - - if (ucontrol->value.enumerated.item[0] > 3 || - ucontrol->value.enumerated.item[1] > 3) - return -EINVAL; - left = ucontrol->value.enumerated.item[0] << 6; - right = ucontrol->value.enumerated.item[1] << 6; - spin_lock_irqsave(&chip->reg_lock, flags); - left = (chip->image[AD1848_LEFT_INPUT] & ~AD1848_MIXS_ALL) | left; - right = (chip->image[AD1848_RIGHT_INPUT] & ~AD1848_MIXS_ALL) | right; - change = left != chip->image[AD1848_LEFT_INPUT] || - right != chip->image[AD1848_RIGHT_INPUT]; - snd_ad1848_out(chip, AD1848_LEFT_INPUT, left); - snd_ad1848_out(chip, AD1848_RIGHT_INPUT, right); - spin_unlock_irqrestore(&chip->reg_lock, flags); - return change; -} - -static int snd_ad1848_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - int mask = (kcontrol->private_value >> 16) & 0xff; - - uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = mask; - return 0; -} - -static int snd_ad1848_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct snd_ad1848 *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; - int reg = kcontrol->private_value & 0xff; - int shift = (kcontrol->private_value >> 8) & 0xff; - int mask = (kcontrol->private_value >> 16) & 0xff; - int invert = (kcontrol->private_value >> 24) & 0xff; - - spin_lock_irqsave(&chip->reg_lock, flags); - ucontrol->value.integer.value[0] = (chip->image[reg] >> shift) & mask; - spin_unlock_irqrestore(&chip->reg_lock, flags); - if (invert) - ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; - return 0; -} - -static int snd_ad1848_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct snd_ad1848 *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; - int reg = kcontrol->private_value & 0xff; - int shift = (kcontrol->private_value >> 8) & 0xff; - int mask = (kcontrol->private_value >> 16) & 0xff; - int invert = (kcontrol->private_value >> 24) & 0xff; - int change; - unsigned short val; - - val = (ucontrol->value.integer.value[0] & mask); - if (invert) - val = mask - val; - val <<= shift; - spin_lock_irqsave(&chip->reg_lock, flags); - val = (chip->image[reg] & ~(mask << shift)) | val; - change = val != chip->image[reg]; - snd_ad1848_out(chip, reg, val); - spin_unlock_irqrestore(&chip->reg_lock, flags); - return change; -} - -static int snd_ad1848_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - int mask = (kcontrol->private_value >> 24) & 0xff; - - uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 2; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = mask; - return 0; -} - -static int snd_ad1848_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct snd_ad1848 *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; - int left_reg = kcontrol->private_value & 0xff; - int right_reg = (kcontrol->private_value >> 8) & 0xff; - int shift_left = (kcontrol->private_value >> 16) & 0x07; - int shift_right = (kcontrol->private_value >> 19) & 0x07; - int mask = (kcontrol->private_value >> 24) & 0xff; - int invert = (kcontrol->private_value >> 22) & 1; - - spin_lock_irqsave(&chip->reg_lock, flags); - ucontrol->value.integer.value[0] = (chip->image[left_reg] >> shift_left) & mask; - ucontrol->value.integer.value[1] = (chip->image[right_reg] >> shift_right) & mask; - spin_unlock_irqrestore(&chip->reg_lock, flags); - if (invert) { - ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; - ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1]; - } - return 0; -} - -static int snd_ad1848_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct snd_ad1848 *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; - int left_reg = kcontrol->private_value & 0xff; - int right_reg = (kcontrol->private_value >> 8) & 0xff; - int shift_left = (kcontrol->private_value >> 16) & 0x07; - int shift_right = (kcontrol->private_value >> 19) & 0x07; - int mask = (kcontrol->private_value >> 24) & 0xff; - int invert = (kcontrol->private_value >> 22) & 1; - int change; - unsigned short val1, val2; - - val1 = ucontrol->value.integer.value[0] & mask; - val2 = ucontrol->value.integer.value[1] & mask; - if (invert) { - val1 = mask - val1; - val2 = mask - val2; - } - val1 <<= shift_left; - val2 <<= shift_right; - spin_lock_irqsave(&chip->reg_lock, flags); - if (left_reg != right_reg) { - val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1; - val2 = (chip->image[right_reg] & ~(mask << shift_right)) | val2; - change = val1 != chip->image[left_reg] || val2 != chip->image[right_reg]; - snd_ad1848_out(chip, left_reg, val1); - snd_ad1848_out(chip, right_reg, val2); - } else { - val1 = (chip->image[left_reg] & ~((mask << shift_left) | (mask << shift_right))) | val1 | val2; - change = val1 != chip->image[left_reg]; - snd_ad1848_out(chip, left_reg, val1); - } - spin_unlock_irqrestore(&chip->reg_lock, flags); - return change; -} - -/* - */ -int snd_ad1848_add_ctl_elem(struct snd_ad1848 *chip, - const struct ad1848_mix_elem *c) -{ - static struct snd_kcontrol_new newctls[] = { - [AD1848_MIX_SINGLE] = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .info = snd_ad1848_info_single, - .get = snd_ad1848_get_single, - .put = snd_ad1848_put_single, - }, - [AD1848_MIX_DOUBLE] = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .info = snd_ad1848_info_double, - .get = snd_ad1848_get_double, - .put = snd_ad1848_put_double, - }, - [AD1848_MIX_CAPTURE] = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .info = snd_ad1848_info_mux, - .get = snd_ad1848_get_mux, - .put = snd_ad1848_put_mux, - }, - }; - struct snd_kcontrol *ctl; - int err; - - ctl = snd_ctl_new1(&newctls[c->type], chip); - if (! ctl) - return -ENOMEM; - strlcpy(ctl->id.name, c->name, sizeof(ctl->id.name)); - ctl->id.index = c->index; - ctl->private_value = c->private_value; - if (c->tlv) { - ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; - ctl->tlv.p = c->tlv; - } - if ((err = snd_ctl_add(chip->card, ctl)) < 0) - return err; - return 0; -} - -EXPORT_SYMBOL(snd_ad1848_add_ctl_elem); - -static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0); -static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0); -static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0); - -static struct ad1848_mix_elem snd_ad1848_controls[] = { -AD1848_DOUBLE("PCM Playback Switch", 0, AD1848_LEFT_OUTPUT, AD1848_RIGHT_OUTPUT, 7, 7, 1, 1), -AD1848_DOUBLE_TLV("PCM Playback Volume", 0, AD1848_LEFT_OUTPUT, AD1848_RIGHT_OUTPUT, 0, 0, 63, 1, - db_scale_6bit), -AD1848_DOUBLE("Aux Playback Switch", 0, AD1848_AUX1_LEFT_INPUT, AD1848_AUX1_RIGHT_INPUT, 7, 7, 1, 1), -AD1848_DOUBLE_TLV("Aux Playback Volume", 0, AD1848_AUX1_LEFT_INPUT, AD1848_AUX1_RIGHT_INPUT, 0, 0, 31, 1, - db_scale_5bit_12db_max), -AD1848_DOUBLE("Aux Playback Switch", 1, AD1848_AUX2_LEFT_INPUT, AD1848_AUX2_RIGHT_INPUT, 7, 7, 1, 1), -AD1848_DOUBLE_TLV("Aux Playback Volume", 1, AD1848_AUX2_LEFT_INPUT, AD1848_AUX2_RIGHT_INPUT, 0, 0, 31, 1, - db_scale_5bit_12db_max), -AD1848_DOUBLE_TLV("Capture Volume", 0, AD1848_LEFT_INPUT, AD1848_RIGHT_INPUT, 0, 0, 15, 0, - db_scale_rec_gain), -{ - .name = "Capture Source", - .type = AD1848_MIX_CAPTURE, -}, -AD1848_SINGLE("Loopback Capture Switch", 0, AD1848_LOOPBACK, 0, 1, 0), -AD1848_SINGLE_TLV("Loopback Capture Volume", 0, AD1848_LOOPBACK, 1, 63, 0, - db_scale_6bit), -}; - -int snd_ad1848_mixer(struct snd_ad1848 *chip) -{ - struct snd_card *card; - struct snd_pcm *pcm; - unsigned int idx; - int err; - - snd_assert(chip != NULL && chip->pcm != NULL, return -EINVAL); - - pcm = chip->pcm; - card = chip->card; - - strcpy(card->mixername, pcm->name); - - for (idx = 0; idx < ARRAY_SIZE(snd_ad1848_controls); idx++) - if ((err = snd_ad1848_add_ctl_elem(chip, &snd_ad1848_controls[idx])) < 0) - return err; - - return 0; -} - -EXPORT_SYMBOL(snd_ad1848_mixer); - -/* - * INIT part - */ - -static int __init alsa_ad1848_init(void) -{ - return 0; -} - -static void __exit alsa_ad1848_exit(void) -{ -} - -module_init(alsa_ad1848_init) -module_exit(alsa_ad1848_exit) diff --git a/sound/isa/azt2320.c b/sound/isa/azt2320.c index 154e728f592..3e74d1a3928 100644 --- a/sound/isa/azt2320.c +++ b/sound/isa/azt2320.c @@ -38,7 +38,7 @@ #include <linux/moduleparam.h> #include <sound/core.h> #include <sound/initval.h> -#include <sound/cs4231.h> +#include <sound/wss.h> #include <sound/mpu401.h> #include <sound/opl3.h> @@ -76,7 +76,7 @@ struct snd_card_azt2320 { int dev_no; struct pnp_dev *dev; struct pnp_dev *devmpu; - struct snd_cs4231 *chip; + struct snd_wss *chip; }; static struct pnp_card_device_id snd_azt2320_pnpids[] = { @@ -181,7 +181,7 @@ static int __devinit snd_card_azt2320_probe(int dev, int error; struct snd_card *card; struct snd_card_azt2320 *acard; - struct snd_cs4231 *chip; + struct snd_wss *chip; struct snd_opl3 *opl3; if ((card = snd_card_new(index[dev], id[dev], THIS_MODULE, @@ -200,11 +200,11 @@ static int __devinit snd_card_azt2320_probe(int dev, return error; } - if ((error = snd_cs4231_create(card, wss_port[dev], -1, - irq[dev], - dma1[dev], - dma2[dev], - CS4231_HW_DETECT, 0, &chip)) < 0) { + error = snd_wss_create(card, wss_port[dev], -1, + irq[dev], + dma1[dev], dma2[dev], + WSS_HW_DETECT, 0, &chip); + if (error < 0) { snd_card_free(card); return error; } @@ -214,15 +214,18 @@ static int __devinit snd_card_azt2320_probe(int dev, sprintf(card->longname, "%s, WSS at 0x%lx, irq %i, dma %i&%i", card->shortname, chip->port, irq[dev], dma1[dev], dma2[dev]); - if ((error = snd_cs4231_pcm(chip, 0, NULL)) < 0) { + error = snd_wss_pcm(chip, 0, NULL); + if (error < 0) { snd_card_free(card); return error; } - if ((error = snd_cs4231_mixer(chip)) < 0) { + error = snd_wss_mixer(chip); + if (error < 0) { snd_card_free(card); return error; } - if ((error = snd_cs4231_timer(chip, 0, NULL)) < 0) { + error = snd_wss_timer(chip, 0, NULL); + if (error < 0) { snd_card_free(card); return error; } @@ -293,7 +296,7 @@ static int snd_azt2320_pnp_suspend(struct pnp_card_link *pcard, pm_message_t sta { struct snd_card *card = pnp_get_card_drvdata(pcard); struct snd_card_azt2320 *acard = card->private_data; - struct snd_cs4231 *chip = acard->chip; + struct snd_wss *chip = acard->chip; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); chip->suspend(chip); @@ -304,7 +307,7 @@ static int snd_azt2320_pnp_resume(struct pnp_card_link *pcard) { struct snd_card *card = pnp_get_card_drvdata(pcard); struct snd_card_azt2320 *acard = card->private_data; - struct snd_cs4231 *chip = acard->chip; + struct snd_wss *chip = acard->chip; chip->resume(chip); snd_power_change_state(card, SNDRV_CTL_POWER_D0); diff --git a/sound/isa/cmi8330.c b/sound/isa/cmi8330.c index 4d198ec71e9..e49aec700a5 100644 --- a/sound/isa/cmi8330.c +++ b/sound/isa/cmi8330.c @@ -50,7 +50,7 @@ #include <linux/pnp.h> #include <linux/moduleparam.h> #include <sound/core.h> -#include <sound/ad1848.h> +#include <sound/wss.h> #include <sound/sb.h> #include <sound/initval.h> @@ -151,7 +151,7 @@ struct snd_cmi8330 { struct pnp_dev *play; #endif struct snd_card *card; - struct snd_ad1848 *wss; + struct snd_wss *wss; struct snd_sb *sb; struct snd_pcm *pcm; @@ -174,32 +174,57 @@ MODULE_DEVICE_TABLE(pnp_card, snd_cmi8330_pnpids); #endif -static struct ad1848_mix_elem snd_cmi8330_controls[] __devinitdata = { -AD1848_DOUBLE("Master Playback Volume", 0, CMI8330_MASTVOL, CMI8330_MASTVOL, 4, 0, 15, 0), -AD1848_SINGLE("Loud Playback Switch", 0, CMI8330_MUTEMUX, 6, 1, 1), -AD1848_DOUBLE("PCM Playback Switch", 0, AD1848_LEFT_OUTPUT, AD1848_RIGHT_OUTPUT, 7, 7, 1, 1), -AD1848_DOUBLE("PCM Playback Volume", 0, AD1848_LEFT_OUTPUT, AD1848_RIGHT_OUTPUT, 0, 0, 63, 1), -AD1848_DOUBLE("Line Playback Switch", 0, CMI8330_MUTEMUX, CMI8330_MUTEMUX, 4, 3, 1, 0), -AD1848_DOUBLE("Line Playback Volume", 0, CMI8330_LINVOL, CMI8330_LINVOL, 4, 0, 15, 0), -AD1848_DOUBLE("Line Capture Switch", 0, CMI8330_RMUX3D, CMI8330_RMUX3D, 2, 1, 1, 0), -AD1848_DOUBLE("Line Capture Volume", 0, CMI8330_LINGAIN, CMI8330_LINGAIN, 4, 0, 15, 0), -AD1848_DOUBLE("CD Playback Switch", 0, CMI8330_MUTEMUX, CMI8330_MUTEMUX, 2, 1, 1, 0), -AD1848_DOUBLE("CD Capture Switch", 0, CMI8330_RMUX3D, CMI8330_RMUX3D, 4, 3, 1, 0), -AD1848_DOUBLE("CD Playback Volume", 0, CMI8330_CDINVOL, CMI8330_CDINVOL, 4, 0, 15, 0), -AD1848_DOUBLE("CD Capture Volume", 0, CMI8330_CDINGAIN, CMI8330_CDINGAIN, 4, 0, 15, 0), -AD1848_SINGLE("Mic Playback Switch", 0, CMI8330_MUTEMUX, 0, 1, 0), -AD1848_SINGLE("Mic Playback Volume", 0, CMI8330_OUTPUTVOL, 0, 7, 0), -AD1848_SINGLE("Mic Capture Switch", 0, CMI8330_RMUX3D, 0, 1, 0), -AD1848_SINGLE("Mic Capture Volume", 0, CMI8330_OUTPUTVOL, 5, 7, 0), -AD1848_DOUBLE("Wavetable Playback Switch", 0, CMI8330_RECMUX, CMI8330_RECMUX, 1, 0, 1, 0), -AD1848_DOUBLE("Wavetable Playback Volume", 0, CMI8330_WAVVOL, CMI8330_WAVVOL, 4, 0, 15, 0), -AD1848_DOUBLE("Wavetable Capture Switch", 0, CMI8330_RECMUX, CMI8330_RECMUX, 5, 4, 1, 0), -AD1848_DOUBLE("Wavetable Capture Volume", 0, CMI8330_WAVGAIN, CMI8330_WAVGAIN, 4, 0, 15, 0), -AD1848_SINGLE("3D Control - Switch", 0, CMI8330_RMUX3D, 5, 1, 1), -AD1848_SINGLE("PC Speaker Playback Volume", 0, CMI8330_OUTPUTVOL, 3, 3, 0), -AD1848_SINGLE("FM Playback Switch", 0, CMI8330_RECMUX, 3, 1, 1), -AD1848_SINGLE(SNDRV_CTL_NAME_IEC958("Input ",CAPTURE,SWITCH), 0, CMI8330_RMUX3D, 7, 1, 1), -AD1848_SINGLE(SNDRV_CTL_NAME_IEC958("Input ",PLAYBACK,SWITCH), 0, CMI8330_MUTEMUX, 7, 1, 1), +static struct snd_kcontrol_new snd_cmi8330_controls[] __devinitdata = { +WSS_DOUBLE("Master Playback Volume", 0, + CMI8330_MASTVOL, CMI8330_MASTVOL, 4, 0, 15, 0), +WSS_SINGLE("Loud Playback Switch", 0, + CMI8330_MUTEMUX, 6, 1, 1), +WSS_DOUBLE("PCM Playback Switch", 0, + CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1), +WSS_DOUBLE("PCM Playback Volume", 0, + CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1), +WSS_DOUBLE("Line Playback Switch", 0, + CMI8330_MUTEMUX, CMI8330_MUTEMUX, 4, 3, 1, 0), +WSS_DOUBLE("Line Playback Volume", 0, + CMI8330_LINVOL, CMI8330_LINVOL, 4, 0, 15, 0), +WSS_DOUBLE("Line Capture Switch", 0, + CMI8330_RMUX3D, CMI8330_RMUX3D, 2, 1, 1, 0), +WSS_DOUBLE("Line Capture Volume", 0, + CMI8330_LINGAIN, CMI8330_LINGAIN, 4, 0, 15, 0), +WSS_DOUBLE("CD Playback Switch", 0, + CMI8330_MUTEMUX, CMI8330_MUTEMUX, 2, 1, 1, 0), +WSS_DOUBLE("CD Capture Switch", 0, + CMI8330_RMUX3D, CMI8330_RMUX3D, 4, 3, 1, 0), +WSS_DOUBLE("CD Playback Volume", 0, + CMI8330_CDINVOL, CMI8330_CDINVOL, 4, 0, 15, 0), +WSS_DOUBLE("CD Capture Volume", 0, + CMI8330_CDINGAIN, CMI8330_CDINGAIN, 4, 0, 15, 0), +WSS_SINGLE("Mic Playback Switch", 0, + CMI8330_MUTEMUX, 0, 1, 0), +WSS_SINGLE("Mic Playback Volume", 0, + CMI8330_OUTPUTVOL, 0, 7, 0), +WSS_SINGLE("Mic Capture Switch", 0, + CMI8330_RMUX3D, 0, 1, 0), +WSS_SINGLE("Mic Capture Volume", 0, + CMI8330_OUTPUTVOL, 5, 7, 0), +WSS_DOUBLE("Wavetable Playback Switch", 0, + CMI8330_RECMUX, CMI8330_RECMUX, 1, 0, 1, 0), +WSS_DOUBLE("Wavetable Playback Volume", 0, + CMI8330_WAVVOL, CMI8330_WAVVOL, 4, 0, 15, 0), +WSS_DOUBLE("Wavetable Capture Switch", 0, + CMI8330_RECMUX, CMI8330_RECMUX, 5, 4, 1, 0), +WSS_DOUBLE("Wavetable Capture Volume", 0, + CMI8330_WAVGAIN, CMI8330_WAVGAIN, 4, 0, 15, 0), +WSS_SINGLE("3D Control - Switch", 0, + CMI8330_RMUX3D, 5, 1, 1), +WSS_SINGLE("PC Speaker Playback Volume", 0, + CMI8330_OUTPUTVOL, 3, 3, 0), +WSS_SINGLE("FM Playback Switch", 0, + CMI8330_RECMUX, 3, 1, 1), +WSS_SINGLE(SNDRV_CTL_NAME_IEC958("Input ", CAPTURE, SWITCH), 0, + CMI8330_RMUX3D, 7, 1, 1), +WSS_SINGLE(SNDRV_CTL_NAME_IEC958("Input ", PLAYBACK, SWITCH), 0, + CMI8330_MUTEMUX, 7, 1, 1), }; #ifdef ENABLE_SB_MIXER @@ -268,7 +293,10 @@ static int __devinit snd_cmi8330_mixer(struct snd_card *card, struct snd_cmi8330 strcpy(card->mixername, "CMI8330/C3D"); for (idx = 0; idx < ARRAY_SIZE(snd_cmi8330_controls); idx++) { - if ((err = snd_ad1848_add_ctl_elem(acard->wss, &snd_cmi8330_controls[idx])) < 0) + err = snd_ctl_add(card, + snd_ctl_new1(&snd_cmi8330_controls[idx], + acard->wss)); + if (err < 0) return err; } @@ -385,7 +413,7 @@ static int __devinit snd_cmi8330_pcm(struct snd_card *card, struct snd_cmi8330 * chip->streams[CMI_SB_STREAM].private_data = chip->sb; /* AD1848 */ - ops = snd_ad1848_get_pcm_ops(CMI_AD_STREAM); + ops = snd_wss_get_pcm_ops(CMI_AD_STREAM); chip->streams[CMI_AD_STREAM].ops = *ops; chip->streams[CMI_AD_STREAM].open = ops->open; chip->streams[CMI_AD_STREAM].ops.open = cmi_open_callbacks[CMI_AD_STREAM]; @@ -461,16 +489,15 @@ static int __devinit snd_cmi8330_probe(struct snd_card *card, int dev) int i, err; acard = card->private_data; - if ((err = snd_ad1848_create(card, - wssport[dev] + 4, - wssirq[dev], - wssdma[dev], - AD1848_HW_DETECT, - &acard->wss)) < 0) { + err = snd_wss_create(card, wssport[dev] + 4, -1, + wssirq[dev], + wssdma[dev], -1, + WSS_HW_DETECT, 0, &acard->wss); + if (err < 0) { snd_printk(KERN_ERR PFX "(AD1848) device busy??\n"); return err; } - if (acard->wss->hardware != AD1848_HW_CMI8330) { + if (acard->wss->hardware != WSS_HW_CMI8330) { snd_printk(KERN_ERR PFX "(AD1848) not found during probe\n"); return -ENODEV; } @@ -489,9 +516,10 @@ static int __devinit snd_cmi8330_probe(struct snd_card *card, int dev) return err; } - snd_ad1848_out(acard->wss, AD1848_MISC_INFO, 0x40); /* switch on MODE2 */ + snd_wss_out(acard->wss, CS4231_MISC_INFO, 0x40); /* switch on MODE2 */ for (i = CMI8330_RMUX3D; i <= CMI8330_CDINGAIN; i++) - snd_ad1848_out(acard->wss, i, snd_cmi8330_image[i - CMI8330_RMUX3D]); + snd_wss_out(acard->wss, i, + snd_cmi8330_image[i - CMI8330_RMUX3D]); if ((err = snd_cmi8330_mixer(card, acard)) < 0) { snd_printk(KERN_ERR PFX "failed to create mixers\n"); diff --git a/sound/isa/cs423x/Makefile b/sound/isa/cs423x/Makefile index 5067ee00193..5870ca21ab5 100644 --- a/sound/isa/cs423x/Makefile +++ b/sound/isa/cs423x/Makefile @@ -3,14 +3,12 @@ # Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz> # -snd-cs4231-lib-objs := cs4231_lib.o snd-cs4236-lib-objs := cs4236_lib.o snd-cs4231-objs := cs4231.o snd-cs4232-objs := cs4232.o snd-cs4236-objs := cs4236.o # Toplevel Module Dependency -obj-$(CONFIG_SND_CS4231_LIB) += snd-cs4231-lib.o obj-$(CONFIG_SND_CS4231) += snd-cs4231.o obj-$(CONFIG_SND_CS4232) += snd-cs4232.o obj-$(CONFIG_SND_CS4236) += snd-cs4236.o snd-cs4236-lib.o diff --git a/sound/isa/cs423x/cs4231.c b/sound/isa/cs423x/cs4231.c index e9462b9944b..ddd289120aa 100644 --- a/sound/isa/cs423x/cs4231.c +++ b/sound/isa/cs423x/cs4231.c @@ -27,7 +27,7 @@ #include <linux/wait.h> #include <linux/moduleparam.h> #include <sound/core.h> -#include <sound/cs4231.h> +#include <sound/wss.h> #include <sound/mpu401.h> #include <sound/initval.h> @@ -91,7 +91,7 @@ static int __devinit snd_cs4231_match(struct device *dev, unsigned int n) static int __devinit snd_cs4231_probe(struct device *dev, unsigned int n) { struct snd_card *card; - struct snd_cs4231 *chip; + struct snd_wss *chip; struct snd_pcm *pcm; int error; @@ -99,14 +99,14 @@ static int __devinit snd_cs4231_probe(struct device *dev, unsigned int n) if (!card) return -EINVAL; - error = snd_cs4231_create(card, port[n], -1, irq[n], dma1[n], dma2[n], - CS4231_HW_DETECT, 0, &chip); + error = snd_wss_create(card, port[n], -1, irq[n], dma1[n], dma2[n], + WSS_HW_DETECT, 0, &chip); if (error < 0) goto out; card->private_data = chip; - error = snd_cs4231_pcm(chip, 0, &pcm); + error = snd_wss_pcm(chip, 0, &pcm); if (error < 0) goto out; @@ -118,11 +118,11 @@ static int __devinit snd_cs4231_probe(struct device *dev, unsigned int n) if (dma2[n] >= 0) sprintf(card->longname + strlen(card->longname), "&%d", dma2[n]); - error = snd_cs4231_mixer(chip); + error = snd_wss_mixer(chip); if (error < 0) goto out; - error = snd_cs4231_timer(chip, 0, NULL); + error = snd_wss_timer(chip, 0, NULL); if (error < 0) goto out; @@ -160,7 +160,7 @@ static int __devexit snd_cs4231_remove(struct device *dev, unsigned int n) static int snd_cs4231_suspend(struct device *dev, unsigned int n, pm_message_t state) { struct snd_card *card = dev_get_drvdata(dev); - struct snd_cs4231 *chip = card->private_data; + struct snd_wss *chip = card->private_data; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); chip->suspend(chip); @@ -170,7 +170,7 @@ static int snd_cs4231_suspend(struct device *dev, unsigned int n, pm_message_t s static int snd_cs4231_resume(struct device *dev, unsigned int n) { struct snd_card *card = dev_get_drvdata(dev); - struct snd_cs4231 *chip = card->private_data; + struct snd_wss *chip = card->private_data; chip->resume(chip); snd_power_change_state(card, SNDRV_CTL_POWER_D0); diff --git a/sound/isa/cs423x/cs4231_lib.c b/sound/isa/cs423x/cs4231_lib.c deleted file mode 100644 index 521db705d17..00000000000 --- a/sound/isa/cs423x/cs4231_lib.c +++ /dev/null @@ -1,1945 +0,0 @@ -/* - * Copyright (c) by Jaroslav Kysela <perex@perex.cz> - * Routines for control of CS4231(A)/CS4232/InterWave & compatible chips - * - * Bugs: - * - sometimes record brokes playback with WSS portion of - * Yamaha OPL3-SA3 chip - * - CS4231 (GUS MAX) - still trouble with occasional noises - * - broken initialization? - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include <linux/delay.h> -#include <linux/pm.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/slab.h> -#include <linux/ioport.h> -#include <sound/core.h> -#include <sound/cs4231.h> -#include <sound/pcm_params.h> - -#include <asm/io.h> -#include <asm/dma.h> -#include <asm/irq.h> - -MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); -MODULE_DESCRIPTION("Routines for control of CS4231(A)/CS4232/InterWave & compatible chips"); -MODULE_LICENSE("GPL"); - -#if 0 -#define SNDRV_DEBUG_MCE -#endif - -/* - * Some variables - */ - -static unsigned char freq_bits[14] = { - /* 5510 */ 0x00 | CS4231_XTAL2, - /* 6620 */ 0x0E | CS4231_XTAL2, - /* 8000 */ 0x00 | CS4231_XTAL1, - /* 9600 */ 0x0E | CS4231_XTAL1, - /* 11025 */ 0x02 | CS4231_XTAL2, - /* 16000 */ 0x02 | CS4231_XTAL1, - /* 18900 */ 0x04 | CS4231_XTAL2, - /* 22050 */ 0x06 | CS4231_XTAL2, - /* 27042 */ 0x04 | CS4231_XTAL1, - /* 32000 */ 0x06 | CS4231_XTAL1, - /* 33075 */ 0x0C | CS4231_XTAL2, - /* 37800 */ 0x08 | CS4231_XTAL2, - /* 44100 */ 0x0A | CS4231_XTAL2, - /* 48000 */ 0x0C | CS4231_XTAL1 -}; - -static unsigned int rates[14] = { - 5510, 6620, 8000, 9600, 11025, 16000, 18900, 22050, - 27042, 32000, 33075, 37800, 44100, 48000 -}; - -static struct snd_pcm_hw_constraint_list hw_constraints_rates = { - .count = ARRAY_SIZE(rates), - .list = rates, - .mask = 0, -}; - -static int snd_cs4231_xrate(struct snd_pcm_runtime *runtime) -{ - return snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); -} - -static unsigned char snd_cs4231_original_image[32] = -{ - 0x00, /* 00/00 - lic */ - 0x00, /* 01/01 - ric */ - 0x9f, /* 02/02 - la1ic */ - 0x9f, /* 03/03 - ra1ic */ - 0x9f, /* 04/04 - la2ic */ - 0x9f, /* 05/05 - ra2ic */ - 0xbf, /* 06/06 - loc */ - 0xbf, /* 07/07 - roc */ - 0x20, /* 08/08 - pdfr */ - CS4231_AUTOCALIB, /* 09/09 - ic */ - 0x00, /* 0a/10 - pc */ - 0x00, /* 0b/11 - ti */ - CS4231_MODE2, /* 0c/12 - mi */ - 0xfc, /* 0d/13 - lbc */ - 0x00, /* 0e/14 - pbru */ - 0x00, /* 0f/15 - pbrl */ - 0x80, /* 10/16 - afei */ - 0x01, /* 11/17 - afeii */ - 0x9f, /* 12/18 - llic */ - 0x9f, /* 13/19 - rlic */ - 0x00, /* 14/20 - tlb */ - 0x00, /* 15/21 - thb */ - 0x00, /* 16/22 - la3mic/reserved */ - 0x00, /* 17/23 - ra3mic/reserved */ - 0x00, /* 18/24 - afs */ - 0x00, /* 19/25 - lamoc/version */ - 0xcf, /* 1a/26 - mioc */ - 0x00, /* 1b/27 - ramoc/reserved */ - 0x20, /* 1c/28 - cdfr */ - 0x00, /* 1d/29 - res4 */ - 0x00, /* 1e/30 - cbru */ - 0x00, /* 1f/31 - cbrl */ -}; - -static unsigned char snd_opti93x_original_image[32] = -{ - 0x00, /* 00/00 - l_mixout_outctrl */ - 0x00, /* 01/01 - r_mixout_outctrl */ - 0x88, /* 02/02 - l_cd_inctrl */ - 0x88, /* 03/03 - r_cd_inctrl */ - 0x88, /* 04/04 - l_a1/fm_inctrl */ - 0x88, /* 05/05 - r_a1/fm_inctrl */ - 0x80, /* 06/06 - l_dac_inctrl */ - 0x80, /* 07/07 - r_dac_inctrl */ - 0x00, /* 08/08 - ply_dataform_reg */ - 0x00, /* 09/09 - if_conf */ - 0x00, /* 0a/10 - pin_ctrl */ - 0x00, /* 0b/11 - err_init_reg */ - 0x0a, /* 0c/12 - id_reg */ - 0x00, /* 0d/13 - reserved */ - 0x00, /* 0e/14 - ply_upcount_reg */ - 0x00, /* 0f/15 - ply_lowcount_reg */ - 0x88, /* 10/16 - reserved/l_a1_inctrl */ - 0x88, /* 11/17 - reserved/r_a1_inctrl */ - 0x88, /* 12/18 - l_line_inctrl */ - 0x88, /* 13/19 - r_line_inctrl */ - 0x88, /* 14/20 - l_mic_inctrl */ - 0x88, /* 15/21 - r_mic_inctrl */ - 0x80, /* 16/22 - l_out_outctrl */ - 0x80, /* 17/23 - r_out_outctrl */ - 0x00, /* 18/24 - reserved */ - 0x00, /* 19/25 - reserved */ - 0x00, /* 1a/26 - reserved */ - 0x00, /* 1b/27 - reserved */ - 0x00, /* 1c/28 - cap_dataform_reg */ - 0x00, /* 1d/29 - reserved */ - 0x00, /* 1e/30 - cap_upcount_reg */ - 0x00 /* 1f/31 - cap_lowcount_reg */ -}; - -/* - * Basic I/O functions - */ - -static inline void cs4231_outb(struct snd_cs4231 *chip, u8 offset, u8 val) -{ - outb(val, chip->port + offset); -} - -static inline u8 cs4231_inb(struct snd_cs4231 *chip, u8 offset) -{ - return inb(chip->port + offset); -} - -static void snd_cs4231_wait(struct snd_cs4231 *chip) -{ - int timeout; - - for (timeout = 250; - timeout > 0 && (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT); - timeout--) - udelay(100); -} - -static void snd_cs4231_outm(struct snd_cs4231 *chip, unsigned char reg, - unsigned char mask, unsigned char value) -{ - unsigned char tmp = (chip->image[reg] & mask) | value; - - snd_cs4231_wait(chip); -#ifdef CONFIG_SND_DEBUG - if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) - snd_printk("outm: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value); -#endif - chip->image[reg] = tmp; - if (!chip->calibrate_mute) { - cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg); - wmb(); - cs4231_outb(chip, CS4231P(REG), tmp); - mb(); - } -} - -static void snd_cs4231_dout(struct snd_cs4231 *chip, unsigned char reg, unsigned char value) -{ - int timeout; - - for (timeout = 250; - timeout > 0 && (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT); - timeout--) - udelay(10); - cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg); - cs4231_outb(chip, CS4231P(REG), value); - mb(); -} - -void snd_cs4231_out(struct snd_cs4231 *chip, unsigned char reg, unsigned char value) -{ - snd_cs4231_wait(chip); -#ifdef CONFIG_SND_DEBUG - if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) - snd_printk("out: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value); -#endif - cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg); - cs4231_outb(chip, CS4231P(REG), value); - chip->image[reg] = value; - mb(); - snd_printdd("codec out - reg 0x%x = 0x%x\n", - chip->mce_bit | reg, value); -} - -unsigned char snd_cs4231_in(struct snd_cs4231 *chip, unsigned char reg) -{ - snd_cs4231_wait(chip); -#ifdef CONFIG_SND_DEBUG - if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) - snd_printk("in: auto calibration time out - reg = 0x%x\n", reg); -#endif - cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg); - mb(); - return cs4231_inb(chip, CS4231P(REG)); -} - -void snd_cs4236_ext_out(struct snd_cs4231 *chip, unsigned char reg, unsigned char val) -{ - cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | 0x17); - cs4231_outb(chip, CS4231P(REG), reg | (chip->image[CS4236_EXT_REG] & 0x01)); - cs4231_outb(chip, CS4231P(REG), val); - chip->eimage[CS4236_REG(reg)] = val; -#if 0 - printk("ext out : reg = 0x%x, val = 0x%x\n", reg, val); -#endif -} - -unsigned char snd_cs4236_ext_in(struct snd_cs4231 *chip, unsigned char reg) -{ - cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | 0x17); - cs4231_outb(chip, CS4231P(REG), reg | (chip->image[CS4236_EXT_REG] & 0x01)); -#if 1 - return cs4231_inb(chip, CS4231P(REG)); -#else - { - unsigned char res; - res = cs4231_inb(chip, CS4231P(REG)); - printk("ext in : reg = 0x%x, val = 0x%x\n", reg, res); - return res; - } -#endif -} - -#if 0 - -static void snd_cs4231_debug(struct snd_cs4231 *chip) -{ - printk("CS4231 REGS: INDEX = 0x%02x ", cs4231_inb(chip, CS4231P(REGSEL))); - printk(" STATUS = 0x%02x\n", cs4231_inb(chip, CS4231P(STATUS))); - printk(" 0x00: left input = 0x%02x ", snd_cs4231_in(chip, 0x00)); - printk(" 0x10: alt 1 (CFIG 2) = 0x%02x\n", snd_cs4231_in(chip, 0x10)); - printk(" 0x01: right input = 0x%02x ", snd_cs4231_in(chip, 0x01)); - printk(" 0x11: alt 2 (CFIG 3) = 0x%02x\n", snd_cs4231_in(chip, 0x11)); - printk(" 0x02: GF1 left input = 0x%02x ", snd_cs4231_in(chip, 0x02)); - printk(" 0x12: left line in = 0x%02x\n", snd_cs4231_in(chip, 0x12)); - printk(" 0x03: GF1 right input = 0x%02x ", snd_cs4231_in(chip, 0x03)); - printk(" 0x13: right line in = 0x%02x\n", snd_cs4231_in(chip, 0x13)); - printk(" 0x04: CD left input = 0x%02x ", snd_cs4231_in(chip, 0x04)); - printk(" 0x14: timer low = 0x%02x\n", snd_cs4231_in(chip, 0x14)); - printk(" 0x05: CD right input = 0x%02x ", snd_cs4231_in(chip, 0x05)); - printk(" 0x15: timer high = 0x%02x\n", snd_cs4231_in(chip, 0x15)); - printk(" 0x06: left output = 0x%02x ", snd_cs4231_in(chip, 0x06)); - printk(" 0x16: left MIC (PnP) = 0x%02x\n", snd_cs4231_in(chip, 0x16)); - printk(" 0x07: right output = 0x%02x ", snd_cs4231_in(chip, 0x07)); - printk(" 0x17: right MIC (PnP) = 0x%02x\n", snd_cs4231_in(chip, 0x17)); - printk(" 0x08: playback format = 0x%02x ", snd_cs4231_in(chip, 0x08)); - printk(" 0x18: IRQ status = 0x%02x\n", snd_cs4231_in(chip, 0x18)); - printk(" 0x09: iface (CFIG 1) = 0x%02x ", snd_cs4231_in(chip, 0x09)); - printk(" 0x19: left line out = 0x%02x\n", snd_cs4231_in(chip, 0x19)); - printk(" 0x0a: pin control = 0x%02x ", snd_cs4231_in(chip, 0x0a)); - printk(" 0x1a: mono control = 0x%02x\n", snd_cs4231_in(chip, 0x1a)); - printk(" 0x0b: init & status = 0x%02x ", snd_cs4231_in(chip, 0x0b)); - printk(" 0x1b: right line out = 0x%02x\n", snd_cs4231_in(chip, 0x1b)); - printk(" 0x0c: revision & mode = 0x%02x ", snd_cs4231_in(chip, 0x0c)); - printk(" 0x1c: record format = 0x%02x\n", snd_cs4231_in(chip, 0x1c)); - printk(" 0x0d: loopback = 0x%02x ", snd_cs4231_in(chip, 0x0d)); - printk(" 0x1d: var freq (PnP) = 0x%02x\n", snd_cs4231_in(chip, 0x1d)); - printk(" 0x0e: ply upr count = 0x%02x ", snd_cs4231_in(chip, 0x0e)); - printk(" 0x1e: ply lwr count = 0x%02x\n", snd_cs4231_in(chip, 0x1e)); - printk(" 0x0f: rec upr count = 0x%02x ", snd_cs4231_in(chip, 0x0f)); - printk(" 0x1f: rec lwr count = 0x%02x\n", snd_cs4231_in(chip, 0x1f)); -} - -#endif - -/* - * CS4231 detection / MCE routines - */ - -static void snd_cs4231_busy_wait(struct snd_cs4231 *chip) -{ - int timeout; - - /* huh.. looks like this sequence is proper for CS4231A chip (GUS MAX) */ - for (timeout = 5; timeout > 0; timeout--) - cs4231_inb(chip, CS4231P(REGSEL)); - /* end of cleanup sequence */ - for (timeout = 250; - timeout > 0 && (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT); - timeout--) - udelay(10); -} - -void snd_cs4231_mce_up(struct snd_cs4231 *chip) -{ - unsigned long flags; - int timeout; - - snd_cs4231_wait(chip); -#ifdef CONFIG_SND_DEBUG - if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) - snd_printk("mce_up - auto calibration time out (0)\n"); -#endif - spin_lock_irqsave(&chip->reg_lock, flags); - chip->mce_bit |= CS4231_MCE; - timeout = cs4231_inb(chip, CS4231P(REGSEL)); - if (timeout == 0x80) - snd_printk("mce_up [0x%lx]: serious init problem - codec still busy\n", chip->port); - if (!(timeout & CS4231_MCE)) - cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | (timeout & 0x1f)); - spin_unlock_irqrestore(&chip->reg_lock, flags); -} - -void snd_cs4231_mce_down(struct snd_cs4231 *chip) -{ - unsigned long flags; - unsigned long end_time; - int timeout; - - snd_cs4231_busy_wait(chip); - -#ifdef CONFIG_SND_DEBUG - if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) - snd_printk("mce_down [0x%lx] - auto calibration time out (0)\n", (long)CS4231P(REGSEL)); -#endif - spin_lock_irqsave(&chip->reg_lock, flags); - chip->mce_bit &= ~CS4231_MCE; - timeout = cs4231_inb(chip, CS4231P(REGSEL)); - cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | (timeout & 0x1f)); - spin_unlock_irqrestore(&chip->reg_lock, flags); - if (timeout == 0x80) - snd_printk("mce_down [0x%lx]: serious init problem - codec still busy\n", chip->port); - if ((timeout & CS4231_MCE) == 0 || - !(chip->hardware & (CS4231_HW_CS4231_MASK | CS4231_HW_CS4232_MASK))) { - return; - } - - /* - * Wait for (possible -- during init auto-calibration may not be set) - * calibration process to start. Needs upto 5 sample periods on AD1848 - * which at the slowest possible rate of 5.5125 kHz means 907 us. - */ - msleep(1); - - snd_printdd("(1) jiffies = %lu\n", jiffies); - - /* check condition up to 250 ms */ - end_time = jiffies + msecs_to_jiffies(250); - while (snd_cs4231_in(chip, CS4231_TEST_INIT) & - CS4231_CALIB_IN_PROGRESS) { - - if (time_after(jiffies, end_time)) { - snd_printk(KERN_ERR "mce_down - " - "auto calibration time out (2)\n"); - return; - } - msleep(1); - } - - snd_printdd("(2) jiffies = %lu\n", jiffies); - - /* check condition up to 100 ms */ - end_time = jiffies + msecs_to_jiffies(100); - while (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) { - if (time_after(jiffies, end_time)) { - snd_printk(KERN_ERR "mce_down - auto calibration time out (3)\n"); - return; - } - msleep(1); - } - - snd_printdd("(3) jiffies = %lu\n", jiffies); - snd_printd("mce_down - exit = 0x%x\n", cs4231_inb(chip, CS4231P(REGSEL))); -} - -static unsigned int snd_cs4231_get_count(unsigned char format, unsigned int size) -{ - switch (format & 0xe0) { - case CS4231_LINEAR_16: - case CS4231_LINEAR_16_BIG: - size >>= 1; - break; - case CS4231_ADPCM_16: - return size >> 2; - } - if (format & CS4231_STEREO) - size >>= 1; - return size; -} - -static int snd_cs4231_trigger(struct snd_pcm_substream *substream, - int cmd) -{ - struct snd_cs4231 *chip = snd_pcm_substream_chip(substream); - int result = 0; - unsigned int what; - struct snd_pcm_substream *s; - int do_start; - -#if 0 - printk("codec trigger!!! - what = %i, enable = %i, status = 0x%x\n", what, enable, cs4231_inb(chip, CS4231P(STATUS))); -#endif - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - do_start = 1; break; - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - do_start = 0; break; - default: - return -EINVAL; - } - - what = 0; - snd_pcm_group_for_each_entry(s, substream) { - if (s == chip->playback_substream) { - what |= CS4231_PLAYBACK_ENABLE; - snd_pcm_trigger_done(s, substream); - } else if (s == chip->capture_substream) { - what |= CS4231_RECORD_ENABLE; - snd_pcm_trigger_done(s, substream); - } - } - spin_lock(&chip->reg_lock); - if (do_start) { - chip->image[CS4231_IFACE_CTRL] |= what; - if (chip->trigger) - chip->trigger(chip, what, 1); - } else { - chip->image[CS4231_IFACE_CTRL] &= ~what; - if (chip->trigger) - chip->trigger(chip, what, 0); - } - snd_cs4231_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]); - spin_unlock(&chip->reg_lock); -#if 0 - snd_cs4231_debug(chip); -#endif - return result; -} - -/* - * CODEC I/O - */ - -static unsigned char snd_cs4231_get_rate(unsigned int rate) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(rates); i++) - if (rate == rates[i]) - return freq_bits[i]; - // snd_BUG(); - return freq_bits[ARRAY_SIZE(rates) - 1]; -} - -static unsigned char snd_cs4231_get_format(struct snd_cs4231 *chip, - int format, - int channels) -{ - unsigned char rformat; - - rformat = CS4231_LINEAR_8; - switch (format) { - case SNDRV_PCM_FORMAT_MU_LAW: rformat = CS4231_ULAW_8; break; - case SNDRV_PCM_FORMAT_A_LAW: rformat = CS4231_ALAW_8; break; - case SNDRV_PCM_FORMAT_S16_LE: rformat = CS4231_LINEAR_16; break; - case SNDRV_PCM_FORMAT_S16_BE: rformat = CS4231_LINEAR_16_BIG; break; - case SNDRV_PCM_FORMAT_IMA_ADPCM: rformat = CS4231_ADPCM_16; break; - } - if (channels > 1) - rformat |= CS4231_STEREO; -#if 0 - snd_printk("get_format: 0x%x (mode=0x%x)\n", format, mode); -#endif - return rformat; -} - -static void snd_cs4231_calibrate_mute(struct snd_cs4231 *chip, int mute) -{ - unsigned long flags; - - mute = mute ? 1 : 0; - spin_lock_irqsave(&chip->reg_lock, flags); - if (chip->calibrate_mute == mute) { - spin_unlock_irqrestore(&chip->reg_lock, flags); - return; - } - if (!mute) { - snd_cs4231_dout(chip, CS4231_LEFT_INPUT, chip->image[CS4231_LEFT_INPUT]); - snd_cs4231_dout(chip, CS4231_RIGHT_INPUT, chip->image[CS4231_RIGHT_INPUT]); - snd_cs4231_dout(chip, CS4231_LOOPBACK, chip->image[CS4231_LOOPBACK]); - } - snd_cs4231_dout(chip, CS4231_AUX1_LEFT_INPUT, mute ? 0x80 : chip->image[CS4231_AUX1_LEFT_INPUT]); - snd_cs4231_dout(chip, CS4231_AUX1_RIGHT_INPUT, mute ? 0x80 : chip->image[CS4231_AUX1_RIGHT_INPUT]); - snd_cs4231_dout(chip, CS4231_AUX2_LEFT_INPUT, mute ? 0x80 : chip->image[CS4231_AUX2_LEFT_INPUT]); - snd_cs4231_dout(chip, CS4231_AUX2_RIGHT_INPUT, mute ? 0x80 : chip->image[CS4231_AUX2_RIGHT_INPUT]); - snd_cs4231_dout(chip, CS4231_LEFT_OUTPUT, mute ? 0x80 : chip->image[CS4231_LEFT_OUTPUT]); - snd_cs4231_dout(chip, CS4231_RIGHT_OUTPUT, mute ? 0x80 : chip->image[CS4231_RIGHT_OUTPUT]); - snd_cs4231_dout(chip, CS4231_LEFT_LINE_IN, mute ? 0x80 : chip->image[CS4231_LEFT_LINE_IN]); - snd_cs4231_dout(chip, CS4231_RIGHT_LINE_IN, mute ? 0x80 : chip->image[CS4231_RIGHT_LINE_IN]); - snd_cs4231_dout(chip, CS4231_MONO_CTRL, mute ? 0xc0 : chip->image[CS4231_MONO_CTRL]); - if (chip->hardware == CS4231_HW_INTERWAVE) { - snd_cs4231_dout(chip, CS4231_LEFT_MIC_INPUT, mute ? 0x80 : chip->image[CS4231_LEFT_MIC_INPUT]); - snd_cs4231_dout(chip, CS4231_RIGHT_MIC_INPUT, mute ? 0x80 : chip->image[CS4231_RIGHT_MIC_INPUT]); - snd_cs4231_dout(chip, CS4231_LINE_LEFT_OUTPUT, mute ? 0x80 : chip->image[CS4231_LINE_LEFT_OUTPUT]); - snd_cs4231_dout(chip, CS4231_LINE_RIGHT_OUTPUT, mute ? 0x80 : chip->image[CS4231_LINE_RIGHT_OUTPUT]); - } - chip->calibrate_mute = mute; - spin_unlock_irqrestore(&chip->reg_lock, flags); -} - -static void snd_cs4231_playback_format(struct snd_cs4231 *chip, - struct snd_pcm_hw_params *params, - unsigned char pdfr) -{ - unsigned long flags; - int full_calib = 1; - - mutex_lock(&chip->mce_mutex); - snd_cs4231_calibrate_mute(chip, 1); - if (chip->hardware == CS4231_HW_CS4231A || - (chip->hardware & CS4231_HW_CS4232_MASK)) { - spin_lock_irqsave(&chip->reg_lock, flags); - if ((chip->image[CS4231_PLAYBK_FORMAT] & 0x0f) == (pdfr & 0x0f)) { /* rate is same? */ - snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] | 0x10); - snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT, chip->image[CS4231_PLAYBK_FORMAT] = pdfr); - snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] &= ~0x10); - udelay(100); /* Fixes audible clicks at least on GUS MAX */ - full_calib = 0; - } - spin_unlock_irqrestore(&chip->reg_lock, flags); - } - if (full_calib) { - snd_cs4231_mce_up(chip); - spin_lock_irqsave(&chip->reg_lock, flags); - if (chip->hardware != CS4231_HW_INTERWAVE && !chip->single_dma) { - snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT, - (chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE) ? - (pdfr & 0xf0) | (chip->image[CS4231_REC_FORMAT] & 0x0f) : - pdfr); - } else { - snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT, chip->image[CS4231_PLAYBK_FORMAT] = pdfr); - } - spin_unlock_irqrestore(&chip->reg_lock, flags); - if (chip->hardware == CS4231_HW_OPL3SA2) - udelay(100); /* this seems to help */ - snd_cs4231_mce_down(chip); - } - snd_cs4231_calibrate_mute(chip, 0); - mutex_unlock(&chip->mce_mutex); -} - -static void snd_cs4231_capture_format(struct snd_cs4231 *chip, - struct snd_pcm_hw_params *params, - unsigned char cdfr) -{ - unsigned long flags; - int full_calib = 1; - - mutex_lock(&chip->mce_mutex); - snd_cs4231_calibrate_mute(chip, 1); - if (chip->hardware == CS4231_HW_CS4231A || - (chip->hardware & CS4231_HW_CS4232_MASK)) { - spin_lock_irqsave(&chip->reg_lock, flags); - if ((chip->image[CS4231_PLAYBK_FORMAT] & 0x0f) == (cdfr & 0x0f) || /* rate is same? */ - (chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE)) { - snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] | 0x20); - snd_cs4231_out(chip, CS4231_REC_FORMAT, chip->image[CS4231_REC_FORMAT] = cdfr); - snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] &= ~0x20); - full_calib = 0; - } - spin_unlock_irqrestore(&chip->reg_lock, flags); - } - if (full_calib) { - snd_cs4231_mce_up(chip); - spin_lock_irqsave(&chip->reg_lock, flags); - if (chip->hardware != CS4231_HW_INTERWAVE) { - if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE)) { - snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT, - ((chip->single_dma ? cdfr : chip->image[CS4231_PLAYBK_FORMAT]) & 0xf0) | - (cdfr & 0x0f)); - spin_unlock_irqrestore(&chip->reg_lock, flags); - snd_cs4231_mce_down(chip); - snd_cs4231_mce_up(chip); - spin_lock_irqsave(&chip->reg_lock, flags); - } - } - snd_cs4231_out(chip, CS4231_REC_FORMAT, cdfr); - spin_unlock_irqrestore(&chip->reg_lock, flags); - snd_cs4231_mce_down(chip); - } - snd_cs4231_calibrate_mute(chip, 0); - mutex_unlock(&chip->mce_mutex); -} - -/* - * Timer interface - */ - -static unsigned long snd_cs4231_timer_resolution(struct snd_timer * timer) -{ - struct snd_cs4231 *chip = snd_timer_chip(timer); - if (chip->hardware & CS4231_HW_CS4236B_MASK) - return 14467; - else - return chip->image[CS4231_PLAYBK_FORMAT] & 1 ? 9969 : 9920; -} - -static int snd_cs4231_timer_start(struct snd_timer * timer) -{ - unsigned long flags; - unsigned int ticks; - struct snd_cs4231 *chip = snd_timer_chip(timer); - spin_lock_irqsave(&chip->reg_lock, flags); - ticks = timer->sticks; - if ((chip->image[CS4231_ALT_FEATURE_1] & CS4231_TIMER_ENABLE) == 0 || - (unsigned char)(ticks >> 8) != chip->image[CS4231_TIMER_HIGH] || - (unsigned char)ticks != chip->image[CS4231_TIMER_LOW]) { - snd_cs4231_out(chip, CS4231_TIMER_HIGH, chip->image[CS4231_TIMER_HIGH] = (unsigned char) (ticks >> 8)); - snd_cs4231_out(chip, CS4231_TIMER_LOW, chip->image[CS4231_TIMER_LOW] = (unsigned char) ticks); - snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] | CS4231_TIMER_ENABLE); - } - spin_unlock_irqrestore(&chip->reg_lock, flags); - return 0; -} - -static int snd_cs4231_timer_stop(struct snd_timer * timer) -{ - unsigned long flags; - struct snd_cs4231 *chip = snd_timer_chip(timer); - spin_lock_irqsave(&chip->reg_lock, flags); - snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] &= ~CS4231_TIMER_ENABLE); - spin_unlock_irqrestore(&chip->reg_lock, flags); - return 0; -} - -static void snd_cs4231_init(struct snd_cs4231 *chip) -{ - unsigned long flags; - - snd_cs4231_mce_down(chip); - -#ifdef SNDRV_DEBUG_MCE - snd_printk("init: (1)\n"); -#endif - snd_cs4231_mce_up(chip); - spin_lock_irqsave(&chip->reg_lock, flags); - chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO | - CS4231_RECORD_ENABLE | CS4231_RECORD_PIO | - CS4231_CALIB_MODE); - chip->image[CS4231_IFACE_CTRL] |= CS4231_AUTOCALIB; - snd_cs4231_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]); - spin_unlock_irqrestore(&chip->reg_lock, flags); - snd_cs4231_mce_down(chip); - -#ifdef SNDRV_DEBUG_MCE - snd_printk("init: (2)\n"); -#endif - - snd_cs4231_mce_up(chip); - spin_lock_irqsave(&chip->reg_lock, flags); - snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1]); - spin_unlock_irqrestore(&chip->reg_lock, flags); - snd_cs4231_mce_down(chip); - -#ifdef SNDRV_DEBUG_MCE - snd_printk("init: (3) - afei = 0x%x\n", chip->image[CS4231_ALT_FEATURE_1]); -#endif - - spin_lock_irqsave(&chip->reg_lock, flags); - snd_cs4231_out(chip, CS4231_ALT_FEATURE_2, chip->image[CS4231_ALT_FEATURE_2]); - spin_unlock_irqrestore(&chip->reg_lock, flags); - - snd_cs4231_mce_up(chip); - spin_lock_irqsave(&chip->reg_lock, flags); - snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT, chip->image[CS4231_PLAYBK_FORMAT]); - spin_unlock_irqrestore(&chip->reg_lock, flags); - snd_cs4231_mce_down(chip); - -#ifdef SNDRV_DEBUG_MCE - snd_printk("init: (4)\n"); -#endif - - snd_cs4231_mce_up(chip); - spin_lock_irqsave(&chip->reg_lock, flags); - snd_cs4231_out(chip, CS4231_REC_FORMAT, chip->image[CS4231_REC_FORMAT]); - spin_unlock_irqrestore(&chip->reg_lock, flags); - snd_cs4231_mce_down(chip); - -#ifdef SNDRV_DEBUG_MCE - snd_printk("init: (5)\n"); -#endif -} - -static int snd_cs4231_open(struct snd_cs4231 *chip, unsigned int mode) -{ - unsigned long flags; - - mutex_lock(&chip->open_mutex); - if ((chip->mode & mode) || - ((chip->mode & CS4231_MODE_OPEN) && chip->single_dma)) { - mutex_unlock(&chip->open_mutex); - return -EAGAIN; - } - if (chip->mode & CS4231_MODE_OPEN) { - chip->mode |= mode; - mutex_unlock(&chip->open_mutex); - return 0; - } - /* ok. now enable and ack CODEC IRQ */ - spin_lock_irqsave(&chip->reg_lock, flags); - snd_cs4231_out(chip, CS4231_IRQ_STATUS, CS4231_PLAYBACK_IRQ | - CS4231_RECORD_IRQ | - CS4231_TIMER_IRQ); - snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0); - cs4231_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */ - cs4231_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */ - chip->image[CS4231_PIN_CTRL] |= CS4231_IRQ_ENABLE; - snd_cs4231_out(chip, CS4231_PIN_CTRL, chip->image[CS4231_PIN_CTRL]); - snd_cs4231_out(chip, CS4231_IRQ_STATUS, CS4231_PLAYBACK_IRQ | - CS4231_RECORD_IRQ | - CS4231_TIMER_IRQ); - snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0); - spin_unlock_irqrestore(&chip->reg_lock, flags); - - chip->mode = mode; - mutex_unlock(&chip->open_mutex); - return 0; -} - -static void snd_cs4231_close(struct snd_cs4231 *chip, unsigned int mode) -{ - unsigned long flags; - - mutex_lock(&chip->open_mutex); - chip->mode &= ~mode; - if (chip->mode & CS4231_MODE_OPEN) { - mutex_unlock(&chip->open_mutex); - return; - } - snd_cs4231_calibrate_mute(chip, 1); - - /* disable IRQ */ - spin_lock_irqsave(&chip->reg_lock, flags); - snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0); - cs4231_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */ - cs4231_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */ - chip->image[CS4231_PIN_CTRL] &= ~CS4231_IRQ_ENABLE; - snd_cs4231_out(chip, CS4231_PIN_CTRL, chip->image[CS4231_PIN_CTRL]); - - /* now disable record & playback */ - - if (chip->image[CS4231_IFACE_CTRL] & (CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO | - CS4231_RECORD_ENABLE | CS4231_RECORD_PIO)) { - spin_unlock_irqrestore(&chip->reg_lock, flags); - snd_cs4231_mce_up(chip); - spin_lock_irqsave(&chip->reg_lock, flags); - chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO | - CS4231_RECORD_ENABLE | CS4231_RECORD_PIO); - snd_cs4231_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]); - spin_unlock_irqrestore(&chip->reg_lock, flags); - snd_cs4231_mce_down(chip); - spin_lock_irqsave(&chip->reg_lock, flags); - } - - /* clear IRQ again */ - snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0); - cs4231_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */ - cs4231_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */ - spin_unlock_irqrestore(&chip->reg_lock, flags); - - snd_cs4231_calibrate_mute(chip, 0); - - chip->mode = 0; - mutex_unlock(&chip->open_mutex); -} - -/* - * timer open/close - */ - -static int snd_cs4231_timer_open(struct snd_timer * timer) -{ - struct snd_cs4231 *chip = snd_timer_chip(timer); - snd_cs4231_open(chip, CS4231_MODE_TIMER); - return 0; -} - -static int snd_cs4231_timer_close(struct snd_timer * timer) -{ - struct snd_cs4231 *chip = snd_timer_chip(timer); - snd_cs4231_close(chip, CS4231_MODE_TIMER); - return 0; -} - -static struct snd_timer_hardware snd_cs4231_timer_table = -{ - .flags = SNDRV_TIMER_HW_AUTO, - .resolution = 9945, - .ticks = 65535, - .open = snd_cs4231_timer_open, - .close = snd_cs4231_timer_close, - .c_resolution = snd_cs4231_timer_resolution, - .start = snd_cs4231_timer_start, - .stop = snd_cs4231_timer_stop, -}; - -/* - * ok.. exported functions.. - */ - -static int snd_cs4231_playback_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) -{ - struct snd_cs4231 *chip = snd_pcm_substream_chip(substream); - unsigned char new_pdfr; - int err; - - if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0) - return err; - new_pdfr = snd_cs4231_get_format(chip, params_format(hw_params), params_channels(hw_params)) | - snd_cs4231_get_rate(params_rate(hw_params)); - chip->set_playback_format(chip, hw_params, new_pdfr); - return 0; -} - -static int snd_cs4231_playback_hw_free(struct snd_pcm_substream *substream) -{ - return snd_pcm_lib_free_pages(substream); -} - -static int snd_cs4231_playback_prepare(struct snd_pcm_substream *substream) -{ - struct snd_cs4231 *chip = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - unsigned long flags; - unsigned int size = snd_pcm_lib_buffer_bytes(substream); - unsigned int count = snd_pcm_lib_period_bytes(substream); - - spin_lock_irqsave(&chip->reg_lock, flags); - chip->p_dma_size = size; - chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO); - snd_dma_program(chip->dma1, runtime->dma_addr, size, DMA_MODE_WRITE | DMA_AUTOINIT); - count = snd_cs4231_get_count(chip->image[CS4231_PLAYBK_FORMAT], count) - 1; - snd_cs4231_out(chip, CS4231_PLY_LWR_CNT, (unsigned char) count); - snd_cs4231_out(chip, CS4231_PLY_UPR_CNT, (unsigned char) (count >> 8)); - spin_unlock_irqrestore(&chip->reg_lock, flags); -#if 0 - snd_cs4231_debug(chip); -#endif - return 0; -} - -static int snd_cs4231_capture_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) -{ - struct snd_cs4231 *chip = snd_pcm_substream_chip(substream); - unsigned char new_cdfr; - int err; - - if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0) - return err; - new_cdfr = snd_cs4231_get_format(chip, params_format(hw_params), params_channels(hw_params)) | - snd_cs4231_get_rate(params_rate(hw_params)); - chip->set_capture_format(chip, hw_params, new_cdfr); - return 0; -} - -static int snd_cs4231_capture_hw_free(struct snd_pcm_substream *substream) -{ - return snd_pcm_lib_free_pages(substream); -} - -static int snd_cs4231_capture_prepare(struct snd_pcm_substream *substream) -{ - struct snd_cs4231 *chip = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - unsigned long flags; - unsigned int size = snd_pcm_lib_buffer_bytes(substream); - unsigned int count = snd_pcm_lib_period_bytes(substream); - - spin_lock_irqsave(&chip->reg_lock, flags); - chip->c_dma_size = size; - chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_RECORD_ENABLE | CS4231_RECORD_PIO); - snd_dma_program(chip->dma2, runtime->dma_addr, size, DMA_MODE_READ | DMA_AUTOINIT); - count = snd_cs4231_get_count(chip->image[CS4231_REC_FORMAT], count) - 1; - if (chip->single_dma && chip->hardware != CS4231_HW_INTERWAVE) { - snd_cs4231_out(chip, CS4231_PLY_LWR_CNT, (unsigned char) count); - snd_cs4231_out(chip, CS4231_PLY_UPR_CNT, (unsigned char) (count >> 8)); - } else { - snd_cs4231_out(chip, CS4231_REC_LWR_CNT, (unsigned char) count); - snd_cs4231_out(chip, CS4231_REC_UPR_CNT, (unsigned char) (count >> 8)); - } - spin_unlock_irqrestore(&chip->reg_lock, flags); - return 0; -} - -void snd_cs4231_overrange(struct snd_cs4231 *chip) -{ - unsigned long flags; - unsigned char res; - - spin_lock_irqsave(&chip->reg_lock, flags); - res = snd_cs4231_in(chip, CS4231_TEST_INIT); - spin_unlock_irqrestore(&chip->reg_lock, flags); - if (res & (0x08 | 0x02)) /* detect overrange only above 0dB; may be user selectable? */ - chip->capture_substream->runtime->overrange++; -} - -irqreturn_t snd_cs4231_interrupt(int irq, void *dev_id) -{ - struct snd_cs4231 *chip = dev_id; - unsigned char status; - - status = snd_cs4231_in(chip, CS4231_IRQ_STATUS); - if (status & CS4231_TIMER_IRQ) { - if (chip->timer) - snd_timer_interrupt(chip->timer, chip->timer->sticks); - } - if (chip->single_dma && chip->hardware != CS4231_HW_INTERWAVE) { - if (status & CS4231_PLAYBACK_IRQ) { - if (chip->mode & CS4231_MODE_PLAY) { - if (chip->playback_substream) - snd_pcm_period_elapsed(chip->playback_substream); - } - if (chip->mode & CS4231_MODE_RECORD) { - if (chip->capture_substream) { - snd_cs4231_overrange(chip); - snd_pcm_period_elapsed(chip->capture_substream); - } - } - } - } else { - if (status & CS4231_PLAYBACK_IRQ) { - if (chip->playback_substream) - snd_pcm_period_elapsed(chip->playback_substream); - } - if (status & CS4231_RECORD_IRQ) { - if (chip->capture_substream) { - snd_cs4231_overrange(chip); - snd_pcm_period_elapsed(chip->capture_substream); - } - } - } - - spin_lock(&chip->reg_lock); - snd_cs4231_outm(chip, CS4231_IRQ_STATUS, ~CS4231_ALL_IRQS | ~status, 0); - spin_unlock(&chip->reg_lock); - return IRQ_HANDLED; -} - -static snd_pcm_uframes_t snd_cs4231_playback_pointer(struct snd_pcm_substream *substream) -{ - struct snd_cs4231 *chip = snd_pcm_substream_chip(substream); - size_t ptr; - - if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE)) - return 0; - ptr = snd_dma_pointer(chip->dma1, chip->p_dma_size); - return bytes_to_frames(substream->runtime, ptr); -} - -static snd_pcm_uframes_t snd_cs4231_capture_pointer(struct snd_pcm_substream *substream) -{ - struct snd_cs4231 *chip = snd_pcm_substream_chip(substream); - size_t ptr; - - if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE)) - return 0; - ptr = snd_dma_pointer(chip->dma2, chip->c_dma_size); - return bytes_to_frames(substream->runtime, ptr); -} - -/* - - */ - -static int snd_cs4231_probe(struct snd_cs4231 *chip) -{ - unsigned long flags; - int i, id, rev; - unsigned char *ptr; - unsigned int hw; - -#if 0 - snd_cs4231_debug(chip); -#endif - id = 0; - for (i = 0; i < 50; i++) { - mb(); - if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) - udelay(2000); - else { - spin_lock_irqsave(&chip->reg_lock, flags); - snd_cs4231_out(chip, CS4231_MISC_INFO, CS4231_MODE2); - id = snd_cs4231_in(chip, CS4231_MISC_INFO) & 0x0f; - spin_unlock_irqrestore(&chip->reg_lock, flags); - if (id == 0x0a) - break; /* this is valid value */ - } - } - snd_printdd("cs4231: port = 0x%lx, id = 0x%x\n", chip->port, id); - if (id != 0x0a) - return -ENODEV; /* no valid device found */ - - if (((hw = chip->hardware) & CS4231_HW_TYPE_MASK) == CS4231_HW_DETECT) { - rev = snd_cs4231_in(chip, CS4231_VERSION) & 0xe7; - snd_printdd("CS4231: VERSION (I25) = 0x%x\n", rev); - if (rev == 0x80) { - unsigned char tmp = snd_cs4231_in(chip, 23); - snd_cs4231_out(chip, 23, ~tmp); - if (snd_cs4231_in(chip, 23) != tmp) - chip->hardware = CS4231_HW_AD1845; - else - chip->hardware = CS4231_HW_CS4231; - } else if (rev == 0xa0) { - chip->hardware = CS4231_HW_CS4231A; - } else if (rev == 0xa2) { - chip->hardware = CS4231_HW_CS4232; - } else if (rev == 0xb2) { - chip->hardware = CS4231_HW_CS4232A; - } else if (rev == 0x83) { - chip->hardware = CS4231_HW_CS4236; - } else if (rev == 0x03) { - chip->hardware = CS4231_HW_CS4236B; - } else { - snd_printk("unknown CS chip with version 0x%x\n", rev); - return -ENODEV; /* unknown CS4231 chip? */ - } - } - spin_lock_irqsave(&chip->reg_lock, flags); - cs4231_inb(chip, CS4231P(STATUS)); /* clear any pendings IRQ */ - cs4231_outb(chip, CS4231P(STATUS), 0); - mb(); - spin_unlock_irqrestore(&chip->reg_lock, flags); - - chip->image[CS4231_MISC_INFO] = CS4231_MODE2; - switch (chip->hardware) { - case CS4231_HW_INTERWAVE: - chip->image[CS4231_MISC_INFO] = CS4231_IW_MODE3; - break; - case CS4231_HW_CS4235: - case CS4231_HW_CS4236B: - case CS4231_HW_CS4237B: - case CS4231_HW_CS4238B: - case CS4231_HW_CS4239: - if (hw == CS4231_HW_DETECT3) - chip->image[CS4231_MISC_INFO] = CS4231_4236_MODE3; - else - chip->hardware = CS4231_HW_CS4236; - break; - } - - chip->image[CS4231_IFACE_CTRL] = - (chip->image[CS4231_IFACE_CTRL] & ~CS4231_SINGLE_DMA) | - (chip->single_dma ? CS4231_SINGLE_DMA : 0); - if (chip->hardware != CS4231_HW_OPTI93X) { - chip->image[CS4231_ALT_FEATURE_1] = 0x80; - chip->image[CS4231_ALT_FEATURE_2] = - chip->hardware == CS4231_HW_INTERWAVE ? 0xc2 : 0x01; - } - ptr = (unsigned char *) &chip->image; - snd_cs4231_mce_down(chip); - spin_lock_irqsave(&chip->reg_lock, flags); - for (i = 0; i < 32; i++) /* ok.. fill all CS4231 registers */ - snd_cs4231_out(chip, i, *ptr++); - spin_unlock_irqrestore(&chip->reg_lock, flags); - snd_cs4231_mce_up(chip); - snd_cs4231_mce_down(chip); - - mdelay(2); - - /* ok.. try check hardware version for CS4236+ chips */ - if ((hw & CS4231_HW_TYPE_MASK) == CS4231_HW_DETECT) { - if (chip->hardware == CS4231_HW_CS4236B) { - rev = snd_cs4236_ext_in(chip, CS4236_VERSION); - snd_cs4236_ext_out(chip, CS4236_VERSION, 0xff); - id = snd_cs4236_ext_in(chip, CS4236_VERSION); - snd_cs4236_ext_out(chip, CS4236_VERSION, rev); - snd_printdd("CS4231: ext version; rev = 0x%x, id = 0x%x\n", rev, id); - if ((id & 0x1f) == 0x1d) { /* CS4235 */ - chip->hardware = CS4231_HW_CS4235; - switch (id >> 5) { - case 4: - case 5: - case 6: - break; - default: - snd_printk("unknown CS4235 chip (enhanced version = 0x%x)\n", id); - } - } else if ((id & 0x1f) == 0x0b) { /* CS4236/B */ - switch (id >> 5) { - case 4: - case 5: - case 6: - case 7: - chip->hardware = CS4231_HW_CS4236B; - break; - default: - snd_printk("unknown CS4236 chip (enhanced version = 0x%x)\n", id); - } - } else if ((id & 0x1f) == 0x08) { /* CS4237B */ - chip->hardware = CS4231_HW_CS4237B; - switch (id >> 5) { - case 4: - case 5: - case 6: - case 7: - break; - default: - snd_printk("unknown CS4237B chip (enhanced version = 0x%x)\n", id); - } - } else if ((id & 0x1f) == 0x09) { /* CS4238B */ - chip->hardware = CS4231_HW_CS4238B; - switch (id >> 5) { - case 5: - case 6: - case 7: - break; - default: - snd_printk("unknown CS4238B chip (enhanced version = 0x%x)\n", id); - } - } else if ((id & 0x1f) == 0x1e) { /* CS4239 */ - chip->hardware = CS4231_HW_CS4239; - switch (id >> 5) { - case 4: - case 5: - case 6: - break; - default: - snd_printk("unknown CS4239 chip (enhanced version = 0x%x)\n", id); - } - } else { - snd_printk("unknown CS4236/CS423xB chip (enhanced version = 0x%x)\n", id); - } - } - } - return 0; /* all things are ok.. */ -} - -/* - - */ - -static struct snd_pcm_hardware snd_cs4231_playback = -{ - .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_RESUME | - SNDRV_PCM_INFO_SYNC_START), - .formats = (SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | SNDRV_PCM_FMTBIT_IMA_ADPCM | - SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE), - .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000, - .rate_min = 5510, - .rate_max = 48000, - .channels_min = 1, - .channels_max = 2, - .buffer_bytes_max = (128*1024), - .period_bytes_min = 64, - .period_bytes_max = (128*1024), - .periods_min = 1, - .periods_max = 1024, - .fifo_size = 0, -}; - -static struct snd_pcm_hardware snd_cs4231_capture = -{ - .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_RESUME | - SNDRV_PCM_INFO_SYNC_START), - .formats = (SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | SNDRV_PCM_FMTBIT_IMA_ADPCM | - SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE), - .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000, - .rate_min = 5510, - .rate_max = 48000, - .channels_min = 1, - .channels_max = 2, - .buffer_bytes_max = (128*1024), - .period_bytes_min = 64, - .period_bytes_max = (128*1024), - .periods_min = 1, - .periods_max = 1024, - .fifo_size = 0, -}; - -/* - - */ - -static int snd_cs4231_playback_open(struct snd_pcm_substream *substream) -{ - struct snd_cs4231 *chip = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - int err; - - runtime->hw = snd_cs4231_playback; - - /* hardware bug in InterWave chipset */ - if (chip->hardware == CS4231_HW_INTERWAVE && chip->dma1 > 3) - runtime->hw.formats &= ~SNDRV_PCM_FMTBIT_MU_LAW; - - /* hardware limitation of cheap chips */ - if (chip->hardware == CS4231_HW_CS4235 || - chip->hardware == CS4231_HW_CS4239) - runtime->hw.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE; - - snd_pcm_limit_isa_dma_size(chip->dma1, &runtime->hw.buffer_bytes_max); - snd_pcm_limit_isa_dma_size(chip->dma1, &runtime->hw.period_bytes_max); - - if (chip->claim_dma) { - if ((err = chip->claim_dma(chip, chip->dma_private_data, chip->dma1)) < 0) - return err; - } - - if ((err = snd_cs4231_open(chip, CS4231_MODE_PLAY)) < 0) { - if (chip->release_dma) - chip->release_dma(chip, chip->dma_private_data, chip->dma1); - snd_free_pages(runtime->dma_area, runtime->dma_bytes); - return err; - } - chip->playback_substream = substream; - snd_pcm_set_sync(substream); - chip->rate_constraint(runtime); - return 0; -} - -static int snd_cs4231_capture_open(struct snd_pcm_substream *substream) -{ - struct snd_cs4231 *chip = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - int err; - - runtime->hw = snd_cs4231_capture; - - /* hardware limitation of cheap chips */ - if (chip->hardware == CS4231_HW_CS4235 || - chip->hardware == CS4231_HW_CS4239) - runtime->hw.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE; - - snd_pcm_limit_isa_dma_size(chip->dma2, &runtime->hw.buffer_bytes_max); - snd_pcm_limit_isa_dma_size(chip->dma2, &runtime->hw.period_bytes_max); - - if (chip->claim_dma) { - if ((err = chip->claim_dma(chip, chip->dma_private_data, chip->dma2)) < 0) - return err; - } - - if ((err = snd_cs4231_open(chip, CS4231_MODE_RECORD)) < 0) { - if (chip->release_dma) - chip->release_dma(chip, chip->dma_private_data, chip->dma2); - snd_free_pages(runtime->dma_area, runtime->dma_bytes); - return err; - } - chip->capture_substream = substream; - snd_pcm_set_sync(substream); - chip->rate_constraint(runtime); - return 0; -} - -static int snd_cs4231_playback_close(struct snd_pcm_substream *substream) -{ - struct snd_cs4231 *chip = snd_pcm_substream_chip(substream); - - chip->playback_substream = NULL; - snd_cs4231_close(chip, CS4231_MODE_PLAY); - return 0; -} - -static int snd_cs4231_capture_close(struct snd_pcm_substream *substream) -{ - struct snd_cs4231 *chip = snd_pcm_substream_chip(substream); - - chip->capture_substream = NULL; - snd_cs4231_close(chip, CS4231_MODE_RECORD); - return 0; -} - -#ifdef CONFIG_PM - -/* lowlevel suspend callback for CS4231 */ -static void snd_cs4231_suspend(struct snd_cs4231 *chip) -{ - int reg; - unsigned long flags; - - snd_pcm_suspend_all(chip->pcm); - spin_lock_irqsave(&chip->reg_lock, flags); - for (reg = 0; reg < 32; reg++) - chip->image[reg] = snd_cs4231_in(chip, reg); - spin_unlock_irqrestore(&chip->reg_lock, flags); -} - -/* lowlevel resume callback for CS4231 */ -static void snd_cs4231_resume(struct snd_cs4231 *chip) -{ - int reg; - unsigned long flags; - /* int timeout; */ - - snd_cs4231_mce_up(chip); - spin_lock_irqsave(&chip->reg_lock, flags); - for (reg = 0; reg < 32; reg++) { - switch (reg) { - case CS4231_VERSION: - break; - default: - snd_cs4231_out(chip, reg, chip->image[reg]); - break; - } - } - spin_unlock_irqrestore(&chip->reg_lock, flags); -#if 1 - snd_cs4231_mce_down(chip); -#else - /* The following is a workaround to avoid freeze after resume on TP600E. - This is the first half of copy of snd_cs4231_mce_down(), but doesn't - include rescheduling. -- iwai - */ - snd_cs4231_busy_wait(chip); - spin_lock_irqsave(&chip->reg_lock, flags); - chip->mce_bit &= ~CS4231_MCE; - timeout = cs4231_inb(chip, CS4231P(REGSEL)); - cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | (timeout & 0x1f)); - spin_unlock_irqrestore(&chip->reg_lock, flags); - if (timeout == 0x80) - snd_printk("down [0x%lx]: serious init problem - codec still busy\n", chip->port); - if ((timeout & CS4231_MCE) == 0 || - !(chip->hardware & (CS4231_HW_CS4231_MASK | CS4231_HW_CS4232_MASK))) { - return; - } - snd_cs4231_busy_wait(chip); -#endif -} -#endif /* CONFIG_PM */ - -static int snd_cs4231_free(struct snd_cs4231 *chip) -{ - release_and_free_resource(chip->res_port); - release_and_free_resource(chip->res_cport); - if (chip->irq >= 0) { - disable_irq(chip->irq); - if (!(chip->hwshare & CS4231_HWSHARE_IRQ)) - free_irq(chip->irq, (void *) chip); - } - if (!(chip->hwshare & CS4231_HWSHARE_DMA1) && chip->dma1 >= 0) { - snd_dma_disable(chip->dma1); - free_dma(chip->dma1); - } - if (!(chip->hwshare & CS4231_HWSHARE_DMA2) && chip->dma2 >= 0 && chip->dma2 != chip->dma1) { - snd_dma_disable(chip->dma2); - free_dma(chip->dma2); - } - if (chip->timer) - snd_device_free(chip->card, chip->timer); - kfree(chip); - return 0; -} - -static int snd_cs4231_dev_free(struct snd_device *device) -{ - struct snd_cs4231 *chip = device->device_data; - return snd_cs4231_free(chip); -} - -const char *snd_cs4231_chip_id(struct snd_cs4231 *chip) -{ - switch (chip->hardware) { - case CS4231_HW_CS4231: return "CS4231"; - case CS4231_HW_CS4231A: return "CS4231A"; - case CS4231_HW_CS4232: return "CS4232"; - case CS4231_HW_CS4232A: return "CS4232A"; - case CS4231_HW_CS4235: return "CS4235"; - case CS4231_HW_CS4236: return "CS4236"; - case CS4231_HW_CS4236B: return "CS4236B"; - case CS4231_HW_CS4237B: return "CS4237B"; - case CS4231_HW_CS4238B: return "CS4238B"; - case CS4231_HW_CS4239: return "CS4239"; - case CS4231_HW_INTERWAVE: return "AMD InterWave"; - case CS4231_HW_OPL3SA2: return chip->card->shortname; - case CS4231_HW_AD1845: return "AD1845"; - case CS4231_HW_OPTI93X: return "OPTi 93x"; - default: return "???"; - } -} - -static int snd_cs4231_new(struct snd_card *card, - unsigned short hardware, - unsigned short hwshare, - struct snd_cs4231 ** rchip) -{ - struct snd_cs4231 *chip; - - *rchip = NULL; - chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (chip == NULL) - return -ENOMEM; - chip->hardware = hardware; - chip->hwshare = hwshare; - - spin_lock_init(&chip->reg_lock); - mutex_init(&chip->mce_mutex); - mutex_init(&chip->open_mutex); - chip->card = card; - chip->rate_constraint = snd_cs4231_xrate; - chip->set_playback_format = snd_cs4231_playback_format; - chip->set_capture_format = snd_cs4231_capture_format; - if (chip->hardware == CS4231_HW_OPTI93X) - memcpy(&chip->image, &snd_opti93x_original_image, - sizeof(snd_opti93x_original_image)); - else - memcpy(&chip->image, &snd_cs4231_original_image, - sizeof(snd_cs4231_original_image)); - - *rchip = chip; - return 0; -} - -int snd_cs4231_create(struct snd_card *card, - unsigned long port, - unsigned long cport, - int irq, int dma1, int dma2, - unsigned short hardware, - unsigned short hwshare, - struct snd_cs4231 ** rchip) -{ - static struct snd_device_ops ops = { - .dev_free = snd_cs4231_dev_free, - }; - struct snd_cs4231 *chip; - int err; - - err = snd_cs4231_new(card, hardware, hwshare, &chip); - if (err < 0) - return err; - - chip->irq = -1; - chip->dma1 = -1; - chip->dma2 = -1; - - if ((chip->res_port = request_region(port, 4, "CS4231")) == NULL) { - snd_printk(KERN_ERR "cs4231: can't grab port 0x%lx\n", port); - snd_cs4231_free(chip); - return -EBUSY; - } - chip->port = port; - if ((long)cport >= 0 && (chip->res_cport = request_region(cport, 8, "CS4232 Control")) == NULL) { - snd_printk(KERN_ERR "cs4231: can't grab control port 0x%lx\n", cport); - snd_cs4231_free(chip); - return -ENODEV; - } - chip->cport = cport; - if (!(hwshare & CS4231_HWSHARE_IRQ) && request_irq(irq, snd_cs4231_interrupt, IRQF_DISABLED, "CS4231", (void *) chip)) { - snd_printk(KERN_ERR "cs4231: can't grab IRQ %d\n", irq); - snd_cs4231_free(chip); - return -EBUSY; - } - chip->irq = irq; - if (!(hwshare & CS4231_HWSHARE_DMA1) && request_dma(dma1, "CS4231 - 1")) { - snd_printk(KERN_ERR "cs4231: can't grab DMA1 %d\n", dma1); - snd_cs4231_free(chip); - return -EBUSY; - } - chip->dma1 = dma1; - if (!(hwshare & CS4231_HWSHARE_DMA2) && dma1 != dma2 && dma2 >= 0 && request_dma(dma2, "CS4231 - 2")) { - snd_printk(KERN_ERR "cs4231: can't grab DMA2 %d\n", dma2); - snd_cs4231_free(chip); - return -EBUSY; - } - if (dma1 == dma2 || dma2 < 0) { - chip->single_dma = 1; - chip->dma2 = chip->dma1; - } else - chip->dma2 = dma2; - - /* global setup */ - if (snd_cs4231_probe(chip) < 0) { - snd_cs4231_free(chip); - return -ENODEV; - } - snd_cs4231_init(chip); - -#if 0 - if (chip->hardware & CS4231_HW_CS4232_MASK) { - if (chip->res_cport == NULL) - snd_printk("CS4232 control port features are not accessible\n"); - } -#endif - - /* Register device */ - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { - snd_cs4231_free(chip); - return err; - } - -#ifdef CONFIG_PM - /* Power Management */ - chip->suspend = snd_cs4231_suspend; - chip->resume = snd_cs4231_resume; -#endif - - *rchip = chip; - return 0; -} - -static struct snd_pcm_ops snd_cs4231_playback_ops = { - .open = snd_cs4231_playback_open, - .close = snd_cs4231_playback_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = snd_cs4231_playback_hw_params, - .hw_free = snd_cs4231_playback_hw_free, - .prepare = snd_cs4231_playback_prepare, - .trigger = snd_cs4231_trigger, - .pointer = snd_cs4231_playback_pointer, -}; - -static struct snd_pcm_ops snd_cs4231_capture_ops = { - .open = snd_cs4231_capture_open, - .close = snd_cs4231_capture_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = snd_cs4231_capture_hw_params, - .hw_free = snd_cs4231_capture_hw_free, - .prepare = snd_cs4231_capture_prepare, - .trigger = snd_cs4231_trigger, - .pointer = snd_cs4231_capture_pointer, -}; - -int snd_cs4231_pcm(struct snd_cs4231 *chip, int device, struct snd_pcm **rpcm) -{ - struct snd_pcm *pcm; - int err; - - if ((err = snd_pcm_new(chip->card, "CS4231", device, 1, 1, &pcm)) < 0) - return err; - - spin_lock_init(&chip->reg_lock); - mutex_init(&chip->mce_mutex); - mutex_init(&chip->open_mutex); - - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_cs4231_playback_ops); - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_cs4231_capture_ops); - - /* global setup */ - pcm->private_data = chip; - pcm->info_flags = 0; - if (chip->single_dma) - pcm->info_flags |= SNDRV_PCM_INFO_HALF_DUPLEX; - if (chip->hardware != CS4231_HW_INTERWAVE) - pcm->info_flags |= SNDRV_PCM_INFO_JOINT_DUPLEX; - strcpy(pcm->name, snd_cs4231_chip_id(chip)); - - snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_isa_data(), - 64*1024, chip->dma1 > 3 || chip->dma2 > 3 ? 128*1024 : 64*1024); - - chip->pcm = pcm; - if (rpcm) - *rpcm = pcm; - return 0; -} - -static void snd_cs4231_timer_free(struct snd_timer *timer) -{ - struct snd_cs4231 *chip = timer->private_data; - chip->timer = NULL; -} - -int snd_cs4231_timer(struct snd_cs4231 *chip, int device, struct snd_timer **rtimer) -{ - struct snd_timer *timer; - struct snd_timer_id tid; - int err; - - /* Timer initialization */ - tid.dev_class = SNDRV_TIMER_CLASS_CARD; - tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE; - tid.card = chip->card->number; - tid.device = device; - tid.subdevice = 0; - if ((err = snd_timer_new(chip->card, "CS4231", &tid, &timer)) < 0) - return err; - strcpy(timer->name, snd_cs4231_chip_id(chip)); - timer->private_data = chip; - timer->private_free = snd_cs4231_timer_free; - timer->hw = snd_cs4231_timer_table; - chip->timer = timer; - if (rtimer) - *rtimer = timer; - return 0; -} - -/* - * MIXER part - */ - -static int snd_cs4231_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - static char *texts[4] = { - "Line", "Aux", "Mic", "Mix" - }; - static char *opl3sa_texts[4] = { - "Line", "CD", "Mic", "Mix" - }; - static char *gusmax_texts[4] = { - "Line", "Synth", "Mic", "Mix" - }; - char **ptexts = texts; - struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol); - - snd_assert(chip->card != NULL, return -EINVAL); - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 2; - uinfo->value.enumerated.items = 4; - if (uinfo->value.enumerated.item > 3) - uinfo->value.enumerated.item = 3; - if (!strcmp(chip->card->driver, "GUS MAX")) - ptexts = gusmax_texts; - switch (chip->hardware) { - case CS4231_HW_INTERWAVE: ptexts = gusmax_texts; break; - case CS4231_HW_OPL3SA2: ptexts = opl3sa_texts; break; - } - strcpy(uinfo->value.enumerated.name, ptexts[uinfo->value.enumerated.item]); - return 0; -} - -static int snd_cs4231_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; - - spin_lock_irqsave(&chip->reg_lock, flags); - ucontrol->value.enumerated.item[0] = (chip->image[CS4231_LEFT_INPUT] & CS4231_MIXS_ALL) >> 6; - ucontrol->value.enumerated.item[1] = (chip->image[CS4231_RIGHT_INPUT] & CS4231_MIXS_ALL) >> 6; - spin_unlock_irqrestore(&chip->reg_lock, flags); - return 0; -} - -static int snd_cs4231_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; - unsigned short left, right; - int change; - - if (ucontrol->value.enumerated.item[0] > 3 || - ucontrol->value.enumerated.item[1] > 3) - return -EINVAL; - left = ucontrol->value.enumerated.item[0] << 6; - right = ucontrol->value.enumerated.item[1] << 6; - spin_lock_irqsave(&chip->reg_lock, flags); - left = (chip->image[CS4231_LEFT_INPUT] & ~CS4231_MIXS_ALL) | left; - right = (chip->image[CS4231_RIGHT_INPUT] & ~CS4231_MIXS_ALL) | right; - change = left != chip->image[CS4231_LEFT_INPUT] || - right != chip->image[CS4231_RIGHT_INPUT]; - snd_cs4231_out(chip, CS4231_LEFT_INPUT, left); - snd_cs4231_out(chip, CS4231_RIGHT_INPUT, right); - spin_unlock_irqrestore(&chip->reg_lock, flags); - return change; -} - -int snd_cs4231_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - int mask = (kcontrol->private_value >> 16) & 0xff; - - uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = mask; - return 0; -} - -int snd_cs4231_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; - int reg = kcontrol->private_value & 0xff; - int shift = (kcontrol->private_value >> 8) & 0xff; - int mask = (kcontrol->private_value >> 16) & 0xff; - int invert = (kcontrol->private_value >> 24) & 0xff; - - spin_lock_irqsave(&chip->reg_lock, flags); - ucontrol->value.integer.value[0] = (chip->image[reg] >> shift) & mask; - spin_unlock_irqrestore(&chip->reg_lock, flags); - if (invert) - ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; - return 0; -} - -int snd_cs4231_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; - int reg = kcontrol->private_value & 0xff; - int shift = (kcontrol->private_value >> 8) & 0xff; - int mask = (kcontrol->private_value >> 16) & 0xff; - int invert = (kcontrol->private_value >> 24) & 0xff; - int change; - unsigned short val; - - val = (ucontrol->value.integer.value[0] & mask); - if (invert) - val = mask - val; - val <<= shift; - spin_lock_irqsave(&chip->reg_lock, flags); - val = (chip->image[reg] & ~(mask << shift)) | val; - change = val != chip->image[reg]; - snd_cs4231_out(chip, reg, val); - spin_unlock_irqrestore(&chip->reg_lock, flags); - return change; -} - -int snd_cs4231_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - int mask = (kcontrol->private_value >> 24) & 0xff; - - uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 2; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = mask; - return 0; -} - -int snd_cs4231_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; - int left_reg = kcontrol->private_value & 0xff; - int right_reg = (kcontrol->private_value >> 8) & 0xff; - int shift_left = (kcontrol->private_value >> 16) & 0x07; - int shift_right = (kcontrol->private_value >> 19) & 0x07; - int mask = (kcontrol->private_value >> 24) & 0xff; - int invert = (kcontrol->private_value >> 22) & 1; - - spin_lock_irqsave(&chip->reg_lock, flags); - ucontrol->value.integer.value[0] = (chip->image[left_reg] >> shift_left) & mask; - ucontrol->value.integer.value[1] = (chip->image[right_reg] >> shift_right) & mask; - spin_unlock_irqrestore(&chip->reg_lock, flags); - if (invert) { - ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; - ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1]; - } - return 0; -} - -int snd_cs4231_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol); - unsigned long flags; - int left_reg = kcontrol->private_value & 0xff; - int right_reg = (kcontrol->private_value >> 8) & 0xff; - int shift_left = (kcontrol->private_value >> 16) & 0x07; - int shift_right = (kcontrol->private_value >> 19) & 0x07; - int mask = (kcontrol->private_value >> 24) & 0xff; - int invert = (kcontrol->private_value >> 22) & 1; - int change; - unsigned short val1, val2; - - val1 = ucontrol->value.integer.value[0] & mask; - val2 = ucontrol->value.integer.value[1] & mask; - if (invert) { - val1 = mask - val1; - val2 = mask - val2; - } - val1 <<= shift_left; - val2 <<= shift_right; - spin_lock_irqsave(&chip->reg_lock, flags); - val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1; - val2 = (chip->image[right_reg] & ~(mask << shift_right)) | val2; - change = val1 != chip->image[left_reg] || val2 != chip->image[right_reg]; - snd_cs4231_out(chip, left_reg, val1); - snd_cs4231_out(chip, right_reg, val2); - spin_unlock_irqrestore(&chip->reg_lock, flags); - return change; -} - -static struct snd_kcontrol_new snd_cs4231_controls[] = { -CS4231_DOUBLE("PCM Playback Switch", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1), -CS4231_DOUBLE("PCM Playback Volume", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1), -CS4231_DOUBLE("Line Playback Switch", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1), -CS4231_DOUBLE("Line Playback Volume", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1), -CS4231_DOUBLE("Aux Playback Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1), -CS4231_DOUBLE("Aux Playback Volume", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1), -CS4231_DOUBLE("Aux Playback Switch", 1, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1), -CS4231_DOUBLE("Aux Playback Volume", 1, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1), -CS4231_SINGLE("Mono Playback Switch", 0, CS4231_MONO_CTRL, 7, 1, 1), -CS4231_SINGLE("Mono Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1), -CS4231_SINGLE("Mono Output Playback Switch", 0, CS4231_MONO_CTRL, 6, 1, 1), -CS4231_SINGLE("Mono Output Playback Bypass", 0, CS4231_MONO_CTRL, 5, 1, 0), -CS4231_DOUBLE("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0), -{ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .info = snd_cs4231_info_mux, - .get = snd_cs4231_get_mux, - .put = snd_cs4231_put_mux, -}, -CS4231_DOUBLE("Mic Boost", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 5, 5, 1, 0), -CS4231_SINGLE("Loopback Capture Switch", 0, CS4231_LOOPBACK, 0, 1, 0), -CS4231_SINGLE("Loopback Capture Volume", 0, CS4231_LOOPBACK, 2, 63, 1) -}; - -static struct snd_kcontrol_new snd_opti93x_controls[] = { -CS4231_DOUBLE("Master Playback Switch", 0, - OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 7, 7, 1, 1), -CS4231_DOUBLE("Master Playback Volume", 0, - OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 1, 1, 31, 1), -CS4231_DOUBLE("PCM Playback Switch", 0, - CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1), -CS4231_DOUBLE("PCM Playback Volume", 0, - CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 31, 1), -CS4231_DOUBLE("FM Playback Switch", 0, - CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1), -CS4231_DOUBLE("FM Playback Volume", 0, - CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 1, 1, 15, 1), -CS4231_DOUBLE("Line Playback Switch", 0, - CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1), -CS4231_DOUBLE("Line Playback Volume", 0, - CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 15, 1), -CS4231_DOUBLE("Mic Playback Switch", 0, - OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 7, 7, 1, 1), -CS4231_DOUBLE("Mic Playback Volume", 0, - OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 1, 1, 15, 1), -CS4231_DOUBLE("Mic Boost", 0, - CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 5, 5, 1, 0), -CS4231_DOUBLE("CD Playback Switch", 0, - CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1), -CS4231_DOUBLE("CD Playback Volume", 0, - CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 1, 1, 15, 1), -CS4231_DOUBLE("Aux Playback Switch", 0, - OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 7, 7, 1, 1), -CS4231_DOUBLE("Aux Playback Volume", 0, - OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 1, 1, 15, 1), -CS4231_DOUBLE("Capture Volume", 0, - CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0), -{ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .info = snd_cs4231_info_mux, - .get = snd_cs4231_get_mux, - .put = snd_cs4231_put_mux, -} -}; - -int snd_cs4231_mixer(struct snd_cs4231 *chip) -{ - struct snd_card *card; - unsigned int idx; - int err; - - snd_assert(chip != NULL && chip->pcm != NULL, return -EINVAL); - - card = chip->card; - - strcpy(card->mixername, chip->pcm->name); - - if (chip->hardware == CS4231_HW_OPTI93X) - for (idx = 0; idx < ARRAY_SIZE(snd_opti93x_controls); idx++) { - err = snd_ctl_add(card, - snd_ctl_new1(&snd_opti93x_controls[idx], - chip)); - if (err < 0) - return err; - } - else - for (idx = 0; idx < ARRAY_SIZE(snd_cs4231_controls); idx++) { - err = snd_ctl_add(card, - snd_ctl_new1(&snd_cs4231_controls[idx], - chip)); - if (err < 0) - return err; - } - return 0; -} - -EXPORT_SYMBOL(snd_cs4231_out); -EXPORT_SYMBOL(snd_cs4231_in); -EXPORT_SYMBOL(snd_cs4236_ext_out); -EXPORT_SYMBOL(snd_cs4236_ext_in); -EXPORT_SYMBOL(snd_cs4231_mce_up); -EXPORT_SYMBOL(snd_cs4231_mce_down); -EXPORT_SYMBOL(snd_cs4231_overrange); -EXPORT_SYMBOL(snd_cs4231_interrupt); -EXPORT_SYMBOL(snd_cs4231_chip_id); -EXPORT_SYMBOL(snd_cs4231_create); -EXPORT_SYMBOL(snd_cs4231_pcm); -EXPORT_SYMBOL(snd_cs4231_mixer); -EXPORT_SYMBOL(snd_cs4231_timer); -EXPORT_SYMBOL(snd_cs4231_info_single); -EXPORT_SYMBOL(snd_cs4231_get_single); -EXPORT_SYMBOL(snd_cs4231_put_single); -EXPORT_SYMBOL(snd_cs4231_info_double); -EXPORT_SYMBOL(snd_cs4231_get_double); -EXPORT_SYMBOL(snd_cs4231_put_double); - -/* - * INIT part - */ - -static int __init alsa_cs4231_init(void) -{ - return 0; -} - -static void __exit alsa_cs4231_exit(void) -{ -} - -module_init(alsa_cs4231_init) -module_exit(alsa_cs4231_exit) diff --git a/sound/isa/cs423x/cs4236.c b/sound/isa/cs423x/cs4236.c index dbe63db4bfd..91f9c15d3e3 100644 --- a/sound/isa/cs423x/cs4236.c +++ b/sound/isa/cs423x/cs4236.c @@ -26,7 +26,7 @@ #include <linux/pnp.h> #include <linux/moduleparam.h> #include <sound/core.h> -#include <sound/cs4231.h> +#include <sound/wss.h> #include <sound/mpu401.h> #include <sound/opl3.h> #include <sound/initval.h> @@ -134,7 +134,7 @@ static int pnp_registered; #endif /* CONFIG_PNP */ struct snd_card_cs4236 { - struct snd_cs4231 *chip; + struct snd_wss *chip; struct resource *res_sb_port; #ifdef CONFIG_PNP struct pnp_dev *wss; @@ -239,6 +239,8 @@ static struct pnp_card_device_id snd_cs423x_pnpids[] = { { .id = "CSC9836", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } }, /* Gallant SC-70P */ { .id = "CSC9837", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } }, + /* Techmakers MF-4236PW */ + { .id = "CSCa736", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } }, /* TerraTec AudioSystem EWS64XL - CS4236B */ { .id = "CSCa836", .devs = { { "CSCa800" }, { "CSCa810" }, { "CSCa803" } } }, /* TerraTec AudioSystem EWS64XL - CS4236B */ @@ -325,6 +327,7 @@ static int __devinit snd_cs423x_pnp_init_mpu(int dev, struct pnp_dev *pdev) static int __devinit snd_card_cs4232_pnp(int dev, struct snd_card_cs4236 *acard, struct pnp_dev *pdev) { + acard->wss = pdev; if (snd_cs423x_pnp_init_wss(dev, acard->wss) < 0) return -EBUSY; cport[dev] = -1; @@ -395,7 +398,7 @@ static int __devinit snd_cs423x_probe(struct snd_card *card, int dev) { struct snd_card_cs4236 *acard; struct snd_pcm *pcm; - struct snd_cs4231 *chip; + struct snd_wss *chip; struct snd_opl3 *opl3; int err; @@ -407,41 +410,37 @@ static int __devinit snd_cs423x_probe(struct snd_card *card, int dev) } #ifdef CS4232 - if ((err = snd_cs4231_create(card, - port[dev], - cport[dev], - irq[dev], - dma1[dev], - dma2[dev], - CS4231_HW_DETECT, - 0, - &chip)) < 0) + err = snd_wss_create(card, port[dev], cport[dev], + irq[dev], + dma1[dev], dma2[dev], + WSS_HW_DETECT, 0, &chip); + if (err < 0) return err; acard->chip = chip; - if ((err = snd_cs4231_pcm(chip, 0, &pcm)) < 0) + err = snd_wss_pcm(chip, 0, &pcm); + if (err < 0) return err; - if ((err = snd_cs4231_mixer(chip)) < 0) + err = snd_wss_mixer(chip); + if (err < 0) return err; #else /* CS4236 */ - if ((err = snd_cs4236_create(card, - port[dev], - cport[dev], - irq[dev], - dma1[dev], - dma2[dev], - CS4231_HW_DETECT, - 0, - &chip)) < 0) + err = snd_cs4236_create(card, + port[dev], cport[dev], + irq[dev], dma1[dev], dma2[dev], + WSS_HW_DETECT, 0, &chip); + if (err < 0) return err; acard->chip = chip; - if ((err = snd_cs4236_pcm(chip, 0, &pcm)) < 0) + err = snd_cs4236_pcm(chip, 0, &pcm); + if (err < 0) return err; - if ((err = snd_cs4236_mixer(chip)) < 0) + err = snd_cs4236_mixer(chip); + if (err < 0) return err; #endif strcpy(card->driver, pcm->name); @@ -454,7 +453,8 @@ static int __devinit snd_cs423x_probe(struct snd_card *card, int dev) if (dma2[dev] >= 0) sprintf(card->longname + strlen(card->longname), "&%d", dma2[dev]); - if ((err = snd_cs4231_timer(chip, 0, NULL)) < 0) + err = snd_wss_timer(chip, 0, NULL); + if (err < 0) return err; if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) { diff --git a/sound/isa/cs423x/cs4236_lib.c b/sound/isa/cs423x/cs4236_lib.c index de71910401e..6a85fdc53b6 100644 --- a/sound/isa/cs423x/cs4236_lib.c +++ b/sound/isa/cs423x/cs4236_lib.c @@ -85,7 +85,7 @@ #include <linux/time.h> #include <linux/wait.h> #include <sound/core.h> -#include <sound/cs4231.h> +#include <sound/wss.h> #include <sound/asoundef.h> MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); @@ -121,13 +121,14 @@ static unsigned char snd_cs4236_ext_map[18] = { * */ -static void snd_cs4236_ctrl_out(struct snd_cs4231 *chip, unsigned char reg, unsigned char val) +static void snd_cs4236_ctrl_out(struct snd_wss *chip, + unsigned char reg, unsigned char val) { outb(reg, chip->cport + 3); outb(chip->cimage[reg] = val, chip->cport + 4); } -static unsigned char snd_cs4236_ctrl_in(struct snd_cs4231 *chip, unsigned char reg) +static unsigned char snd_cs4236_ctrl_in(struct snd_wss *chip, unsigned char reg) { outb(reg, chip->cport + 3); return inb(chip->cport + 4); @@ -180,44 +181,52 @@ static unsigned char divisor_to_rate_register(unsigned int divisor) } } -static void snd_cs4236_playback_format(struct snd_cs4231 *chip, struct snd_pcm_hw_params *params, unsigned char pdfr) +static void snd_cs4236_playback_format(struct snd_wss *chip, + struct snd_pcm_hw_params *params, + unsigned char pdfr) { unsigned long flags; unsigned char rate = divisor_to_rate_register(params->rate_den); spin_lock_irqsave(&chip->reg_lock, flags); /* set fast playback format change and clean playback FIFO */ - snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] | 0x10); - snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT, pdfr & 0xf0); - snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] & ~0x10); + snd_wss_out(chip, CS4231_ALT_FEATURE_1, + chip->image[CS4231_ALT_FEATURE_1] | 0x10); + snd_wss_out(chip, CS4231_PLAYBK_FORMAT, pdfr & 0xf0); + snd_wss_out(chip, CS4231_ALT_FEATURE_1, + chip->image[CS4231_ALT_FEATURE_1] & ~0x10); snd_cs4236_ext_out(chip, CS4236_DAC_RATE, rate); spin_unlock_irqrestore(&chip->reg_lock, flags); } -static void snd_cs4236_capture_format(struct snd_cs4231 *chip, struct snd_pcm_hw_params *params, unsigned char cdfr) +static void snd_cs4236_capture_format(struct snd_wss *chip, + struct snd_pcm_hw_params *params, + unsigned char cdfr) { unsigned long flags; unsigned char rate = divisor_to_rate_register(params->rate_den); spin_lock_irqsave(&chip->reg_lock, flags); /* set fast capture format change and clean capture FIFO */ - snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] | 0x20); - snd_cs4231_out(chip, CS4231_REC_FORMAT, cdfr & 0xf0); - snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] & ~0x20); + snd_wss_out(chip, CS4231_ALT_FEATURE_1, + chip->image[CS4231_ALT_FEATURE_1] | 0x20); + snd_wss_out(chip, CS4231_REC_FORMAT, cdfr & 0xf0); + snd_wss_out(chip, CS4231_ALT_FEATURE_1, + chip->image[CS4231_ALT_FEATURE_1] & ~0x20); snd_cs4236_ext_out(chip, CS4236_ADC_RATE, rate); spin_unlock_irqrestore(&chip->reg_lock, flags); } #ifdef CONFIG_PM -static void snd_cs4236_suspend(struct snd_cs4231 *chip) +static void snd_cs4236_suspend(struct snd_wss *chip) { int reg; unsigned long flags; spin_lock_irqsave(&chip->reg_lock, flags); for (reg = 0; reg < 32; reg++) - chip->image[reg] = snd_cs4231_in(chip, reg); + chip->image[reg] = snd_wss_in(chip, reg); for (reg = 0; reg < 18; reg++) chip->eimage[reg] = snd_cs4236_ext_in(chip, CS4236_I23VAL(reg)); for (reg = 2; reg < 9; reg++) @@ -225,12 +234,12 @@ static void snd_cs4236_suspend(struct snd_cs4231 *chip) spin_unlock_irqrestore(&chip->reg_lock, flags); } -static void snd_cs4236_resume(struct snd_cs4231 *chip) +static void snd_cs4236_resume(struct snd_wss *chip) { int reg; unsigned long flags; - snd_cs4231_mce_up(chip); + snd_wss_mce_up(chip); spin_lock_irqsave(&chip->reg_lock, flags); for (reg = 0; reg < 32; reg++) { switch (reg) { @@ -240,7 +249,7 @@ static void snd_cs4236_resume(struct snd_cs4231 *chip) case 29: /* why? CS4235 - master right */ break; default: - snd_cs4231_out(chip, reg, chip->image[reg]); + snd_wss_out(chip, reg, chip->image[reg]); break; } } @@ -255,7 +264,7 @@ static void snd_cs4236_resume(struct snd_cs4231 *chip) } } spin_unlock_irqrestore(&chip->reg_lock, flags); - snd_cs4231_mce_down(chip); + snd_wss_mce_down(chip); } #endif /* CONFIG_PM */ @@ -266,24 +275,26 @@ int snd_cs4236_create(struct snd_card *card, int irq, int dma1, int dma2, unsigned short hardware, unsigned short hwshare, - struct snd_cs4231 ** rchip) + struct snd_wss **rchip) { - struct snd_cs4231 *chip; + struct snd_wss *chip; unsigned char ver1, ver2; unsigned int reg; int err; *rchip = NULL; - if (hardware == CS4231_HW_DETECT) - hardware = CS4231_HW_DETECT3; + if (hardware == WSS_HW_DETECT) + hardware = WSS_HW_DETECT3; if (cport < 0x100) { snd_printk("please, specify control port for CS4236+ chips\n"); return -ENODEV; } - if ((err = snd_cs4231_create(card, port, cport, irq, dma1, dma2, hardware, hwshare, &chip)) < 0) + err = snd_wss_create(card, port, cport, + irq, dma1, dma2, hardware, hwshare, &chip); + if (err < 0) return err; - if (!(chip->hardware & CS4231_HW_CS4236B_MASK)) { + if (!(chip->hardware & WSS_HW_CS4236B_MASK)) { snd_printk("CS4236+: MODE3 and extended registers not available, hardware=0x%x\n",chip->hardware); snd_device_free(card, chip); return -ENODEV; @@ -330,20 +341,20 @@ int snd_cs4236_create(struct snd_card *card, snd_cs4236_ext_out(chip, CS4236_I23VAL(reg), snd_cs4236_ext_map[reg]); /* initialize compatible but more featured registers */ - snd_cs4231_out(chip, CS4231_LEFT_INPUT, 0x40); - snd_cs4231_out(chip, CS4231_RIGHT_INPUT, 0x40); - snd_cs4231_out(chip, CS4231_AUX1_LEFT_INPUT, 0xff); - snd_cs4231_out(chip, CS4231_AUX1_RIGHT_INPUT, 0xff); - snd_cs4231_out(chip, CS4231_AUX2_LEFT_INPUT, 0xdf); - snd_cs4231_out(chip, CS4231_AUX2_RIGHT_INPUT, 0xdf); - snd_cs4231_out(chip, CS4231_RIGHT_LINE_IN, 0xff); - snd_cs4231_out(chip, CS4231_LEFT_LINE_IN, 0xff); - snd_cs4231_out(chip, CS4231_RIGHT_LINE_IN, 0xff); + snd_wss_out(chip, CS4231_LEFT_INPUT, 0x40); + snd_wss_out(chip, CS4231_RIGHT_INPUT, 0x40); + snd_wss_out(chip, CS4231_AUX1_LEFT_INPUT, 0xff); + snd_wss_out(chip, CS4231_AUX1_RIGHT_INPUT, 0xff); + snd_wss_out(chip, CS4231_AUX2_LEFT_INPUT, 0xdf); + snd_wss_out(chip, CS4231_AUX2_RIGHT_INPUT, 0xdf); + snd_wss_out(chip, CS4231_RIGHT_LINE_IN, 0xff); + snd_wss_out(chip, CS4231_LEFT_LINE_IN, 0xff); + snd_wss_out(chip, CS4231_RIGHT_LINE_IN, 0xff); switch (chip->hardware) { - case CS4231_HW_CS4235: - case CS4231_HW_CS4239: - snd_cs4231_out(chip, CS4235_LEFT_MASTER, 0xff); - snd_cs4231_out(chip, CS4235_RIGHT_MASTER, 0xff); + case WSS_HW_CS4235: + case WSS_HW_CS4239: + snd_wss_out(chip, CS4235_LEFT_MASTER, 0xff); + snd_wss_out(chip, CS4235_RIGHT_MASTER, 0xff); break; } @@ -351,12 +362,13 @@ int snd_cs4236_create(struct snd_card *card, return 0; } -int snd_cs4236_pcm(struct snd_cs4231 *chip, int device, struct snd_pcm **rpcm) +int snd_cs4236_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm) { struct snd_pcm *pcm; int err; - if ((err = snd_cs4231_pcm(chip, device, &pcm)) < 0) + err = snd_wss_pcm(chip, device, &pcm); + if (err < 0) return err; pcm->info_flags &= ~SNDRV_PCM_INFO_JOINT_DUPLEX; if (rpcm) @@ -387,7 +399,7 @@ static int snd_cs4236_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_ static int snd_cs4236_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol); + struct snd_wss *chip = snd_kcontrol_chip(kcontrol); unsigned long flags; int reg = kcontrol->private_value & 0xff; int shift = (kcontrol->private_value >> 8) & 0xff; @@ -404,7 +416,7 @@ static int snd_cs4236_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_e static int snd_cs4236_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol); + struct snd_wss *chip = snd_kcontrol_chip(kcontrol); unsigned long flags; int reg = kcontrol->private_value & 0xff; int shift = (kcontrol->private_value >> 8) & 0xff; @@ -433,7 +445,7 @@ static int snd_cs4236_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_e static int snd_cs4236_get_singlec(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol); + struct snd_wss *chip = snd_kcontrol_chip(kcontrol); unsigned long flags; int reg = kcontrol->private_value & 0xff; int shift = (kcontrol->private_value >> 8) & 0xff; @@ -450,7 +462,7 @@ static int snd_cs4236_get_singlec(struct snd_kcontrol *kcontrol, struct snd_ctl_ static int snd_cs4236_put_singlec(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol); + struct snd_wss *chip = snd_kcontrol_chip(kcontrol); unsigned long flags; int reg = kcontrol->private_value & 0xff; int shift = (kcontrol->private_value >> 8) & 0xff; @@ -490,7 +502,7 @@ static int snd_cs4236_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_ static int snd_cs4236_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol); + struct snd_wss *chip = snd_kcontrol_chip(kcontrol); unsigned long flags; int left_reg = kcontrol->private_value & 0xff; int right_reg = (kcontrol->private_value >> 8) & 0xff; @@ -512,7 +524,7 @@ static int snd_cs4236_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e static int snd_cs4236_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol); + struct snd_wss *chip = snd_kcontrol_chip(kcontrol); unsigned long flags; int left_reg = kcontrol->private_value & 0xff; int right_reg = (kcontrol->private_value >> 8) & 0xff; @@ -555,7 +567,7 @@ static int snd_cs4236_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e static int snd_cs4236_get_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol); + struct snd_wss *chip = snd_kcontrol_chip(kcontrol); unsigned long flags; int left_reg = kcontrol->private_value & 0xff; int right_reg = (kcontrol->private_value >> 8) & 0xff; @@ -577,7 +589,7 @@ static int snd_cs4236_get_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_ static int snd_cs4236_put_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol); + struct snd_wss *chip = snd_kcontrol_chip(kcontrol); unsigned long flags; int left_reg = kcontrol->private_value & 0xff; int right_reg = (kcontrol->private_value >> 8) & 0xff; @@ -600,7 +612,7 @@ static int snd_cs4236_put_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_ val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1; val2 = (chip->eimage[CS4236_REG(right_reg)] & ~(mask << shift_right)) | val2; change = val1 != chip->image[left_reg] || val2 != chip->eimage[CS4236_REG(right_reg)]; - snd_cs4231_out(chip, left_reg, val1); + snd_wss_out(chip, left_reg, val1); snd_cs4236_ext_out(chip, right_reg, val2); spin_unlock_irqrestore(&chip->reg_lock, flags); return change; @@ -619,7 +631,7 @@ static inline int snd_cs4236_mixer_master_digital_invert_volume(int vol) static int snd_cs4236_get_master_digital(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol); + struct snd_wss *chip = snd_kcontrol_chip(kcontrol); unsigned long flags; spin_lock_irqsave(&chip->reg_lock, flags); @@ -631,7 +643,7 @@ static int snd_cs4236_get_master_digital(struct snd_kcontrol *kcontrol, struct s static int snd_cs4236_put_master_digital(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol); + struct snd_wss *chip = snd_kcontrol_chip(kcontrol); unsigned long flags; int change; unsigned short val1, val2; @@ -678,7 +690,7 @@ static inline int snd_cs4235_mixer_output_accu_set_volume(int vol) static int snd_cs4235_get_output_accu(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol); + struct snd_wss *chip = snd_kcontrol_chip(kcontrol); unsigned long flags; spin_lock_irqsave(&chip->reg_lock, flags); @@ -690,7 +702,7 @@ static int snd_cs4235_get_output_accu(struct snd_kcontrol *kcontrol, struct snd_ static int snd_cs4235_put_output_accu(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol); + struct snd_wss *chip = snd_kcontrol_chip(kcontrol); unsigned long flags; int change; unsigned short val1, val2; @@ -701,108 +713,160 @@ static int snd_cs4235_put_output_accu(struct snd_kcontrol *kcontrol, struct snd_ val1 = (chip->image[CS4235_LEFT_MASTER] & ~(3 << 5)) | val1; val2 = (chip->image[CS4235_RIGHT_MASTER] & ~(3 << 5)) | val2; change = val1 != chip->image[CS4235_LEFT_MASTER] || val2 != chip->image[CS4235_RIGHT_MASTER]; - snd_cs4231_out(chip, CS4235_LEFT_MASTER, val1); - snd_cs4231_out(chip, CS4235_RIGHT_MASTER, val2); + snd_wss_out(chip, CS4235_LEFT_MASTER, val1); + snd_wss_out(chip, CS4235_RIGHT_MASTER, val2); spin_unlock_irqrestore(&chip->reg_lock, flags); return change; } static struct snd_kcontrol_new snd_cs4236_controls[] = { -CS4236_DOUBLE("Master Digital Playback Switch", 0, CS4236_LEFT_MASTER, CS4236_RIGHT_MASTER, 7, 7, 1, 1), -CS4236_DOUBLE("Master Digital Capture Switch", 0, CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1), +CS4236_DOUBLE("Master Digital Playback Switch", 0, + CS4236_LEFT_MASTER, CS4236_RIGHT_MASTER, 7, 7, 1, 1), +CS4236_DOUBLE("Master Digital Capture Switch", 0, + CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1), CS4236_MASTER_DIGITAL("Master Digital Volume", 0), -CS4236_DOUBLE("Capture Boost Volume", 0, CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1), - -CS4231_DOUBLE("PCM Playback Switch", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1), -CS4231_DOUBLE("PCM Playback Volume", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1), - -CS4236_DOUBLE("DSP Playback Switch", 0, CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 7, 7, 1, 1), -CS4236_DOUBLE("DSP Playback Volume", 0, CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 0, 0, 63, 1), - -CS4236_DOUBLE("FM Playback Switch", 0, CS4236_LEFT_FM, CS4236_RIGHT_FM, 7, 7, 1, 1), -CS4236_DOUBLE("FM Playback Volume", 0, CS4236_LEFT_FM, CS4236_RIGHT_FM, 0, 0, 63, 1), - -CS4236_DOUBLE("Wavetable Playback Switch", 0, CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 7, 7, 1, 1), -CS4236_DOUBLE("Wavetable Playback Volume", 0, CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 0, 0, 63, 1), - -CS4231_DOUBLE("Synth Playback Switch", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1), -CS4231_DOUBLE("Synth Volume", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1), -CS4231_DOUBLE("Synth Capture Switch", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 6, 6, 1, 1), -CS4231_DOUBLE("Synth Capture Bypass", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 5, 5, 1, 1), - -CS4236_DOUBLE("Mic Playback Switch", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 6, 6, 1, 1), -CS4236_DOUBLE("Mic Capture Switch", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 7, 7, 1, 1), +CS4236_DOUBLE("Capture Boost Volume", 0, + CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1), + +WSS_DOUBLE("PCM Playback Switch", 0, + CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1), +WSS_DOUBLE("PCM Playback Volume", 0, + CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1), + +CS4236_DOUBLE("DSP Playback Switch", 0, + CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 7, 7, 1, 1), +CS4236_DOUBLE("DSP Playback Volume", 0, + CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 0, 0, 63, 1), + +CS4236_DOUBLE("FM Playback Switch", 0, + CS4236_LEFT_FM, CS4236_RIGHT_FM, 7, 7, 1, 1), +CS4236_DOUBLE("FM Playback Volume", 0, + CS4236_LEFT_FM, CS4236_RIGHT_FM, 0, 0, 63, 1), + +CS4236_DOUBLE("Wavetable Playback Switch", 0, + CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 7, 7, 1, 1), +CS4236_DOUBLE("Wavetable Playback Volume", 0, + CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 0, 0, 63, 1), + +WSS_DOUBLE("Synth Playback Switch", 0, + CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1), +WSS_DOUBLE("Synth Volume", 0, + CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1), +WSS_DOUBLE("Synth Capture Switch", 0, + CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 6, 6, 1, 1), +WSS_DOUBLE("Synth Capture Bypass", 0, + CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 5, 5, 1, 1), + +CS4236_DOUBLE("Mic Playback Switch", 0, + CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 6, 6, 1, 1), +CS4236_DOUBLE("Mic Capture Switch", 0, + CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 7, 7, 1, 1), CS4236_DOUBLE("Mic Volume", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 0, 0, 31, 1), -CS4236_DOUBLE("Mic Playback Boost", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 5, 5, 1, 0), - -CS4231_DOUBLE("Line Playback Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1), -CS4231_DOUBLE("Line Volume", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1), -CS4231_DOUBLE("Line Capture Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 6, 6, 1, 1), -CS4231_DOUBLE("Line Capture Bypass", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 5, 5, 1, 1), - -CS4231_DOUBLE("CD Playback Switch", 0, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1), -CS4231_DOUBLE("CD Volume", 0, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1), -CS4231_DOUBLE("CD Capture Switch", 0, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 6, 6, 1, 1), - -CS4236_DOUBLE1("Mono Output Playback Switch", 0, CS4231_MONO_CTRL, CS4236_RIGHT_MIX_CTRL, 6, 7, 1, 1), -CS4236_DOUBLE1("Mono Playback Switch", 0, CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, 7, 1, 1), -CS4231_SINGLE("Mono Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1), -CS4231_SINGLE("Mono Playback Bypass", 0, CS4231_MONO_CTRL, 5, 1, 0), - -CS4231_DOUBLE("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0), -CS4231_DOUBLE("Analog Loopback Capture Switch", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 7, 7, 1, 0), - -CS4231_SINGLE("Digital Loopback Playback Switch", 0, CS4231_LOOPBACK, 0, 1, 0), -CS4236_DOUBLE1("Digital Loopback Playback Volume", 0, CS4231_LOOPBACK, CS4236_RIGHT_LOOPBACK, 2, 0, 63, 1) +CS4236_DOUBLE("Mic Playback Boost", 0, + CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 5, 5, 1, 0), + +WSS_DOUBLE("Line Playback Switch", 0, + CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1), +WSS_DOUBLE("Line Volume", 0, + CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1), +WSS_DOUBLE("Line Capture Switch", 0, + CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 6, 6, 1, 1), +WSS_DOUBLE("Line Capture Bypass", 0, + CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 5, 5, 1, 1), + +WSS_DOUBLE("CD Playback Switch", 0, + CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1), +WSS_DOUBLE("CD Volume", 0, + CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1), +WSS_DOUBLE("CD Capture Switch", 0, + CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 6, 6, 1, 1), + +CS4236_DOUBLE1("Mono Output Playback Switch", 0, + CS4231_MONO_CTRL, CS4236_RIGHT_MIX_CTRL, 6, 7, 1, 1), +CS4236_DOUBLE1("Mono Playback Switch", 0, + CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, 7, 1, 1), +WSS_SINGLE("Mono Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1), +WSS_SINGLE("Mono Playback Bypass", 0, CS4231_MONO_CTRL, 5, 1, 0), + +WSS_DOUBLE("Capture Volume", 0, + CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0), +WSS_DOUBLE("Analog Loopback Capture Switch", 0, + CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 7, 7, 1, 0), + +WSS_SINGLE("Digital Loopback Playback Switch", 0, CS4231_LOOPBACK, 0, 1, 0), +CS4236_DOUBLE1("Digital Loopback Playback Volume", 0, + CS4231_LOOPBACK, CS4236_RIGHT_LOOPBACK, 2, 0, 63, 1) }; static struct snd_kcontrol_new snd_cs4235_controls[] = { -CS4231_DOUBLE("Master Switch", 0, CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 7, 7, 1, 1), -CS4231_DOUBLE("Master Volume", 0, CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 0, 0, 31, 1), +WSS_DOUBLE("Master Switch", 0, + CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 7, 7, 1, 1), +WSS_DOUBLE("Master Volume", 0, + CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 0, 0, 31, 1), CS4235_OUTPUT_ACCU("Playback Volume", 0), -CS4236_DOUBLE("Master Digital Playback Switch", 0, CS4236_LEFT_MASTER, CS4236_RIGHT_MASTER, 7, 7, 1, 1), -CS4236_DOUBLE("Master Digital Capture Switch", 0, CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1), +CS4236_DOUBLE("Master Digital Playback Switch", 0, + CS4236_LEFT_MASTER, CS4236_RIGHT_MASTER, 7, 7, 1, 1), +CS4236_DOUBLE("Master Digital Capture Switch", 0, + CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1), CS4236_MASTER_DIGITAL("Master Digital Volume", 0), -CS4231_DOUBLE("Master Digital Playback Switch", 1, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1), -CS4231_DOUBLE("Master Digital Capture Switch", 1, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 6, 6, 1, 1), -CS4231_DOUBLE("Master Digital Volume", 1, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1), +WSS_DOUBLE("Master Digital Playback Switch", 1, + CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1), +WSS_DOUBLE("Master Digital Capture Switch", 1, + CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 6, 6, 1, 1), +WSS_DOUBLE("Master Digital Volume", 1, + CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1), -CS4236_DOUBLE("Capture Volume", 0, CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1), +CS4236_DOUBLE("Capture Volume", 0, + CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1), -CS4231_DOUBLE("PCM Switch", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1), -CS4231_DOUBLE("PCM Volume", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1), +WSS_DOUBLE("PCM Switch", 0, + CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1), +WSS_DOUBLE("PCM Volume", 0, + CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1), CS4236_DOUBLE("DSP Switch", 0, CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 7, 7, 1, 1), CS4236_DOUBLE("FM Switch", 0, CS4236_LEFT_FM, CS4236_RIGHT_FM, 7, 7, 1, 1), -CS4236_DOUBLE("Wavetable Switch", 0, CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 7, 7, 1, 1), +CS4236_DOUBLE("Wavetable Switch", 0, + CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 7, 7, 1, 1), -CS4236_DOUBLE("Mic Capture Switch", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 7, 7, 1, 1), -CS4236_DOUBLE("Mic Playback Switch", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 6, 6, 1, 1), +CS4236_DOUBLE("Mic Capture Switch", 0, + CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 7, 7, 1, 1), +CS4236_DOUBLE("Mic Playback Switch", 0, + CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 6, 6, 1, 1), CS4236_SINGLE("Mic Volume", 0, CS4236_LEFT_MIC, 0, 31, 1), CS4236_SINGLE("Mic Playback Boost", 0, CS4236_LEFT_MIC, 5, 1, 0), -CS4231_DOUBLE("Aux Playback Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1), -CS4231_DOUBLE("Aux Capture Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 6, 6, 1, 1), -CS4231_DOUBLE("Aux Volume", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1), - -CS4231_DOUBLE("Aux Playback Switch", 1, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1), -CS4231_DOUBLE("Aux Capture Switch", 1, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 6, 6, 1, 1), -CS4231_DOUBLE("Aux Volume", 1, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1), - -CS4236_DOUBLE1("Master Mono Switch", 0, CS4231_MONO_CTRL, CS4236_RIGHT_MIX_CTRL, 6, 7, 1, 1), - -CS4236_DOUBLE1("Mono Switch", 0, CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, 7, 1, 1), -CS4231_SINGLE("Mono Volume", 0, CS4231_MONO_CTRL, 0, 15, 1), - -CS4231_DOUBLE("Analog Loopback Switch", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 7, 7, 1, 0), +WSS_DOUBLE("Aux Playback Switch", 0, + CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1), +WSS_DOUBLE("Aux Capture Switch", 0, + CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 6, 6, 1, 1), +WSS_DOUBLE("Aux Volume", 0, + CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1), + +WSS_DOUBLE("Aux Playback Switch", 1, + CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1), +WSS_DOUBLE("Aux Capture Switch", 1, + CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 6, 6, 1, 1), +WSS_DOUBLE("Aux Volume", 1, + CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1), + +CS4236_DOUBLE1("Master Mono Switch", 0, + CS4231_MONO_CTRL, CS4236_RIGHT_MIX_CTRL, 6, 7, 1, 1), + +CS4236_DOUBLE1("Mono Switch", 0, + CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, 7, 1, 1), +WSS_SINGLE("Mono Volume", 0, CS4231_MONO_CTRL, 0, 15, 1), + +WSS_DOUBLE("Analog Loopback Switch", 0, + CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 7, 7, 1, 0), }; #define CS4236_IEC958_ENABLE(xname, xindex) \ @@ -813,14 +877,14 @@ CS4231_DOUBLE("Analog Loopback Switch", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT static int snd_cs4236_get_iec958_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol); + struct snd_wss *chip = snd_kcontrol_chip(kcontrol); unsigned long flags; spin_lock_irqsave(&chip->reg_lock, flags); ucontrol->value.integer.value[0] = chip->image[CS4231_ALT_FEATURE_1] & 0x02 ? 1 : 0; #if 0 printk("get valid: ALT = 0x%x, C3 = 0x%x, C4 = 0x%x, C5 = 0x%x, C6 = 0x%x, C8 = 0x%x\n", - snd_cs4231_in(chip, CS4231_ALT_FEATURE_1), + snd_wss_in(chip, CS4231_ALT_FEATURE_1), snd_cs4236_ctrl_in(chip, 3), snd_cs4236_ctrl_in(chip, 4), snd_cs4236_ctrl_in(chip, 5), @@ -833,7 +897,7 @@ static int snd_cs4236_get_iec958_switch(struct snd_kcontrol *kcontrol, struct sn static int snd_cs4236_put_iec958_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol); + struct snd_wss *chip = snd_kcontrol_chip(kcontrol); unsigned long flags; int change; unsigned short enable, val; @@ -841,23 +905,23 @@ static int snd_cs4236_put_iec958_switch(struct snd_kcontrol *kcontrol, struct sn enable = ucontrol->value.integer.value[0] & 1; mutex_lock(&chip->mce_mutex); - snd_cs4231_mce_up(chip); + snd_wss_mce_up(chip); spin_lock_irqsave(&chip->reg_lock, flags); val = (chip->image[CS4231_ALT_FEATURE_1] & ~0x0e) | (0<<2) | (enable << 1); change = val != chip->image[CS4231_ALT_FEATURE_1]; - snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, val); + snd_wss_out(chip, CS4231_ALT_FEATURE_1, val); val = snd_cs4236_ctrl_in(chip, 4) | 0xc0; snd_cs4236_ctrl_out(chip, 4, val); udelay(100); val &= ~0x40; snd_cs4236_ctrl_out(chip, 4, val); spin_unlock_irqrestore(&chip->reg_lock, flags); - snd_cs4231_mce_down(chip); + snd_wss_mce_down(chip); mutex_unlock(&chip->mce_mutex); #if 0 printk("set valid: ALT = 0x%x, C3 = 0x%x, C4 = 0x%x, C5 = 0x%x, C6 = 0x%x, C8 = 0x%x\n", - snd_cs4231_in(chip, CS4231_ALT_FEATURE_1), + snd_wss_in(chip, CS4231_ALT_FEATURE_1), snd_cs4236_ctrl_in(chip, 3), snd_cs4236_ctrl_in(chip, 4), snd_cs4236_ctrl_in(chip, 5), @@ -896,19 +960,20 @@ CS4236_SINGLEC("3D Control - Volume", 0, 2, 0, 15, 1), CS4236_SINGLEC("3D Control - IEC958", 0, 3, 5, 1, 0) }; -int snd_cs4236_mixer(struct snd_cs4231 *chip) +int snd_cs4236_mixer(struct snd_wss *chip) { struct snd_card *card; unsigned int idx, count; int err; struct snd_kcontrol_new *kcontrol; - snd_assert(chip != NULL && chip->card != NULL, return -EINVAL); + if (snd_BUG_ON(!chip || !chip->card)) + return -EINVAL; card = chip->card; - strcpy(card->mixername, snd_cs4231_chip_id(chip)); + strcpy(card->mixername, snd_wss_chip_id(chip)); - if (chip->hardware == CS4231_HW_CS4235 || - chip->hardware == CS4231_HW_CS4239) { + if (chip->hardware == WSS_HW_CS4235 || + chip->hardware == WSS_HW_CS4239) { for (idx = 0; idx < ARRAY_SIZE(snd_cs4235_controls); idx++) { if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4235_controls[idx], chip))) < 0) return err; @@ -920,16 +985,16 @@ int snd_cs4236_mixer(struct snd_cs4231 *chip) } } switch (chip->hardware) { - case CS4231_HW_CS4235: - case CS4231_HW_CS4239: + case WSS_HW_CS4235: + case WSS_HW_CS4239: count = ARRAY_SIZE(snd_cs4236_3d_controls_cs4235); kcontrol = snd_cs4236_3d_controls_cs4235; break; - case CS4231_HW_CS4237B: + case WSS_HW_CS4237B: count = ARRAY_SIZE(snd_cs4236_3d_controls_cs4237); kcontrol = snd_cs4236_3d_controls_cs4237; break; - case CS4231_HW_CS4238B: + case WSS_HW_CS4238B: count = ARRAY_SIZE(snd_cs4236_3d_controls_cs4238); kcontrol = snd_cs4236_3d_controls_cs4238; break; @@ -941,8 +1006,8 @@ int snd_cs4236_mixer(struct snd_cs4231 *chip) if ((err = snd_ctl_add(card, snd_ctl_new1(kcontrol, chip))) < 0) return err; } - if (chip->hardware == CS4231_HW_CS4237B || - chip->hardware == CS4231_HW_CS4238B) { + if (chip->hardware == WSS_HW_CS4237B || + chip->hardware == WSS_HW_CS4238B) { for (idx = 0; idx < ARRAY_SIZE(snd_cs4236_iec958_controls); idx++) { if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4236_iec958_controls[idx], chip))) < 0) return err; diff --git a/sound/isa/es1688/es1688_lib.c b/sound/isa/es1688/es1688_lib.c index 1e1e575b1db..4fbb508a817 100644 --- a/sound/isa/es1688/es1688_lib.c +++ b/sound/isa/es1688/es1688_lib.c @@ -1009,7 +1009,8 @@ int snd_es1688_mixer(struct snd_es1688 *chip) int err; unsigned char reg, val; - snd_assert(chip != NULL && chip->card != NULL, return -EINVAL); + if (snd_BUG_ON(!chip || !chip->card)) + return -EINVAL; card = chip->card; diff --git a/sound/isa/gus/gus_main.c b/sound/isa/gus/gus_main.c index cccc16c8113..12eb98f2f93 100644 --- a/sound/isa/gus/gus_main.c +++ b/sound/isa/gus/gus_main.c @@ -276,9 +276,11 @@ static int snd_gus_init_dma_irq(struct snd_gus_card * gus, int latches) static unsigned char dmas[8] = {6, 1, 0, 2, 0, 3, 4, 5}; - snd_assert(gus != NULL, return -EINVAL); + if (snd_BUG_ON(!gus)) + return -EINVAL; card = gus->card; - snd_assert(card != NULL, return -EINVAL); + if (snd_BUG_ON(!card)) + return -EINVAL; gus->mix_cntrl_reg &= 0xf8; gus->mix_cntrl_reg |= 0x01; /* disable MIC, LINE IN, enable LINE OUT */ diff --git a/sound/isa/gus/gus_mixer.c b/sound/isa/gus/gus_mixer.c index ebdb3346930..0dd43414016 100644 --- a/sound/isa/gus/gus_mixer.c +++ b/sound/isa/gus/gus_mixer.c @@ -161,9 +161,11 @@ int snd_gf1_new_mixer(struct snd_gus_card * gus) unsigned int idx, max; int err; - snd_assert(gus != NULL, return -EINVAL); + if (snd_BUG_ON(!gus)) + return -EINVAL; card = gus->card; - snd_assert(card != NULL, return -EINVAL); + if (snd_BUG_ON(!card)) + return -EINVAL; if (gus->ics_flag) snd_component_add(card, "ICS2101"); diff --git a/sound/isa/gus/gus_pcm.c b/sound/isa/gus/gus_pcm.c index 99731dc9732..38510aeb21c 100644 --- a/sound/isa/gus/gus_pcm.c +++ b/sound/isa/gus/gus_pcm.c @@ -352,8 +352,10 @@ static int snd_gf1_pcm_playback_copy(struct snd_pcm_substream *substream, bpos = samples_to_bytes(runtime, pos) + (voice * (pcmp->dma_size / 2)); len = samples_to_bytes(runtime, count); - snd_assert(bpos <= pcmp->dma_size, return -EIO); - snd_assert(bpos + len <= pcmp->dma_size, return -EIO); + if (snd_BUG_ON(bpos > pcmp->dma_size)) + return -EIO; + if (snd_BUG_ON(bpos + len > pcmp->dma_size)) + return -EIO; if (copy_from_user(runtime->dma_area + bpos, src, len)) return -EFAULT; if (snd_gf1_pcm_use_dma && len > 32) { @@ -381,8 +383,10 @@ static int snd_gf1_pcm_playback_silence(struct snd_pcm_substream *substream, bpos = samples_to_bytes(runtime, pos) + (voice * (pcmp->dma_size / 2)); len = samples_to_bytes(runtime, count); - snd_assert(bpos <= pcmp->dma_size, return -EIO); - snd_assert(bpos + len <= pcmp->dma_size, return -EIO); + if (snd_BUG_ON(bpos > pcmp->dma_size)) + return -EIO; + if (snd_BUG_ON(bpos + len > pcmp->dma_size)) + return -EIO; snd_pcm_format_set_silence(runtime->format, runtime->dma_area + bpos, count); if (snd_gf1_pcm_use_dma && len > 32) { return snd_gf1_pcm_block_change(substream, bpos, pcmp->memory + bpos, len); diff --git a/sound/isa/gus/gusmax.c b/sound/isa/gus/gusmax.c index f87c6236661..f94c1976e63 100644 --- a/sound/isa/gus/gusmax.c +++ b/sound/isa/gus/gusmax.c @@ -28,7 +28,7 @@ #include <asm/dma.h> #include <sound/core.h> #include <sound/gus.h> -#include <sound/cs4231.h> +#include <sound/wss.h> #define SNDRV_LEGACY_FIND_FREE_IRQ #define SNDRV_LEGACY_FIND_FREE_DMA #include <sound/initval.h> @@ -75,7 +75,7 @@ struct snd_gusmax { int irq; struct snd_card *card; struct snd_gus_card *gus; - struct snd_cs4231 *cs4231; + struct snd_wss *wss; unsigned short gus_status_reg; unsigned short pcm_status_reg; }; @@ -117,7 +117,7 @@ static irqreturn_t snd_gusmax_interrupt(int irq, void *dev_id) } if (inb(maxcard->pcm_status_reg) & 0x01) { /* IRQ bit is set? */ handled = 1; - snd_cs4231_interrupt(irq, maxcard->cs4231); + snd_wss_interrupt(irq, maxcard->wss); loop++; } } while (loop && --max > 0); @@ -140,10 +140,7 @@ static void __devinit snd_gusmax_init(int dev, struct snd_card *card, outb(gus->max_cntrl_val, GUSP(gus, MAXCNTRLPORT)); } -#define CS4231_PRIVATE( left, right, shift, mute ) \ - ((left << 24)|(right << 16)|(shift<<8)|mute) - -static int __devinit snd_gusmax_mixer(struct snd_cs4231 *chip) +static int __devinit snd_gusmax_mixer(struct snd_wss *chip) { struct snd_card *card = chip->card; struct snd_ctl_elem_id id1, id2; @@ -214,7 +211,7 @@ static int __devinit snd_gusmax_probe(struct device *pdev, unsigned int dev) int xirq, xdma1, xdma2, err; struct snd_card *card; struct snd_gus_card *gus = NULL; - struct snd_cs4231 *cs4231; + struct snd_wss *wss; struct snd_gusmax *maxcard; card = snd_card_new(index[dev], id[dev], THIS_MODULE, @@ -301,33 +298,39 @@ static int __devinit snd_gusmax_probe(struct device *pdev, unsigned int dev) } maxcard->irq = xirq; - if ((err = snd_cs4231_create(card, - gus->gf1.port + 0x10c, -1, xirq, - xdma2 < 0 ? xdma1 : xdma2, xdma1, - CS4231_HW_DETECT, - CS4231_HWSHARE_IRQ | - CS4231_HWSHARE_DMA1 | - CS4231_HWSHARE_DMA2, - &cs4231)) < 0) + err = snd_wss_create(card, + gus->gf1.port + 0x10c, -1, xirq, + xdma2 < 0 ? xdma1 : xdma2, xdma1, + WSS_HW_DETECT, + WSS_HWSHARE_IRQ | + WSS_HWSHARE_DMA1 | + WSS_HWSHARE_DMA2, + &wss); + if (err < 0) goto _err; - if ((err = snd_cs4231_pcm(cs4231, 0, NULL)) < 0) + err = snd_wss_pcm(wss, 0, NULL); + if (err < 0) goto _err; - if ((err = snd_cs4231_mixer(cs4231)) < 0) + err = snd_wss_mixer(wss); + if (err < 0) goto _err; - if ((err = snd_cs4231_timer(cs4231, 2, NULL)) < 0) + err = snd_wss_timer(wss, 2, NULL); + if (err < 0) goto _err; if (pcm_channels[dev] > 0) { if ((err = snd_gf1_pcm_new(gus, 1, 1, NULL)) < 0) goto _err; } - if ((err = snd_gusmax_mixer(cs4231)) < 0) + err = snd_gusmax_mixer(wss); + if (err < 0) goto _err; - if ((err = snd_gf1_rawmidi_new(gus, 0, NULL)) < 0) + err = snd_gf1_rawmidi_new(gus, 0, NULL); + if (err < 0) goto _err; sprintf(card->longname + strlen(card->longname), " at 0x%lx, irq %i, dma %i", gus->gf1.port, xirq, xdma1); @@ -336,11 +339,12 @@ static int __devinit snd_gusmax_probe(struct device *pdev, unsigned int dev) snd_card_set_dev(card, pdev); - if ((err = snd_card_register(card)) < 0) + err = snd_card_register(card); + if (err < 0) goto _err; maxcard->gus = gus; - maxcard->cs4231 = cs4231; + maxcard->wss = wss; dev_set_drvdata(pdev, card); return 0; diff --git a/sound/isa/gus/interwave.c b/sound/isa/gus/interwave.c index ca0d7ace0c7..5faecfb602d 100644 --- a/sound/isa/gus/interwave.c +++ b/sound/isa/gus/interwave.c @@ -32,7 +32,7 @@ #include <asm/dma.h> #include <sound/core.h> #include <sound/gus.h> -#include <sound/cs4231.h> +#include <sound/wss.h> #ifdef SNDRV_STB #include <sound/tea6330t.h> #endif @@ -118,7 +118,7 @@ struct snd_interwave { int irq; struct snd_card *card; struct snd_gus_card *gus; - struct snd_cs4231 *cs4231; + struct snd_wss *wss; #ifdef SNDRV_STB struct resource *i2c_res; #endif @@ -312,7 +312,7 @@ static irqreturn_t snd_interwave_interrupt(int irq, void *dev_id) } if (inb(iwcard->pcm_status_reg) & 0x01) { /* IRQ bit is set? */ handled = 1; - snd_cs4231_interrupt(irq, iwcard->cs4231); + snd_wss_interrupt(irq, iwcard->wss); loop++; } } while (loop && --max > 0); @@ -498,13 +498,17 @@ static void __devinit snd_interwave_init(int dev, struct snd_gus_card * gus) } static struct snd_kcontrol_new snd_interwave_controls[] = { -CS4231_DOUBLE("Master Playback Switch", 0, CS4231_LINE_LEFT_OUTPUT, CS4231_LINE_RIGHT_OUTPUT, 7, 7, 1, 1), -CS4231_DOUBLE("Master Playback Volume", 0, CS4231_LINE_LEFT_OUTPUT, CS4231_LINE_RIGHT_OUTPUT, 0, 0, 31, 1), -CS4231_DOUBLE("Mic Playback Switch", 0, CS4231_LEFT_MIC_INPUT, CS4231_RIGHT_MIC_INPUT, 7, 7, 1, 1), -CS4231_DOUBLE("Mic Playback Volume", 0, CS4231_LEFT_MIC_INPUT, CS4231_RIGHT_MIC_INPUT, 0, 0, 31, 1) +WSS_DOUBLE("Master Playback Switch", 0, + CS4231_LINE_LEFT_OUTPUT, CS4231_LINE_RIGHT_OUTPUT, 7, 7, 1, 1), +WSS_DOUBLE("Master Playback Volume", 0, + CS4231_LINE_LEFT_OUTPUT, CS4231_LINE_RIGHT_OUTPUT, 0, 0, 31, 1), +WSS_DOUBLE("Mic Playback Switch", 0, + CS4231_LEFT_MIC_INPUT, CS4231_RIGHT_MIC_INPUT, 7, 7, 1, 1), +WSS_DOUBLE("Mic Playback Volume", 0, + CS4231_LEFT_MIC_INPUT, CS4231_RIGHT_MIC_INPUT, 0, 0, 31, 1) }; -static int __devinit snd_interwave_mixer(struct snd_cs4231 *chip) +static int __devinit snd_interwave_mixer(struct snd_wss *chip) { struct snd_card *card = chip->card; struct snd_ctl_elem_id id1, id2; @@ -527,10 +531,10 @@ static int __devinit snd_interwave_mixer(struct snd_cs4231 *chip) for (idx = 0; idx < ARRAY_SIZE(snd_interwave_controls); idx++) if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_interwave_controls[idx], chip))) < 0) return err; - snd_cs4231_out(chip, CS4231_LINE_LEFT_OUTPUT, 0x9f); - snd_cs4231_out(chip, CS4231_LINE_RIGHT_OUTPUT, 0x9f); - snd_cs4231_out(chip, CS4231_LEFT_MIC_INPUT, 0x9f); - snd_cs4231_out(chip, CS4231_RIGHT_MIC_INPUT, 0x9f); + snd_wss_out(chip, CS4231_LINE_LEFT_OUTPUT, 0x9f); + snd_wss_out(chip, CS4231_LINE_RIGHT_OUTPUT, 0x9f); + snd_wss_out(chip, CS4231_LEFT_MIC_INPUT, 0x9f); + snd_wss_out(chip, CS4231_RIGHT_MIC_INPUT, 0x9f); /* reassign AUXA to SYNTHESIZER */ strcpy(id1.name, "Aux Playback Switch"); strcpy(id2.name, "Synth Playback Switch"); @@ -642,7 +646,7 @@ static int __devinit snd_interwave_probe(struct snd_card *card, int dev) { int xirq, xdma1, xdma2; struct snd_interwave *iwcard = card->private_data; - struct snd_cs4231 *cs4231; + struct snd_wss *wss; struct snd_gus_card *gus; #ifdef SNDRV_STB struct snd_i2c_bus *i2c_bus; @@ -684,33 +688,39 @@ static int __devinit snd_interwave_probe(struct snd_card *card, int dev) } iwcard->irq = xirq; - if ((err = snd_cs4231_create(card, - gus->gf1.port + 0x10c, -1, xirq, - xdma2 < 0 ? xdma1 : xdma2, xdma1, - CS4231_HW_INTERWAVE, - CS4231_HWSHARE_IRQ | - CS4231_HWSHARE_DMA1 | - CS4231_HWSHARE_DMA2, - &cs4231)) < 0) + err = snd_wss_create(card, + gus->gf1.port + 0x10c, -1, xirq, + xdma2 < 0 ? xdma1 : xdma2, xdma1, + WSS_HW_INTERWAVE, + WSS_HWSHARE_IRQ | + WSS_HWSHARE_DMA1 | + WSS_HWSHARE_DMA2, + &wss); + if (err < 0) return err; - if ((err = snd_cs4231_pcm(cs4231, 0, &pcm)) < 0) + err = snd_wss_pcm(wss, 0, &pcm); + if (err < 0) return err; sprintf(pcm->name + strlen(pcm->name), " rev %c", gus->revision + 'A'); strcat(pcm->name, " (codec)"); - if ((err = snd_cs4231_timer(cs4231, 2, NULL)) < 0) + err = snd_wss_timer(wss, 2, NULL); + if (err < 0) return err; - if ((err = snd_cs4231_mixer(cs4231)) < 0) + err = snd_wss_mixer(wss); + if (err < 0) return err; if (pcm_channels[dev] > 0) { - if ((err = snd_gf1_pcm_new(gus, 1, 1, NULL)) < 0) + err = snd_gf1_pcm_new(gus, 1, 1, NULL); + if (err < 0) return err; } - if ((err = snd_interwave_mixer(cs4231)) < 0) + err = snd_interwave_mixer(wss); + if (err < 0) return err; #ifdef SNDRV_STB @@ -754,10 +764,11 @@ static int __devinit snd_interwave_probe(struct snd_card *card, int dev) if (xdma2 >= 0) sprintf(card->longname + strlen(card->longname), "&%d", xdma2); - if ((err = snd_card_register(card)) < 0) + err = snd_card_register(card); + if (err < 0) return err; - iwcard->cs4231 = cs4231; + iwcard->wss = wss; iwcard->gus = gus; return 0; } diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c index 854a9f74b46..58c972b2af0 100644 --- a/sound/isa/opl3sa2.c +++ b/sound/isa/opl3sa2.c @@ -28,7 +28,7 @@ #include <linux/pnp.h> #include <linux/moduleparam.h> #include <sound/core.h> -#include <sound/cs4231.h> +#include <sound/wss.h> #include <sound/mpu401.h> #include <sound/opl3.h> #include <sound/initval.h> @@ -124,7 +124,6 @@ static int pnpc_registered; #define OPL3SA2_PM_D3 (OPL3SA2_PM_ADOWN|OPL3SA2_PM_PSV|OPL3SA2_PM_PDN|OPL3SA2_PM_PDX) struct snd_opl3sa2 { - struct snd_card *card; int version; /* 2 or 3 */ unsigned long port; /* control port */ struct resource *res_port; /* control port resource */ @@ -133,7 +132,7 @@ struct snd_opl3sa2 { spinlock_t reg_lock; struct snd_hwdep *synth; struct snd_rawmidi *rmidi; - struct snd_cs4231 *cs4231; + struct snd_wss *wss; unsigned char ctlregs[0x20]; int ymode; /* SL added */ struct snd_kcontrol *master_switch; @@ -222,14 +221,13 @@ static void snd_opl3sa2_write(struct snd_opl3sa2 *chip, unsigned char reg, unsig spin_unlock_irqrestore(&chip->reg_lock, flags); } -static int __devinit snd_opl3sa2_detect(struct snd_opl3sa2 *chip) +static int __devinit snd_opl3sa2_detect(struct snd_card *card) { - struct snd_card *card; + struct snd_opl3sa2 *chip = card->private_data; unsigned long port; unsigned char tmp, tmp1; char str[2]; - card = chip->card; port = chip->port; if ((chip->res_port = request_region(port, 2, "OPL3-SA control")) == NULL) { snd_printk(KERN_ERR PFX "can't grab port 0x%lx\n", port); @@ -298,12 +296,14 @@ static int __devinit snd_opl3sa2_detect(struct snd_opl3sa2 *chip) static irqreturn_t snd_opl3sa2_interrupt(int irq, void *dev_id) { unsigned short status; - struct snd_opl3sa2 *chip = dev_id; + struct snd_card *card = dev_id; + struct snd_opl3sa2 *chip; int handled = 0; - if (chip == NULL || chip->card == NULL) + if (card == NULL) return IRQ_NONE; + chip = card->private_data; status = snd_opl3sa2_read(chip, OPL3SA2_IRQ_STATUS); if (status & 0x20) { @@ -318,7 +318,7 @@ static irqreturn_t snd_opl3sa2_interrupt(int irq, void *dev_id) if (status & 0x07) { /* TI,CI,PI */ handled = 1; - snd_cs4231_interrupt(irq, chip->cs4231); + snd_wss_interrupt(irq, chip->wss); } if (status & 0x40) { /* hardware volume change */ @@ -327,8 +327,10 @@ static irqreturn_t snd_opl3sa2_interrupt(int irq, void *dev_id) snd_opl3sa2_read(chip, OPL3SA2_MASTER_RIGHT); snd_opl3sa2_read(chip, OPL3SA2_MASTER_LEFT); if (chip->master_switch && chip->master_volume) { - snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->master_switch->id); - snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->master_volume->id); + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &chip->master_switch->id); + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &chip->master_volume->id); } } return IRQ_RETVAL(handled); @@ -336,29 +338,18 @@ static irqreturn_t snd_opl3sa2_interrupt(int irq, void *dev_id) #define OPL3SA2_SINGLE(xname, xindex, reg, shift, mask, invert) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ - .info = snd_opl3sa2_info_single, \ + .info = snd_wss_info_single, \ .get = snd_opl3sa2_get_single, .put = snd_opl3sa2_put_single, \ .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) } #define OPL3SA2_SINGLE_TLV(xname, xindex, reg, shift, mask, invert, xtlv) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ .name = xname, .index = xindex, \ - .info = snd_opl3sa2_info_single, \ + .info = snd_wss_info_single, \ .get = snd_opl3sa2_get_single, .put = snd_opl3sa2_put_single, \ .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24), \ .tlv = { .p = (xtlv) } } -static int snd_opl3sa2_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - int mask = (kcontrol->private_value >> 16) & 0xff; - - uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = mask; - return 0; -} - static int snd_opl3sa2_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_opl3sa2 *chip = snd_kcontrol_chip(kcontrol); @@ -402,29 +393,18 @@ static int snd_opl3sa2_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_ #define OPL3SA2_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ - .info = snd_opl3sa2_info_double, \ + .info = snd_wss_info_double, \ .get = snd_opl3sa2_get_double, .put = snd_opl3sa2_put_double, \ .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) } #define OPL3SA2_DOUBLE_TLV(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert, xtlv) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ .name = xname, .index = xindex, \ - .info = snd_opl3sa2_info_double, \ + .info = snd_wss_info_double, \ .get = snd_opl3sa2_get_double, .put = snd_opl3sa2_put_double, \ .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22), \ .tlv = { .p = (xtlv) } } -static int snd_opl3sa2_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - int mask = (kcontrol->private_value >> 24) & 0xff; - - uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 2; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = mask; - return 0; -} - static int snd_opl3sa2_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_opl3sa2 *chip = snd_kcontrol_chip(kcontrol); @@ -512,9 +492,9 @@ static void snd_opl3sa2_master_free(struct snd_kcontrol *kcontrol) chip->master_volume = NULL; } -static int __devinit snd_opl3sa2_mixer(struct snd_opl3sa2 *chip) +static int __devinit snd_opl3sa2_mixer(struct snd_card *card) { - struct snd_card *card = chip->card; + struct snd_opl3sa2 *chip = card->private_data; struct snd_ctl_elem_id id1, id2; struct snd_kcontrol *kctl; unsigned int idx; @@ -573,7 +553,7 @@ static int snd_opl3sa2_suspend(struct snd_card *card, pm_message_t state) struct snd_opl3sa2 *chip = card->private_data; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - chip->cs4231->suspend(chip->cs4231); + chip->wss->suspend(chip->wss); /* power down */ snd_opl3sa2_write(chip, OPL3SA2_PM_CTRL, OPL3SA2_PM_D3); @@ -597,8 +577,8 @@ static int snd_opl3sa2_resume(struct snd_card *card) for (i = 0x12; i <= 0x16; i++) snd_opl3sa2_write(chip, i, chip->ctlregs[i]); } - /* restore cs4231 */ - chip->cs4231->resume(chip->cs4231); + /* restore wss */ + chip->wss->resume(chip->wss); snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0; @@ -650,7 +630,6 @@ static struct snd_card *snd_opl3sa2_card_new(int dev) chip = card->private_data; spin_lock_init(&chip->reg_lock); chip->irq = -1; - chip->card = card; card->private_free = snd_opl3sa2_free; return card; } @@ -659,7 +638,7 @@ static int __devinit snd_opl3sa2_probe(struct snd_card *card, int dev) { int xirq, xdma1, xdma2; struct snd_opl3sa2 *chip; - struct snd_cs4231 *cs4231; + struct snd_wss *wss; struct snd_opl3 *opl3; int err; @@ -672,30 +651,36 @@ static int __devinit snd_opl3sa2_probe(struct snd_card *card, int dev) xdma2 = dma2[dev]; if (xdma2 < 0) chip->single_dma = 1; - if ((err = snd_opl3sa2_detect(chip)) < 0) + err = snd_opl3sa2_detect(card); + if (err < 0) return err; - if (request_irq(xirq, snd_opl3sa2_interrupt, IRQF_DISABLED, "OPL3-SA2", chip)) { + err = request_irq(xirq, snd_opl3sa2_interrupt, IRQF_DISABLED, + "OPL3-SA2", card); + if (err) { snd_printk(KERN_ERR PFX "can't grab IRQ %d\n", xirq); return -ENODEV; } chip->irq = xirq; - if ((err = snd_cs4231_create(card, - wss_port[dev] + 4, -1, - xirq, xdma1, xdma2, - CS4231_HW_OPL3SA2, - CS4231_HWSHARE_IRQ, - &cs4231)) < 0) { + err = snd_wss_create(card, + wss_port[dev] + 4, -1, + xirq, xdma1, xdma2, + WSS_HW_OPL3SA2, WSS_HWSHARE_IRQ, &wss); + if (err < 0) { snd_printd("Oops, WSS not detected at 0x%lx\n", wss_port[dev] + 4); return err; } - chip->cs4231 = cs4231; - if ((err = snd_cs4231_pcm(cs4231, 0, NULL)) < 0) + chip->wss = wss; + err = snd_wss_pcm(wss, 0, NULL); + if (err < 0) return err; - if ((err = snd_cs4231_mixer(cs4231)) < 0) + err = snd_wss_mixer(wss); + if (err < 0) return err; - if ((err = snd_opl3sa2_mixer(chip)) < 0) + err = snd_opl3sa2_mixer(card); + if (err < 0) return err; - if ((err = snd_cs4231_timer(cs4231, 0, NULL)) < 0) + err = snd_wss_timer(wss, 0, NULL); + if (err < 0) return err; if (fm_port[dev] >= 0x340 && fm_port[dev] < 0x400) { if ((err = snd_opl3_create(card, fm_port[dev], diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c index 2a1e2f5d12c..440755cc001 100644 --- a/sound/isa/opti9xx/miro.c +++ b/sound/isa/opti9xx/miro.c @@ -32,7 +32,7 @@ #include <asm/io.h> #include <asm/dma.h> #include <sound/core.h> -#include <sound/cs4231.h> +#include <sound/wss.h> #include <sound/mpu401.h> #include <sound/opl4.h> #include <sound/control.h> @@ -675,7 +675,8 @@ static int __devinit snd_miro_mixer(struct snd_miro *miro) unsigned int idx; int err; - snd_assert(miro != NULL && miro->card != NULL, return -EINVAL); + if (snd_BUG_ON(!miro || !miro->card)) + return -EINVAL; card = miro->card; @@ -1221,7 +1222,7 @@ static int __devinit snd_miro_probe(struct device *devptr, unsigned int n) int error; struct snd_miro *miro; - struct snd_cs4231 *codec; + struct snd_wss *codec; struct snd_timer *timer; struct snd_card *card; struct snd_pcm *pcm; @@ -1310,29 +1311,32 @@ static int __devinit snd_miro_probe(struct device *devptr, unsigned int n) } } - if ((error = snd_miro_configure(miro))) { + error = snd_miro_configure(miro); + if (error) { snd_card_free(card); return error; } - if ((error = snd_cs4231_create(card, miro->wss_base + 4, -1, - miro->irq, miro->dma1, miro->dma2, - CS4231_HW_AD1845, - 0, - &codec)) < 0) { + error = snd_wss_create(card, miro->wss_base + 4, -1, + miro->irq, miro->dma1, miro->dma2, + WSS_HW_AD1845, 0, &codec); + if (error < 0) { snd_card_free(card); return error; } - if ((error = snd_cs4231_pcm(codec, 0, &pcm)) < 0) { + error = snd_wss_pcm(codec, 0, &pcm); + if (error < 0) { snd_card_free(card); return error; } - if ((error = snd_cs4231_mixer(codec)) < 0) { + error = snd_wss_mixer(codec); + if (error < 0) { snd_card_free(card); return error; } - if ((error = snd_cs4231_timer(codec, 0, &timer)) < 0) { + error = snd_wss_timer(codec, 0, &timer); + if (error < 0) { snd_card_free(card); return error; } diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c index 41c047e665e..19706b0d849 100644 --- a/sound/isa/opti9xx/opti92x-ad1848.c +++ b/sound/isa/opti9xx/opti92x-ad1848.c @@ -33,11 +33,7 @@ #include <asm/io.h> #include <asm/dma.h> #include <sound/core.h> -#if defined(CS4231) || defined(OPTi93X) -#include <sound/cs4231.h> -#else -#include <sound/ad1848.h> -#endif /* CS4231 */ +#include <sound/wss.h> #include <sound/mpu401.h> #include <sound/opl3.h> #ifndef OPTi93X @@ -68,7 +64,9 @@ MODULE_SUPPORTED_DEVICE("{{OPTi,82C924 (AD1848)}," static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */ static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */ //static int enable = SNDRV_DEFAULT_ENABLE1; /* Enable this card */ +#ifdef CONFIG_PNP static int isapnp = 1; /* Enable ISA PnP detection */ +#endif static long port = SNDRV_DEFAULT_PORT1; /* 0x530,0xe80,0xf40,0x604 */ static long mpu_port = SNDRV_DEFAULT_PORT1; /* 0x300,0x310,0x320,0x330 */ static long fm_port = SNDRV_DEFAULT_PORT1; /* 0x388 */ @@ -85,8 +83,10 @@ module_param(id, charp, 0444); MODULE_PARM_DESC(id, "ID string for opti9xx based soundcard."); //module_param(enable, bool, 0444); //MODULE_PARM_DESC(enable, "Enable opti9xx soundcard."); +#ifdef CONFIG_PNP module_param(isapnp, bool, 0444); MODULE_PARM_DESC(isapnp, "Enable ISA PnP detection for specified soundcard."); +#endif module_param(port, long, 0444); MODULE_PARM_DESC(port, "WSS port # for opti9xx driver."); module_param(mpu_port, long, 0444); @@ -135,7 +135,7 @@ struct snd_opti9xx { unsigned long mc_base_size; #ifdef OPTi93X unsigned long mc_indir_index; - struct snd_cs4231 *codec; + struct snd_wss *codec; #endif /* OPTi93X */ unsigned long pwd_reg; @@ -144,9 +144,7 @@ struct snd_opti9xx { long wss_base; int irq; int dma1; -#if defined(CS4231) || defined(OPTi93X) int dma2; -#endif /* CS4231 || OPTi93X */ long fm_port; @@ -221,9 +219,7 @@ static int __devinit snd_opti9xx_init(struct snd_opti9xx *chip, chip->wss_base = -1; chip->irq = -1; chip->dma1 = -1; -#if defined(CS4231) || defined (OPTi93X) chip->dma2 = -1; -#endif /* CS4231 || OPTi93X */ chip->fm_port = -1; chip->mpu_port = -1; chip->mpu_irq = -1; @@ -558,7 +554,7 @@ __skip_mpu: static irqreturn_t snd_opti93x_interrupt(int irq, void *dev_id) { - struct snd_cs4231 *codec = dev_id; + struct snd_wss *codec = dev_id; struct snd_opti9xx *chip = codec->card->private_data; unsigned char status; @@ -566,7 +562,7 @@ static irqreturn_t snd_opti93x_interrupt(int irq, void *dev_id) if ((status & OPTi93X_IRQ_PLAYBACK) && codec->playback_substream) snd_pcm_period_elapsed(codec->playback_substream); if ((status & OPTi93X_IRQ_CAPTURE) && codec->capture_substream) { - snd_cs4231_overrange(codec); + snd_wss_overrange(codec); snd_pcm_period_elapsed(codec->capture_substream); } outb(0x00, OPTi93X_PORT(codec, STATUS)); @@ -687,8 +683,8 @@ static void snd_card_opti9xx_free(struct snd_card *card) if (chip) { #ifdef OPTi93X - struct snd_cs4231 *codec = chip->codec; - if (codec->irq > 0) { + struct snd_wss *codec = chip->codec; + if (codec && codec->irq > 0) { disable_irq(codec->irq); free_irq(codec->irq, codec); } @@ -702,14 +698,10 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card) static long possible_ports[] = {0x530, 0xe80, 0xf40, 0x604, -1}; int error; struct snd_opti9xx *chip = card->private_data; -#if defined(CS4231) || defined(OPTi93X) - struct snd_cs4231 *codec; + struct snd_wss *codec; #ifdef CS4231 struct snd_timer *timer; #endif -#else - struct snd_ad1848 *codec; -#endif struct snd_pcm *pcm; struct snd_rawmidi *rmidi; struct snd_hwdep *synth; @@ -727,38 +719,46 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card) chip->dma1 = dma1; #if defined(CS4231) || defined(OPTi93X) chip->dma2 = dma2; +#else + chip->dma2 = -1; #endif if (chip->wss_base == SNDRV_AUTO_PORT) { - if ((chip->wss_base = snd_legacy_find_free_ioport(possible_ports, 4)) < 0) { + chip->wss_base = snd_legacy_find_free_ioport(possible_ports, 4); + if (chip->wss_base < 0) { snd_printk("unable to find a free WSS port\n"); return -EBUSY; } } - if ((error = snd_opti9xx_configure(chip))) + error = snd_opti9xx_configure(chip); + if (error) return error; -#if defined(CS4231) || defined(OPTi93X) - if ((error = snd_cs4231_create(card, chip->wss_base + 4, -1, - chip->irq, chip->dma1, chip->dma2, -#ifdef CS4231 - CS4231_HW_DETECT, 0, -#else /* OPTi93x */ - CS4231_HW_OPTI93X, CS4231_HWSHARE_IRQ, + error = snd_wss_create(card, chip->wss_base + 4, -1, + chip->irq, chip->dma1, chip->dma2, +#ifdef OPTi93X + WSS_HW_OPTI93X, WSS_HWSHARE_IRQ, +#else + WSS_HW_DETECT, 0, #endif - &codec)) < 0) + &codec); + if (error < 0) return error; #ifdef OPTi93X chip->codec = codec; #endif - if ((error = snd_cs4231_pcm(codec, 0, &pcm)) < 0) + error = snd_wss_pcm(codec, 0, &pcm); + if (error < 0) return error; - if ((error = snd_cs4231_mixer(codec)) < 0) + error = snd_wss_mixer(codec); + if (error < 0) return error; #ifdef CS4231 - if ((error = snd_cs4231_timer(codec, 0, &timer)) < 0) + error = snd_wss_timer(codec, 0, &timer); + if (error < 0) return error; -#else /* OPTI93X */ +#endif +#ifdef OPTi93X error = request_irq(chip->irq, snd_opti93x_interrupt, IRQF_DISABLED, DEV_NAME" - WSS", codec); if (error < 0) { @@ -766,16 +766,6 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card) return error; } #endif -#else - if ((error = snd_ad1848_create(card, chip->wss_base + 4, - chip->irq, chip->dma1, - AD1848_HW_DETECT, &codec)) < 0) - return error; - if ((error = snd_ad1848_pcm(codec, 0, &pcm)) < 0) - return error; - if ((error = snd_ad1848_mixer(codec)) < 0) - return error; -#endif strcpy(card->driver, chip->name); sprintf(card->shortname, "OPTi %s", card->driver); #if defined(CS4231) || defined(OPTi93X) diff --git a/sound/isa/sb/emu8000.c b/sound/isa/sb/emu8000.c index b35be7d9a9f..96678d5d383 100644 --- a/sound/isa/sb/emu8000.c +++ b/sound/isa/sb/emu8000.c @@ -1023,7 +1023,8 @@ snd_emu8000_create_mixer(struct snd_card *card, struct snd_emu8000 *emu) { int i, err = 0; - snd_assert(emu != NULL && card != NULL, return -EINVAL); + if (snd_BUG_ON(!emu || !card)) + return -EINVAL; spin_lock_init(&emu->control_lock); diff --git a/sound/isa/sb/emu8000_patch.c b/sound/isa/sb/emu8000_patch.c index 1be16c9700f..c99c6078be3 100644 --- a/sound/isa/sb/emu8000_patch.c +++ b/sound/isa/sb/emu8000_patch.c @@ -156,7 +156,8 @@ snd_emu8000_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp, struct snd_emu8000 *emu; emu = rec->hw; - snd_assert(sp != NULL, return -EINVAL); + if (snd_BUG_ON(!sp)) + return -EINVAL; if (sp->v.size == 0) return 0; diff --git a/sound/isa/sb/sb16_csp.c b/sound/isa/sb/sb16_csp.c index 35f3d7b1653..49037d074c7 100644 --- a/sound/isa/sb/sb16_csp.c +++ b/sound/isa/sb/sb16_csp.c @@ -198,7 +198,8 @@ static int snd_sb_csp_ioctl(struct snd_hwdep * hw, struct file *file, unsigned i struct snd_sb_csp_start start_info; int err; - snd_assert(p != NULL, return -EINVAL); + if (snd_BUG_ON(!p)) + return -EINVAL; if (snd_sb_csp_check_version(p)) return -ENODEV; @@ -1046,7 +1047,8 @@ static int snd_sb_qsound_build(struct snd_sb_csp * p) struct snd_card *card; int err; - snd_assert(p != NULL, return -EINVAL); + if (snd_BUG_ON(!p)) + return -EINVAL; card = p->chip->card; p->qpos_left = p->qpos_right = SNDRV_SB_CSP_QSOUND_MAX_RIGHT / 2; @@ -1071,7 +1073,8 @@ static void snd_sb_qsound_destroy(struct snd_sb_csp * p) struct snd_card *card; unsigned long flags; - snd_assert(p != NULL, return); + if (snd_BUG_ON(!p)) + return; card = p->chip->card; diff --git a/sound/isa/sb/sb16_main.c b/sound/isa/sb/sb16_main.c index f7e8192270a..2a6cc1cfe94 100644 --- a/sound/isa/sb/sb16_main.c +++ b/sound/isa/sb/sb16_main.c @@ -669,7 +669,8 @@ static int snd_sb16_capture_close(struct snd_pcm_substream *substream) static int snd_sb16_set_dma_mode(struct snd_sb *chip, int what) { if (chip->dma8 < 0 || chip->dma16 < 0) { - snd_assert(what == 0, return -EINVAL); + if (snd_BUG_ON(what)) + return -EINVAL; return 0; } if (what == 0) { diff --git a/sound/isa/sb/sb8_main.c b/sound/isa/sb/sb8_main.c index fe03bb82053..658d55769c9 100644 --- a/sound/isa/sb/sb8_main.c +++ b/sound/isa/sb/sb8_main.c @@ -111,7 +111,9 @@ static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream) switch (chip->hardware) { case SB_HW_PRO: if (runtime->channels > 1) { - snd_assert(rate == SB8_RATE(11025) || rate == SB8_RATE(22050), return -EINVAL); + if (snd_BUG_ON(rate != SB8_RATE(11025) && + rate != SB8_RATE(22050))) + return -EINVAL; chip->playback_format = SB_DSP_HI_OUTPUT_AUTO; break; } @@ -237,7 +239,9 @@ static int snd_sb8_capture_prepare(struct snd_pcm_substream *substream) switch (chip->hardware) { case SB_HW_PRO: if (runtime->channels > 1) { - snd_assert(rate == SB8_RATE(11025) || rate == SB8_RATE(22050), return -EINVAL); + if (snd_BUG_ON(rate != SB8_RATE(11025) && + rate != SB8_RATE(22050))) + return -EINVAL; chip->capture_format = SB_DSP_HI_INPUT_AUTO; break; } diff --git a/sound/isa/sb/sb_common.c b/sound/isa/sb/sb_common.c index b432d9ae874..27a65150225 100644 --- a/sound/isa/sb/sb_common.c +++ b/sound/isa/sb/sb_common.c @@ -219,7 +219,8 @@ int snd_sbdsp_create(struct snd_card *card, .dev_free = snd_sbdsp_dev_free, }; - snd_assert(r_chip != NULL, return -EINVAL); + if (snd_BUG_ON(!r_chip)) + return -EINVAL; *r_chip = NULL; chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) diff --git a/sound/isa/sb/sb_mixer.c b/sound/isa/sb/sb_mixer.c index 73d4572d136..406a431af91 100644 --- a/sound/isa/sb/sb_mixer.c +++ b/sound/isa/sb/sb_mixer.c @@ -792,7 +792,8 @@ int snd_sbmixer_new(struct snd_sb *chip) struct snd_card *card; int err; - snd_assert(chip != NULL && chip->card != NULL, return -EINVAL); + if (snd_BUG_ON(!chip || !chip->card)) + return -EINVAL; card = chip->card; @@ -925,7 +926,8 @@ static unsigned char als4000_saved_regs[] = { static void save_mixer(struct snd_sb *chip, unsigned char *regs, int num_regs) { unsigned char *val = chip->saved_regs; - snd_assert(num_regs <= ARRAY_SIZE(chip->saved_regs), return); + if (snd_BUG_ON(num_regs > ARRAY_SIZE(chip->saved_regs))) + return; for (; num_regs; num_regs--) *val++ = snd_sbmixer_read(chip, *regs++); } @@ -933,7 +935,8 @@ static void save_mixer(struct snd_sb *chip, unsigned char *regs, int num_regs) static void restore_mixer(struct snd_sb *chip, unsigned char *regs, int num_regs) { unsigned char *val = chip->saved_regs; - snd_assert(num_regs <= ARRAY_SIZE(chip->saved_regs), return); + if (snd_BUG_ON(num_regs > ARRAY_SIZE(chip->saved_regs))) + return; for (; num_regs; num_regs--) snd_sbmixer_write(chip, *regs++, *val++); } diff --git a/sound/isa/sc6000.c b/sound/isa/sc6000.c index da3d152bcad..ca35924dc3b 100644 --- a/sound/isa/sc6000.c +++ b/sound/isa/sc6000.c @@ -29,7 +29,7 @@ #include <linux/io.h> #include <asm/dma.h> #include <sound/core.h> -#include <sound/ad1848.h> +#include <sound/wss.h> #include <sound/opl3.h> #include <sound/mpu401.h> #include <sound/control.h> @@ -397,7 +397,7 @@ static int __devinit sc6000_init_board(char __iomem *vport, int irq, int dma, return 0; } -static int __devinit snd_sc6000_mixer(struct snd_ad1848 *chip) +static int __devinit snd_sc6000_mixer(struct snd_wss *chip) { struct snd_card *card = chip->card; struct snd_ctl_elem_id id1, id2; @@ -483,7 +483,7 @@ static int __devinit snd_sc6000_probe(struct device *devptr, unsigned int dev) int xirq = irq[dev]; int xdma = dma[dev]; struct snd_card *card; - struct snd_ad1848 *chip; + struct snd_wss *chip; struct snd_opl3 *opl3; char __iomem *vport; char __iomem *vmss_port; @@ -548,21 +548,21 @@ static int __devinit snd_sc6000_probe(struct device *devptr, unsigned int dev) if (err < 0) goto err_unmap2; - err = snd_ad1848_create(card, mss_port[dev] + 4, xirq, xdma, - AD1848_HW_DETECT, &chip); + err = snd_wss_create(card, mss_port[dev] + 4, -1, xirq, xdma, -1, + WSS_HW_DETECT, 0, &chip); if (err < 0) goto err_unmap2; card->private_data = chip; - err = snd_ad1848_pcm(chip, 0, NULL); + err = snd_wss_pcm(chip, 0, NULL); if (err < 0) { snd_printk(KERN_ERR PFX - "error creating new ad1848 PCM device\n"); + "error creating new WSS PCM device\n"); goto err_unmap2; } - err = snd_ad1848_mixer(chip); + err = snd_wss_mixer(chip); if (err < 0) { - snd_printk(KERN_ERR PFX "error creating new ad1848 mixer\n"); + snd_printk(KERN_ERR PFX "error creating new WSS mixer\n"); goto err_unmap2; } err = snd_sc6000_mixer(chip); diff --git a/sound/isa/sgalaxy.c b/sound/isa/sgalaxy.c index a07274ecb14..2c7503bf127 100644 --- a/sound/isa/sgalaxy.c +++ b/sound/isa/sgalaxy.c @@ -31,7 +31,7 @@ #include <asm/dma.h> #include <sound/core.h> #include <sound/sb.h> -#include <sound/ad1848.h> +#include <sound/wss.h> #include <sound/control.h> #define SNDRV_LEGACY_FIND_FREE_IRQ #define SNDRV_LEGACY_FIND_FREE_DMA @@ -175,12 +175,14 @@ static int __devinit snd_sgalaxy_detect(int dev, int irq, int dma) return snd_sgalaxy_setup_wss(wssport[dev], irq, dma); } -static struct ad1848_mix_elem snd_sgalaxy_controls[] = { -AD1848_DOUBLE("Aux Playback Switch", 0, SGALAXY_AUXC_LEFT, SGALAXY_AUXC_RIGHT, 7, 7, 1, 1), -AD1848_DOUBLE("Aux Playback Volume", 0, SGALAXY_AUXC_LEFT, SGALAXY_AUXC_RIGHT, 0, 0, 31, 0) +static struct snd_kcontrol_new snd_sgalaxy_controls[] = { +WSS_DOUBLE("Aux Playback Switch", 0, + SGALAXY_AUXC_LEFT, SGALAXY_AUXC_RIGHT, 7, 7, 1, 1), +WSS_DOUBLE("Aux Playback Volume", 0, + SGALAXY_AUXC_LEFT, SGALAXY_AUXC_RIGHT, 0, 0, 31, 0) }; -static int __devinit snd_sgalaxy_mixer(struct snd_ad1848 *chip) +static int __devinit snd_sgalaxy_mixer(struct snd_wss *chip) { struct snd_card *card = chip->card; struct snd_ctl_elem_id id1, id2; @@ -210,7 +212,9 @@ static int __devinit snd_sgalaxy_mixer(struct snd_ad1848 *chip) return err; /* build AUX2 input */ for (idx = 0; idx < ARRAY_SIZE(snd_sgalaxy_controls); idx++) { - if ((err = snd_ad1848_add_ctl_elem(chip, &snd_sgalaxy_controls[idx])) < 0) + err = snd_ctl_add(card, + snd_ctl_new1(&snd_sgalaxy_controls[idx], chip)); + if (err < 0) return err; } return 0; @@ -237,7 +241,7 @@ static int __devinit snd_sgalaxy_probe(struct device *devptr, unsigned int dev) static int possible_dmas[] = {1, 3, 0, -1}; int err, xirq, xdma1; struct snd_card *card; - struct snd_ad1848 *chip; + struct snd_wss *chip; card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); if (card == NULL) @@ -263,18 +267,21 @@ static int __devinit snd_sgalaxy_probe(struct device *devptr, unsigned int dev) if ((err = snd_sgalaxy_detect(dev, xirq, xdma1)) < 0) goto _err; - if ((err = snd_ad1848_create(card, wssport[dev] + 4, - xirq, xdma1, - AD1848_HW_DETECT, &chip)) < 0) + err = snd_wss_create(card, wssport[dev] + 4, -1, + xirq, xdma1, -1, + WSS_HW_DETECT, 0, &chip); + if (err < 0) goto _err; card->private_data = chip; - if ((err = snd_ad1848_pcm(chip, 0, NULL)) < 0) { - snd_printdd(PFX "error creating new ad1848 PCM device\n"); + err = snd_wss_pcm(chip, 0, NULL); + if (err < 0) { + snd_printdd(PFX "error creating new WSS PCM device\n"); goto _err; } - if ((err = snd_ad1848_mixer(chip)) < 0) { - snd_printdd(PFX "error creating new ad1848 mixer\n"); + err = snd_wss_mixer(chip); + if (err < 0) { + snd_printdd(PFX "error creating new WSS mixer\n"); goto _err; } if ((err = snd_sgalaxy_mixer(chip)) < 0) { @@ -312,7 +319,7 @@ static int snd_sgalaxy_suspend(struct device *pdev, unsigned int n, pm_message_t state) { struct snd_card *card = dev_get_drvdata(pdev); - struct snd_ad1848 *chip = card->private_data; + struct snd_wss *chip = card->private_data; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); chip->suspend(chip); @@ -322,11 +329,11 @@ static int snd_sgalaxy_suspend(struct device *pdev, unsigned int n, static int snd_sgalaxy_resume(struct device *pdev, unsigned int n) { struct snd_card *card = dev_get_drvdata(pdev); - struct snd_ad1848 *chip = card->private_data; + struct snd_wss *chip = card->private_data; chip->resume(chip); - snd_ad1848_out(chip, SGALAXY_AUXC_LEFT, chip->image[SGALAXY_AUXC_LEFT]); - snd_ad1848_out(chip, SGALAXY_AUXC_RIGHT, chip->image[SGALAXY_AUXC_RIGHT]); + snd_wss_out(chip, SGALAXY_AUXC_LEFT, chip->image[SGALAXY_AUXC_LEFT]); + snd_wss_out(chip, SGALAXY_AUXC_RIGHT, chip->image[SGALAXY_AUXC_RIGHT]); snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0; diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c index 06ad7863dff..48a16d86583 100644 --- a/sound/isa/sscape.c +++ b/sound/isa/sscape.c @@ -31,7 +31,7 @@ #include <asm/dma.h> #include <sound/core.h> #include <sound/hwdep.h> -#include <sound/cs4231.h> +#include <sound/wss.h> #include <sound/mpu401.h> #include <sound/initval.h> @@ -147,7 +147,7 @@ struct soundscape { enum card_type type; struct resource *io_res; struct resource *wss_res; - struct snd_cs4231 *chip; + struct snd_wss *chip; struct snd_mpu401 *mpu; struct snd_hwdep *hw; @@ -726,7 +726,7 @@ static int sscape_midi_info(struct snd_kcontrol *ctl, static int sscape_midi_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl) { - struct snd_cs4231 *chip = snd_kcontrol_chip(kctl); + struct snd_wss *chip = snd_kcontrol_chip(kctl); struct snd_card *card = chip->card; register struct soundscape *s = get_card_soundscape(card); unsigned long flags; @@ -746,7 +746,7 @@ static int sscape_midi_get(struct snd_kcontrol *kctl, static int sscape_midi_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl) { - struct snd_cs4231 *chip = snd_kcontrol_chip(kctl); + struct snd_wss *chip = snd_kcontrol_chip(kctl); struct snd_card *card = chip->card; register struct soundscape *s = get_card_soundscape(card); unsigned long flags; @@ -958,7 +958,9 @@ static int __devinit create_mpu401(struct snd_card *card, int devnum, unsigned l * Override for the CS4231 playback format function. * The AD1845 has much simpler format and rate selection. */ -static void ad1845_playback_format(struct snd_cs4231 * chip, struct snd_pcm_hw_params *params, unsigned char format) +static void ad1845_playback_format(struct snd_wss *chip, + struct snd_pcm_hw_params *params, + unsigned char format) { unsigned long flags; unsigned rate = params_rate(params); @@ -983,9 +985,9 @@ static void ad1845_playback_format(struct snd_cs4231 * chip, struct snd_pcm_hw_p * NOTE: We seem to need to write to the MSB before the LSB * to get the correct sample frequency. */ - snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT, (format & 0xf0)); - snd_cs4231_out(chip, AD1845_FREQ_SEL_MSB, (unsigned char) (rate >> 8)); - snd_cs4231_out(chip, AD1845_FREQ_SEL_LSB, (unsigned char) rate); + snd_wss_out(chip, CS4231_PLAYBK_FORMAT, (format & 0xf0)); + snd_wss_out(chip, AD1845_FREQ_SEL_MSB, (unsigned char) (rate >> 8)); + snd_wss_out(chip, AD1845_FREQ_SEL_LSB, (unsigned char) rate); spin_unlock_irqrestore(&chip->reg_lock, flags); } @@ -994,7 +996,9 @@ static void ad1845_playback_format(struct snd_cs4231 * chip, struct snd_pcm_hw_p * Override for the CS4231 capture format function. * The AD1845 has much simpler format and rate selection. */ -static void ad1845_capture_format(struct snd_cs4231 * chip, struct snd_pcm_hw_params *params, unsigned char format) +static void ad1845_capture_format(struct snd_wss *chip, + struct snd_pcm_hw_params *params, + unsigned char format) { unsigned long flags; unsigned rate = params_rate(params); @@ -1019,9 +1023,9 @@ static void ad1845_capture_format(struct snd_cs4231 * chip, struct snd_pcm_hw_pa * NOTE: We seem to need to write to the MSB before the LSB * to get the correct sample frequency. */ - snd_cs4231_out(chip, CS4231_REC_FORMAT, (format & 0xf0)); - snd_cs4231_out(chip, AD1845_FREQ_SEL_MSB, (unsigned char) (rate >> 8)); - snd_cs4231_out(chip, AD1845_FREQ_SEL_LSB, (unsigned char) rate); + snd_wss_out(chip, CS4231_REC_FORMAT, (format & 0xf0)); + snd_wss_out(chip, AD1845_FREQ_SEL_MSB, (unsigned char) (rate >> 8)); + snd_wss_out(chip, AD1845_FREQ_SEL_LSB, (unsigned char) rate); spin_unlock_irqrestore(&chip->reg_lock, flags); } @@ -1036,7 +1040,7 @@ static int __devinit create_ad1845(struct snd_card *card, unsigned port, int irq, int dma1, int dma2) { register struct soundscape *sscape = get_card_soundscape(card); - struct snd_cs4231 *chip; + struct snd_wss *chip; int err; if (sscape->type == SSCAPE_VIVO) @@ -1045,9 +1049,8 @@ static int __devinit create_ad1845(struct snd_card *card, unsigned port, if (dma1 == dma2) dma2 = -1; - err = snd_cs4231_create(card, - port, -1, irq, dma1, dma2, - CS4231_HW_DETECT, CS4231_HWSHARE_DMA1, &chip); + err = snd_wss_create(card, port, -1, irq, dma1, dma2, + WSS_HW_DETECT, WSS_HWSHARE_DMA1, &chip); if (!err) { unsigned long flags; struct snd_pcm *pcm; @@ -1063,11 +1066,11 @@ static int __devinit create_ad1845(struct snd_card *card, unsigned port, * #define AD1845_IFACE_CONFIG \ (CS4231_AUTOCALIB | CS4231_RECORD_ENABLE | CS4231_PLAYBACK_ENABLE) - snd_cs4231_mce_up(chip); + snd_wss_mce_up(chip); spin_lock_irqsave(&chip->reg_lock, flags); - snd_cs4231_out(chip, CS4231_IFACE_CTRL, AD1845_IFACE_CONFIG); + snd_wss_out(chip, CS4231_IFACE_CTRL, AD1845_IFACE_CONFIG); spin_unlock_irqrestore(&chip->reg_lock, flags); - snd_cs4231_mce_down(chip); + snd_wss_mce_down(chip); */ if (sscape->type != SSCAPE_VIVO) { @@ -1077,11 +1080,11 @@ static int __devinit create_ad1845(struct snd_card *card, unsigned port, * be 14.31818 MHz, because we must set this register * to get the playback to sound correct ... */ - snd_cs4231_mce_up(chip); + snd_wss_mce_up(chip); spin_lock_irqsave(&chip->reg_lock, flags); - snd_cs4231_out(chip, AD1845_CRYS_CLOCK_SEL, 0x20); + snd_wss_out(chip, AD1845_CRYS_CLOCK_SEL, 0x20); spin_unlock_irqrestore(&chip->reg_lock, flags); - snd_cs4231_mce_down(chip); + snd_wss_mce_down(chip); /* * More custom configuration: @@ -1089,28 +1092,28 @@ static int __devinit create_ad1845(struct snd_card *card, unsigned port, * b) enable frequency selection (for capture/playback) */ spin_lock_irqsave(&chip->reg_lock, flags); - snd_cs4231_out(chip, CS4231_MISC_INFO, - CS4231_MODE2 | 0x10); - val = snd_cs4231_in(chip, AD1845_PWR_DOWN_CTRL); - snd_cs4231_out(chip, AD1845_PWR_DOWN_CTRL, - val | AD1845_FREQ_SEL_ENABLE); + snd_wss_out(chip, CS4231_MISC_INFO, + CS4231_MODE2 | 0x10); + val = snd_wss_in(chip, AD1845_PWR_DOWN_CTRL); + snd_wss_out(chip, AD1845_PWR_DOWN_CTRL, + val | AD1845_FREQ_SEL_ENABLE); spin_unlock_irqrestore(&chip->reg_lock, flags); } - err = snd_cs4231_pcm(chip, 0, &pcm); + err = snd_wss_pcm(chip, 0, &pcm); if (err < 0) { snd_printk(KERN_ERR "sscape: No PCM device " "for AD1845 chip\n"); goto _error; } - err = snd_cs4231_mixer(chip); + err = snd_wss_mixer(chip); if (err < 0) { snd_printk(KERN_ERR "sscape: No mixer device " "for AD1845 chip\n"); goto _error; } - err = snd_cs4231_timer(chip, 0, NULL); + err = snd_wss_timer(chip, 0, NULL); if (err < 0) { snd_printk(KERN_ERR "sscape: No timer device " "for AD1845 chip\n"); diff --git a/sound/isa/wavefront/wavefront.c b/sound/isa/wavefront/wavefront.c index 3a6c6fe1ec4..4c095bc7c72 100644 --- a/sound/isa/wavefront/wavefront.c +++ b/sound/isa/wavefront/wavefront.c @@ -1,6 +1,6 @@ /* * ALSA card-level driver for Turtle Beach Wavefront cards - * (Maui,Tropez,Tropez+) + * (Maui,Tropez,Tropez+) * * Copyright (c) 1997-1999 by Paul Barton-Davis <pbd@op.net> * @@ -29,6 +29,7 @@ #include <sound/core.h> #include <sound/initval.h> #include <sound/opl3.h> +#include <sound/wss.h> #include <sound/snd_wavefront.h> MODULE_AUTHOR("Paul Barton-Davis <pbd@op.net>"); @@ -319,8 +320,8 @@ snd_wavefront_new_midi (struct snd_card *card, snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_wavefront_midi_input); rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | - SNDRV_RAWMIDI_INFO_INPUT | - SNDRV_RAWMIDI_INFO_DUPLEX; + SNDRV_RAWMIDI_INFO_INPUT | + SNDRV_RAWMIDI_INFO_DUPLEX; return rmidi; } @@ -363,7 +364,7 @@ static int __devinit snd_wavefront_probe (struct snd_card *card, int dev) { snd_wavefront_card_t *acard = card->private_data; - struct snd_cs4231 *chip; + struct snd_wss *chip; struct snd_hwdep *wavefront_synth; struct snd_rawmidi *ics2115_internal_rmidi = NULL; struct snd_rawmidi *ics2115_external_rmidi = NULL; @@ -372,21 +373,20 @@ snd_wavefront_probe (struct snd_card *card, int dev) /* --------- PCM --------------- */ - if ((err = snd_cs4231_create (card, - cs4232_pcm_port[dev], - -1, - cs4232_pcm_irq[dev], - dma1[dev], - dma2[dev], - CS4231_HW_DETECT, 0, &chip)) < 0) { - snd_printk (KERN_ERR "can't allocate CS4231 device\n"); + err = snd_wss_create(card, cs4232_pcm_port[dev], -1, + cs4232_pcm_irq[dev], dma1[dev], dma2[dev], + WSS_HW_DETECT, 0, &chip); + if (err < 0) { + snd_printk(KERN_ERR "can't allocate WSS device\n"); return err; } - if ((err = snd_cs4231_pcm (chip, 0, NULL)) < 0) + err = snd_wss_pcm(chip, 0, NULL); + if (err < 0) return err; - if ((err = snd_cs4231_timer (chip, 0, NULL)) < 0) + err = snd_wss_timer(chip, 0, NULL); + if (err < 0) return err; /* ---------- OPL3 synth --------- */ @@ -394,24 +394,24 @@ snd_wavefront_probe (struct snd_card *card, int dev) if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) { struct snd_opl3 *opl3; - if ((err = snd_opl3_create(card, - fm_port[dev], - fm_port[dev] + 2, - OPL3_HW_OPL3_CS, - 0, &opl3)) < 0) { + err = snd_opl3_create(card, fm_port[dev], fm_port[dev] + 2, + OPL3_HW_OPL3_CS, 0, &opl3); + if (err < 0) { snd_printk (KERN_ERR "can't allocate or detect OPL3 synth\n"); return err; } - if ((err = snd_opl3_hwdep_new(opl3, hw_dev, 1, NULL)) < 0) + err = snd_opl3_hwdep_new(opl3, hw_dev, 1, NULL); + if (err < 0) return err; hw_dev++; } /* ------- ICS2115 Wavetable synth ------- */ - if ((acard->wavefront.res_base = request_region(ics2115_port[dev], 16, - "ICS2115")) == NULL) { + acard->wavefront.res_base = request_region(ics2115_port[dev], 16, + "ICS2115"); + if (acard->wavefront.res_base == NULL) { snd_printk(KERN_ERR "unable to grab ICS2115 i/o region 0x%lx-0x%lx\n", ics2115_port[dev], ics2115_port[dev] + 16 - 1); return -EBUSY; @@ -425,7 +425,8 @@ snd_wavefront_probe (struct snd_card *card, int dev) acard->wavefront.irq = ics2115_irq[dev]; acard->wavefront.base = ics2115_port[dev]; - if ((wavefront_synth = snd_wavefront_new_synth (card, hw_dev, acard)) == NULL) { + wavefront_synth = snd_wavefront_new_synth(card, hw_dev, acard); + if (wavefront_synth == NULL) { snd_printk (KERN_ERR "can't create WaveFront synth device\n"); return -ENOMEM; } @@ -436,7 +437,8 @@ snd_wavefront_probe (struct snd_card *card, int dev) /* --------- Mixer ------------ */ - if ((err = snd_cs4231_mixer(chip)) < 0) { + err = snd_wss_mixer(chip); + if (err < 0) { snd_printk (KERN_ERR "can't allocate mixer device\n"); return err; } @@ -444,11 +446,11 @@ snd_wavefront_probe (struct snd_card *card, int dev) /* -------- CS4232 MPU-401 interface -------- */ if (cs4232_mpu_port[dev] > 0 && cs4232_mpu_port[dev] != SNDRV_AUTO_PORT) { - if ((err = snd_mpu401_uart_new(card, midi_dev, MPU401_HW_CS4232, - cs4232_mpu_port[dev], 0, - cs4232_mpu_irq[dev], - IRQF_DISABLED, - NULL)) < 0) { + err = snd_mpu401_uart_new(card, midi_dev, MPU401_HW_CS4232, + cs4232_mpu_port[dev], 0, + cs4232_mpu_irq[dev], IRQF_DISABLED, + NULL); + if (err < 0) { snd_printk (KERN_ERR "can't allocate CS4232 MPU-401 device\n"); return err; } @@ -601,7 +603,7 @@ static struct isa_driver snd_wavefront_driver = { #ifdef CONFIG_PNP static int __devinit snd_wavefront_pnp_detect(struct pnp_card_link *pcard, - const struct pnp_card_device_id *pid) + const struct pnp_card_device_id *pid) { static int dev; struct snd_card *card; diff --git a/sound/isa/wavefront/wavefront_fx.c b/sound/isa/wavefront/wavefront_fx.c index 2efaa7f205a..dfc449a2194 100644 --- a/sound/isa/wavefront/wavefront_fx.c +++ b/sound/isa/wavefront/wavefront_fx.c @@ -180,11 +180,11 @@ snd_wavefront_fx_ioctl (struct snd_hwdep *sdev, struct file *file, unsigned short *pd; int err = 0; - snd_assert(sdev->card != NULL, return -ENODEV); - card = sdev->card; - - snd_assert(card->private_data != NULL, return -ENODEV); + if (snd_BUG_ON(!card)) + return -ENODEV; + if (snd_BUG_ON(!card->private_data)) + return -ENODEV; acard = card->private_data; dev = &acard->wavefront; diff --git a/sound/isa/wavefront/wavefront_midi.c b/sound/isa/wavefront/wavefront_midi.c index a33384a55b0..f14a7c0b699 100644 --- a/sound/isa/wavefront/wavefront_midi.c +++ b/sound/isa/wavefront/wavefront_midi.c @@ -235,8 +235,10 @@ static int snd_wavefront_midi_input_open(struct snd_rawmidi_substream *substream snd_wavefront_midi_t *midi; snd_wavefront_mpu_id mpu; - snd_assert(substream != NULL && substream->rmidi != NULL, return -EIO); - snd_assert(substream->rmidi->private_data != NULL, return -EIO); + if (snd_BUG_ON(!substream || !substream->rmidi)) + return -ENXIO; + if (snd_BUG_ON(!substream->rmidi->private_data)) + return -ENXIO; mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data); @@ -257,8 +259,10 @@ static int snd_wavefront_midi_output_open(struct snd_rawmidi_substream *substrea snd_wavefront_midi_t *midi; snd_wavefront_mpu_id mpu; - snd_assert(substream != NULL && substream->rmidi != NULL, return -EIO); - snd_assert(substream->rmidi->private_data != NULL, return -EIO); + if (snd_BUG_ON(!substream || !substream->rmidi)) + return -ENXIO; + if (snd_BUG_ON(!substream->rmidi->private_data)) + return -ENXIO; mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data); @@ -279,8 +283,10 @@ static int snd_wavefront_midi_input_close(struct snd_rawmidi_substream *substrea snd_wavefront_midi_t *midi; snd_wavefront_mpu_id mpu; - snd_assert(substream != NULL && substream->rmidi != NULL, return -EIO); - snd_assert(substream->rmidi->private_data != NULL, return -EIO); + if (snd_BUG_ON(!substream || !substream->rmidi)) + return -ENXIO; + if (snd_BUG_ON(!substream->rmidi->private_data)) + return -ENXIO; mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data); @@ -300,8 +306,10 @@ static int snd_wavefront_midi_output_close(struct snd_rawmidi_substream *substre snd_wavefront_midi_t *midi; snd_wavefront_mpu_id mpu; - snd_assert(substream != NULL && substream->rmidi != NULL, return -EIO); - snd_assert(substream->rmidi->private_data != NULL, return -EIO); + if (snd_BUG_ON(!substream || !substream->rmidi)) + return -ENXIO; + if (snd_BUG_ON(!substream->rmidi->private_data)) + return -ENXIO; mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data); diff --git a/sound/isa/wavefront/wavefront_synth.c b/sound/isa/wavefront/wavefront_synth.c index 0bb9b925660..4c410820a99 100644 --- a/sound/isa/wavefront/wavefront_synth.c +++ b/sound/isa/wavefront/wavefront_synth.c @@ -1648,9 +1648,10 @@ snd_wavefront_synth_ioctl (struct snd_hwdep *hw, struct file *file, card = (struct snd_card *) hw->card; - snd_assert(card != NULL, return -ENODEV); - - snd_assert(card->private_data != NULL, return -ENODEV); + if (snd_BUG_ON(!card)) + return -ENODEV; + if (snd_BUG_ON(!card->private_data)) + return -ENODEV; acard = card->private_data; dev = &acard->wavefront; diff --git a/sound/isa/wss/Makefile b/sound/isa/wss/Makefile new file mode 100644 index 00000000000..454fee769a3 --- /dev/null +++ b/sound/isa/wss/Makefile @@ -0,0 +1,10 @@ +# +# Makefile for ALSA +# Copyright (c) 2008 by Jaroslav Kysela <perex@perex.cz> +# + +snd-wss-lib-objs := wss_lib.o + +# Toplevel Module Dependency +obj-$(CONFIG_SND_WSS_LIB) += snd-wss-lib.o + diff --git a/sound/isa/wss/wss_lib.c b/sound/isa/wss/wss_lib.c new file mode 100644 index 00000000000..3d6c5f2838a --- /dev/null +++ b/sound/isa/wss/wss_lib.c @@ -0,0 +1,2322 @@ +/* + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> + * Routines for control of CS4231(A)/CS4232/InterWave & compatible chips + * + * Bugs: + * - sometimes record brokes playback with WSS portion of + * Yamaha OPL3-SA3 chip + * - CS4231 (GUS MAX) - still trouble with occasional noises + * - broken initialization? + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/slab.h> +#include <linux/ioport.h> +#include <sound/core.h> +#include <sound/wss.h> +#include <sound/pcm_params.h> +#include <sound/tlv.h> + +#include <asm/io.h> +#include <asm/dma.h> +#include <asm/irq.h> + +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); +MODULE_DESCRIPTION("Routines for control of CS4231(A)/CS4232/InterWave & compatible chips"); +MODULE_LICENSE("GPL"); + +#if 0 +#define SNDRV_DEBUG_MCE +#endif + +/* + * Some variables + */ + +static unsigned char freq_bits[14] = { + /* 5510 */ 0x00 | CS4231_XTAL2, + /* 6620 */ 0x0E | CS4231_XTAL2, + /* 8000 */ 0x00 | CS4231_XTAL1, + /* 9600 */ 0x0E | CS4231_XTAL1, + /* 11025 */ 0x02 | CS4231_XTAL2, + /* 16000 */ 0x02 | CS4231_XTAL1, + /* 18900 */ 0x04 | CS4231_XTAL2, + /* 22050 */ 0x06 | CS4231_XTAL2, + /* 27042 */ 0x04 | CS4231_XTAL1, + /* 32000 */ 0x06 | CS4231_XTAL1, + /* 33075 */ 0x0C | CS4231_XTAL2, + /* 37800 */ 0x08 | CS4231_XTAL2, + /* 44100 */ 0x0A | CS4231_XTAL2, + /* 48000 */ 0x0C | CS4231_XTAL1 +}; + +static unsigned int rates[14] = { + 5510, 6620, 8000, 9600, 11025, 16000, 18900, 22050, + 27042, 32000, 33075, 37800, 44100, 48000 +}; + +static struct snd_pcm_hw_constraint_list hw_constraints_rates = { + .count = ARRAY_SIZE(rates), + .list = rates, + .mask = 0, +}; + +static int snd_wss_xrate(struct snd_pcm_runtime *runtime) +{ + return snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + &hw_constraints_rates); +} + +static unsigned char snd_wss_original_image[32] = +{ + 0x00, /* 00/00 - lic */ + 0x00, /* 01/01 - ric */ + 0x9f, /* 02/02 - la1ic */ + 0x9f, /* 03/03 - ra1ic */ + 0x9f, /* 04/04 - la2ic */ + 0x9f, /* 05/05 - ra2ic */ + 0xbf, /* 06/06 - loc */ + 0xbf, /* 07/07 - roc */ + 0x20, /* 08/08 - pdfr */ + CS4231_AUTOCALIB, /* 09/09 - ic */ + 0x00, /* 0a/10 - pc */ + 0x00, /* 0b/11 - ti */ + CS4231_MODE2, /* 0c/12 - mi */ + 0xfc, /* 0d/13 - lbc */ + 0x00, /* 0e/14 - pbru */ + 0x00, /* 0f/15 - pbrl */ + 0x80, /* 10/16 - afei */ + 0x01, /* 11/17 - afeii */ + 0x9f, /* 12/18 - llic */ + 0x9f, /* 13/19 - rlic */ + 0x00, /* 14/20 - tlb */ + 0x00, /* 15/21 - thb */ + 0x00, /* 16/22 - la3mic/reserved */ + 0x00, /* 17/23 - ra3mic/reserved */ + 0x00, /* 18/24 - afs */ + 0x00, /* 19/25 - lamoc/version */ + 0xcf, /* 1a/26 - mioc */ + 0x00, /* 1b/27 - ramoc/reserved */ + 0x20, /* 1c/28 - cdfr */ + 0x00, /* 1d/29 - res4 */ + 0x00, /* 1e/30 - cbru */ + 0x00, /* 1f/31 - cbrl */ +}; + +static unsigned char snd_opti93x_original_image[32] = +{ + 0x00, /* 00/00 - l_mixout_outctrl */ + 0x00, /* 01/01 - r_mixout_outctrl */ + 0x88, /* 02/02 - l_cd_inctrl */ + 0x88, /* 03/03 - r_cd_inctrl */ + 0x88, /* 04/04 - l_a1/fm_inctrl */ + 0x88, /* 05/05 - r_a1/fm_inctrl */ + 0x80, /* 06/06 - l_dac_inctrl */ + 0x80, /* 07/07 - r_dac_inctrl */ + 0x00, /* 08/08 - ply_dataform_reg */ + 0x00, /* 09/09 - if_conf */ + 0x00, /* 0a/10 - pin_ctrl */ + 0x00, /* 0b/11 - err_init_reg */ + 0x0a, /* 0c/12 - id_reg */ + 0x00, /* 0d/13 - reserved */ + 0x00, /* 0e/14 - ply_upcount_reg */ + 0x00, /* 0f/15 - ply_lowcount_reg */ + 0x88, /* 10/16 - reserved/l_a1_inctrl */ + 0x88, /* 11/17 - reserved/r_a1_inctrl */ + 0x88, /* 12/18 - l_line_inctrl */ + 0x88, /* 13/19 - r_line_inctrl */ + 0x88, /* 14/20 - l_mic_inctrl */ + 0x88, /* 15/21 - r_mic_inctrl */ + 0x80, /* 16/22 - l_out_outctrl */ + 0x80, /* 17/23 - r_out_outctrl */ + 0x00, /* 18/24 - reserved */ + 0x00, /* 19/25 - reserved */ + 0x00, /* 1a/26 - reserved */ + 0x00, /* 1b/27 - reserved */ + 0x00, /* 1c/28 - cap_dataform_reg */ + 0x00, /* 1d/29 - reserved */ + 0x00, /* 1e/30 - cap_upcount_reg */ + 0x00 /* 1f/31 - cap_lowcount_reg */ +}; + +/* + * Basic I/O functions + */ + +static inline void wss_outb(struct snd_wss *chip, u8 offset, u8 val) +{ + outb(val, chip->port + offset); +} + +static inline u8 wss_inb(struct snd_wss *chip, u8 offset) +{ + return inb(chip->port + offset); +} + +static void snd_wss_wait(struct snd_wss *chip) +{ + int timeout; + + for (timeout = 250; + timeout > 0 && (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT); + timeout--) + udelay(100); +} + +static void snd_wss_outm(struct snd_wss *chip, unsigned char reg, + unsigned char mask, unsigned char value) +{ + unsigned char tmp = (chip->image[reg] & mask) | value; + + snd_wss_wait(chip); +#ifdef CONFIG_SND_DEBUG + if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) + snd_printk("outm: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value); +#endif + chip->image[reg] = tmp; + if (!chip->calibrate_mute) { + wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg); + wmb(); + wss_outb(chip, CS4231P(REG), tmp); + mb(); + } +} + +static void snd_wss_dout(struct snd_wss *chip, unsigned char reg, + unsigned char value) +{ + int timeout; + + for (timeout = 250; + timeout > 0 && (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT); + timeout--) + udelay(10); + wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg); + wss_outb(chip, CS4231P(REG), value); + mb(); +} + +void snd_wss_out(struct snd_wss *chip, unsigned char reg, unsigned char value) +{ + snd_wss_wait(chip); +#ifdef CONFIG_SND_DEBUG + if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) + snd_printk("out: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value); +#endif + wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg); + wss_outb(chip, CS4231P(REG), value); + chip->image[reg] = value; + mb(); + snd_printdd("codec out - reg 0x%x = 0x%x\n", + chip->mce_bit | reg, value); +} +EXPORT_SYMBOL(snd_wss_out); + +unsigned char snd_wss_in(struct snd_wss *chip, unsigned char reg) +{ + snd_wss_wait(chip); +#ifdef CONFIG_SND_DEBUG + if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) + snd_printk("in: auto calibration time out - reg = 0x%x\n", reg); +#endif + wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg); + mb(); + return wss_inb(chip, CS4231P(REG)); +} +EXPORT_SYMBOL(snd_wss_in); + +void snd_cs4236_ext_out(struct snd_wss *chip, unsigned char reg, + unsigned char val) +{ + wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | 0x17); + wss_outb(chip, CS4231P(REG), + reg | (chip->image[CS4236_EXT_REG] & 0x01)); + wss_outb(chip, CS4231P(REG), val); + chip->eimage[CS4236_REG(reg)] = val; +#if 0 + printk("ext out : reg = 0x%x, val = 0x%x\n", reg, val); +#endif +} +EXPORT_SYMBOL(snd_cs4236_ext_out); + +unsigned char snd_cs4236_ext_in(struct snd_wss *chip, unsigned char reg) +{ + wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | 0x17); + wss_outb(chip, CS4231P(REG), + reg | (chip->image[CS4236_EXT_REG] & 0x01)); +#if 1 + return wss_inb(chip, CS4231P(REG)); +#else + { + unsigned char res; + res = wss_inb(chip, CS4231P(REG)); + printk("ext in : reg = 0x%x, val = 0x%x\n", reg, res); + return res; + } +#endif +} +EXPORT_SYMBOL(snd_cs4236_ext_in); + +#if 0 + +static void snd_wss_debug(struct snd_wss *chip) +{ + printk(KERN_DEBUG + "CS4231 REGS: INDEX = 0x%02x " + " STATUS = 0x%02x\n", + wss_inb(chip, CS4231P(REGSEL)), + wss_inb(chip, CS4231P(STATUS))); + printk(KERN_DEBUG + " 0x00: left input = 0x%02x " + " 0x10: alt 1 (CFIG 2) = 0x%02x\n", + snd_wss_in(chip, 0x00), + snd_wss_in(chip, 0x10)); + printk(KERN_DEBUG + " 0x01: right input = 0x%02x " + " 0x11: alt 2 (CFIG 3) = 0x%02x\n", + snd_wss_in(chip, 0x01), + snd_wss_in(chip, 0x11)); + printk(KERN_DEBUG + " 0x02: GF1 left input = 0x%02x " + " 0x12: left line in = 0x%02x\n", + snd_wss_in(chip, 0x02), + snd_wss_in(chip, 0x12)); + printk(KERN_DEBUG + " 0x03: GF1 right input = 0x%02x " + " 0x13: right line in = 0x%02x\n", + snd_wss_in(chip, 0x03), + snd_wss_in(chip, 0x13)); + printk(KERN_DEBUG + " 0x04: CD left input = 0x%02x " + " 0x14: timer low = 0x%02x\n", + snd_wss_in(chip, 0x04), + snd_wss_in(chip, 0x14)); + printk(KERN_DEBUG + " 0x05: CD right input = 0x%02x " + " 0x15: timer high = 0x%02x\n", + snd_wss_in(chip, 0x05), + snd_wss_in(chip, 0x15)); + printk(KERN_DEBUG + " 0x06: left output = 0x%02x " + " 0x16: left MIC (PnP) = 0x%02x\n", + snd_wss_in(chip, 0x06), + snd_wss_in(chip, 0x16)); + printk(KERN_DEBUG + " 0x07: right output = 0x%02x " + " 0x17: right MIC (PnP) = 0x%02x\n", + snd_wss_in(chip, 0x07), + snd_wss_in(chip, 0x17)); + printk(KERN_DEBUG + " 0x08: playback format = 0x%02x " + " 0x18: IRQ status = 0x%02x\n", + snd_wss_in(chip, 0x08), + snd_wss_in(chip, 0x18)); + printk(KERN_DEBUG + " 0x09: iface (CFIG 1) = 0x%02x " + " 0x19: left line out = 0x%02x\n", + snd_wss_in(chip, 0x09), + snd_wss_in(chip, 0x19)); + printk(KERN_DEBUG + " 0x0a: pin control = 0x%02x " + " 0x1a: mono control = 0x%02x\n", + snd_wss_in(chip, 0x0a), + snd_wss_in(chip, 0x1a)); + printk(KERN_DEBUG + " 0x0b: init & status = 0x%02x " + " 0x1b: right line out = 0x%02x\n", + snd_wss_in(chip, 0x0b), + snd_wss_in(chip, 0x1b)); + printk(KERN_DEBUG + " 0x0c: revision & mode = 0x%02x " + " 0x1c: record format = 0x%02x\n", + snd_wss_in(chip, 0x0c), + snd_wss_in(chip, 0x1c)); + printk(KERN_DEBUG + " 0x0d: loopback = 0x%02x " + " 0x1d: var freq (PnP) = 0x%02x\n", + snd_wss_in(chip, 0x0d), + snd_wss_in(chip, 0x1d)); + printk(KERN_DEBUG + " 0x0e: ply upr count = 0x%02x " + " 0x1e: ply lwr count = 0x%02x\n", + snd_wss_in(chip, 0x0e), + snd_wss_in(chip, 0x1e)); + printk(KERN_DEBUG + " 0x0f: rec upr count = 0x%02x " + " 0x1f: rec lwr count = 0x%02x\n", + snd_wss_in(chip, 0x0f), + snd_wss_in(chip, 0x1f)); +} + +#endif + +/* + * CS4231 detection / MCE routines + */ + +static void snd_wss_busy_wait(struct snd_wss *chip) +{ + int timeout; + + /* huh.. looks like this sequence is proper for CS4231A chip (GUS MAX) */ + for (timeout = 5; timeout > 0; timeout--) + wss_inb(chip, CS4231P(REGSEL)); + /* end of cleanup sequence */ + for (timeout = 25000; + timeout > 0 && (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT); + timeout--) + udelay(10); +} + +void snd_wss_mce_up(struct snd_wss *chip) +{ + unsigned long flags; + int timeout; + + snd_wss_wait(chip); +#ifdef CONFIG_SND_DEBUG + if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) + snd_printk("mce_up - auto calibration time out (0)\n"); +#endif + spin_lock_irqsave(&chip->reg_lock, flags); + chip->mce_bit |= CS4231_MCE; + timeout = wss_inb(chip, CS4231P(REGSEL)); + if (timeout == 0x80) + snd_printk("mce_up [0x%lx]: serious init problem - codec still busy\n", chip->port); + if (!(timeout & CS4231_MCE)) + wss_outb(chip, CS4231P(REGSEL), + chip->mce_bit | (timeout & 0x1f)); + spin_unlock_irqrestore(&chip->reg_lock, flags); +} +EXPORT_SYMBOL(snd_wss_mce_up); + +void snd_wss_mce_down(struct snd_wss *chip) +{ + unsigned long flags; + unsigned long end_time; + int timeout; + int hw_mask = WSS_HW_CS4231_MASK | WSS_HW_CS4232_MASK | WSS_HW_AD1848; + + snd_wss_busy_wait(chip); + +#ifdef CONFIG_SND_DEBUG + if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) + snd_printk("mce_down [0x%lx] - auto calibration time out (0)\n", (long)CS4231P(REGSEL)); +#endif + spin_lock_irqsave(&chip->reg_lock, flags); + chip->mce_bit &= ~CS4231_MCE; + timeout = wss_inb(chip, CS4231P(REGSEL)); + wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | (timeout & 0x1f)); + spin_unlock_irqrestore(&chip->reg_lock, flags); + if (timeout == 0x80) + snd_printk("mce_down [0x%lx]: serious init problem - codec still busy\n", chip->port); + if ((timeout & CS4231_MCE) == 0 || !(chip->hardware & hw_mask)) + return; + + /* + * Wait for (possible -- during init auto-calibration may not be set) + * calibration process to start. Needs upto 5 sample periods on AD1848 + * which at the slowest possible rate of 5.5125 kHz means 907 us. + */ + msleep(1); + + snd_printdd("(1) jiffies = %lu\n", jiffies); + + /* check condition up to 250 ms */ + end_time = jiffies + msecs_to_jiffies(250); + while (snd_wss_in(chip, CS4231_TEST_INIT) & + CS4231_CALIB_IN_PROGRESS) { + + if (time_after(jiffies, end_time)) { + snd_printk(KERN_ERR "mce_down - " + "auto calibration time out (2)\n"); + return; + } + msleep(1); + } + + snd_printdd("(2) jiffies = %lu\n", jiffies); + + /* check condition up to 100 ms */ + end_time = jiffies + msecs_to_jiffies(100); + while (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) { + if (time_after(jiffies, end_time)) { + snd_printk(KERN_ERR "mce_down - auto calibration time out (3)\n"); + return; + } + msleep(1); + } + + snd_printdd("(3) jiffies = %lu\n", jiffies); + snd_printd("mce_down - exit = 0x%x\n", wss_inb(chip, CS4231P(REGSEL))); +} +EXPORT_SYMBOL(snd_wss_mce_down); + +static unsigned int snd_wss_get_count(unsigned char format, unsigned int size) +{ + switch (format & 0xe0) { + case CS4231_LINEAR_16: + case CS4231_LINEAR_16_BIG: + size >>= 1; + break; + case CS4231_ADPCM_16: + return size >> 2; + } + if (format & CS4231_STEREO) + size >>= 1; + return size; +} + +static int snd_wss_trigger(struct snd_pcm_substream *substream, + int cmd) +{ + struct snd_wss *chip = snd_pcm_substream_chip(substream); + int result = 0; + unsigned int what; + struct snd_pcm_substream *s; + int do_start; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + do_start = 1; break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + do_start = 0; break; + default: + return -EINVAL; + } + + what = 0; + snd_pcm_group_for_each_entry(s, substream) { + if (s == chip->playback_substream) { + what |= CS4231_PLAYBACK_ENABLE; + snd_pcm_trigger_done(s, substream); + } else if (s == chip->capture_substream) { + what |= CS4231_RECORD_ENABLE; + snd_pcm_trigger_done(s, substream); + } + } + spin_lock(&chip->reg_lock); + if (do_start) { + chip->image[CS4231_IFACE_CTRL] |= what; + if (chip->trigger) + chip->trigger(chip, what, 1); + } else { + chip->image[CS4231_IFACE_CTRL] &= ~what; + if (chip->trigger) + chip->trigger(chip, what, 0); + } + snd_wss_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]); + spin_unlock(&chip->reg_lock); +#if 0 + snd_wss_debug(chip); +#endif + return result; +} + +/* + * CODEC I/O + */ + +static unsigned char snd_wss_get_rate(unsigned int rate) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(rates); i++) + if (rate == rates[i]) + return freq_bits[i]; + // snd_BUG(); + return freq_bits[ARRAY_SIZE(rates) - 1]; +} + +static unsigned char snd_wss_get_format(struct snd_wss *chip, + int format, + int channels) +{ + unsigned char rformat; + + rformat = CS4231_LINEAR_8; + switch (format) { + case SNDRV_PCM_FORMAT_MU_LAW: rformat = CS4231_ULAW_8; break; + case SNDRV_PCM_FORMAT_A_LAW: rformat = CS4231_ALAW_8; break; + case SNDRV_PCM_FORMAT_S16_LE: rformat = CS4231_LINEAR_16; break; + case SNDRV_PCM_FORMAT_S16_BE: rformat = CS4231_LINEAR_16_BIG; break; + case SNDRV_PCM_FORMAT_IMA_ADPCM: rformat = CS4231_ADPCM_16; break; + } + if (channels > 1) + rformat |= CS4231_STEREO; +#if 0 + snd_printk("get_format: 0x%x (mode=0x%x)\n", format, mode); +#endif + return rformat; +} + +static void snd_wss_calibrate_mute(struct snd_wss *chip, int mute) +{ + unsigned long flags; + + mute = mute ? 0x80 : 0; + spin_lock_irqsave(&chip->reg_lock, flags); + if (chip->calibrate_mute == mute) { + spin_unlock_irqrestore(&chip->reg_lock, flags); + return; + } + if (!mute) { + snd_wss_dout(chip, CS4231_LEFT_INPUT, + chip->image[CS4231_LEFT_INPUT]); + snd_wss_dout(chip, CS4231_RIGHT_INPUT, + chip->image[CS4231_RIGHT_INPUT]); + snd_wss_dout(chip, CS4231_LOOPBACK, + chip->image[CS4231_LOOPBACK]); + } + snd_wss_dout(chip, CS4231_AUX1_LEFT_INPUT, + mute | chip->image[CS4231_AUX1_LEFT_INPUT]); + snd_wss_dout(chip, CS4231_AUX1_RIGHT_INPUT, + mute | chip->image[CS4231_AUX1_RIGHT_INPUT]); + snd_wss_dout(chip, CS4231_AUX2_LEFT_INPUT, + mute | chip->image[CS4231_AUX2_LEFT_INPUT]); + snd_wss_dout(chip, CS4231_AUX2_RIGHT_INPUT, + mute | chip->image[CS4231_AUX2_RIGHT_INPUT]); + snd_wss_dout(chip, CS4231_LEFT_OUTPUT, + mute | chip->image[CS4231_LEFT_OUTPUT]); + snd_wss_dout(chip, CS4231_RIGHT_OUTPUT, + mute | chip->image[CS4231_RIGHT_OUTPUT]); + if (!(chip->hardware & WSS_HW_AD1848_MASK)) { + snd_wss_dout(chip, CS4231_LEFT_LINE_IN, + mute | chip->image[CS4231_LEFT_LINE_IN]); + snd_wss_dout(chip, CS4231_RIGHT_LINE_IN, + mute | chip->image[CS4231_RIGHT_LINE_IN]); + snd_wss_dout(chip, CS4231_MONO_CTRL, + mute ? 0xc0 : chip->image[CS4231_MONO_CTRL]); + } + if (chip->hardware == WSS_HW_INTERWAVE) { + snd_wss_dout(chip, CS4231_LEFT_MIC_INPUT, + mute | chip->image[CS4231_LEFT_MIC_INPUT]); + snd_wss_dout(chip, CS4231_RIGHT_MIC_INPUT, + mute | chip->image[CS4231_RIGHT_MIC_INPUT]); + snd_wss_dout(chip, CS4231_LINE_LEFT_OUTPUT, + mute | chip->image[CS4231_LINE_LEFT_OUTPUT]); + snd_wss_dout(chip, CS4231_LINE_RIGHT_OUTPUT, + mute | chip->image[CS4231_LINE_RIGHT_OUTPUT]); + } + chip->calibrate_mute = mute; + spin_unlock_irqrestore(&chip->reg_lock, flags); +} + +static void snd_wss_playback_format(struct snd_wss *chip, + struct snd_pcm_hw_params *params, + unsigned char pdfr) +{ + unsigned long flags; + int full_calib = 1; + + mutex_lock(&chip->mce_mutex); + snd_wss_calibrate_mute(chip, 1); + if (chip->hardware == WSS_HW_CS4231A || + (chip->hardware & WSS_HW_CS4232_MASK)) { + spin_lock_irqsave(&chip->reg_lock, flags); + if ((chip->image[CS4231_PLAYBK_FORMAT] & 0x0f) == (pdfr & 0x0f)) { /* rate is same? */ + snd_wss_out(chip, CS4231_ALT_FEATURE_1, + chip->image[CS4231_ALT_FEATURE_1] | 0x10); + chip->image[CS4231_PLAYBK_FORMAT] = pdfr; + snd_wss_out(chip, CS4231_PLAYBK_FORMAT, + chip->image[CS4231_PLAYBK_FORMAT]); + snd_wss_out(chip, CS4231_ALT_FEATURE_1, + chip->image[CS4231_ALT_FEATURE_1] &= ~0x10); + udelay(100); /* Fixes audible clicks at least on GUS MAX */ + full_calib = 0; + } + spin_unlock_irqrestore(&chip->reg_lock, flags); + } + if (full_calib) { + snd_wss_mce_up(chip); + spin_lock_irqsave(&chip->reg_lock, flags); + if (chip->hardware != WSS_HW_INTERWAVE && !chip->single_dma) { + if (chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE) + pdfr = (pdfr & 0xf0) | + (chip->image[CS4231_REC_FORMAT] & 0x0f); + } else { + chip->image[CS4231_PLAYBK_FORMAT] = pdfr; + } + snd_wss_out(chip, CS4231_PLAYBK_FORMAT, pdfr); + spin_unlock_irqrestore(&chip->reg_lock, flags); + if (chip->hardware == WSS_HW_OPL3SA2) + udelay(100); /* this seems to help */ + snd_wss_mce_down(chip); + } + snd_wss_calibrate_mute(chip, 0); + mutex_unlock(&chip->mce_mutex); +} + +static void snd_wss_capture_format(struct snd_wss *chip, + struct snd_pcm_hw_params *params, + unsigned char cdfr) +{ + unsigned long flags; + int full_calib = 1; + + mutex_lock(&chip->mce_mutex); + snd_wss_calibrate_mute(chip, 1); + if (chip->hardware == WSS_HW_CS4231A || + (chip->hardware & WSS_HW_CS4232_MASK)) { + spin_lock_irqsave(&chip->reg_lock, flags); + if ((chip->image[CS4231_PLAYBK_FORMAT] & 0x0f) == (cdfr & 0x0f) || /* rate is same? */ + (chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE)) { + snd_wss_out(chip, CS4231_ALT_FEATURE_1, + chip->image[CS4231_ALT_FEATURE_1] | 0x20); + snd_wss_out(chip, CS4231_REC_FORMAT, + chip->image[CS4231_REC_FORMAT] = cdfr); + snd_wss_out(chip, CS4231_ALT_FEATURE_1, + chip->image[CS4231_ALT_FEATURE_1] &= ~0x20); + full_calib = 0; + } + spin_unlock_irqrestore(&chip->reg_lock, flags); + } + if (full_calib) { + snd_wss_mce_up(chip); + spin_lock_irqsave(&chip->reg_lock, flags); + if (chip->hardware != WSS_HW_INTERWAVE && + !(chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE)) { + if (chip->single_dma) + snd_wss_out(chip, CS4231_PLAYBK_FORMAT, cdfr); + else + snd_wss_out(chip, CS4231_PLAYBK_FORMAT, + (chip->image[CS4231_PLAYBK_FORMAT] & 0xf0) | + (cdfr & 0x0f)); + spin_unlock_irqrestore(&chip->reg_lock, flags); + snd_wss_mce_down(chip); + snd_wss_mce_up(chip); + spin_lock_irqsave(&chip->reg_lock, flags); + } + if (chip->hardware & WSS_HW_AD1848_MASK) + snd_wss_out(chip, CS4231_PLAYBK_FORMAT, cdfr); + else + snd_wss_out(chip, CS4231_REC_FORMAT, cdfr); + spin_unlock_irqrestore(&chip->reg_lock, flags); + snd_wss_mce_down(chip); + } + snd_wss_calibrate_mute(chip, 0); + mutex_unlock(&chip->mce_mutex); +} + +/* + * Timer interface + */ + +static unsigned long snd_wss_timer_resolution(struct snd_timer *timer) +{ + struct snd_wss *chip = snd_timer_chip(timer); + if (chip->hardware & WSS_HW_CS4236B_MASK) + return 14467; + else + return chip->image[CS4231_PLAYBK_FORMAT] & 1 ? 9969 : 9920; +} + +static int snd_wss_timer_start(struct snd_timer *timer) +{ + unsigned long flags; + unsigned int ticks; + struct snd_wss *chip = snd_timer_chip(timer); + spin_lock_irqsave(&chip->reg_lock, flags); + ticks = timer->sticks; + if ((chip->image[CS4231_ALT_FEATURE_1] & CS4231_TIMER_ENABLE) == 0 || + (unsigned char)(ticks >> 8) != chip->image[CS4231_TIMER_HIGH] || + (unsigned char)ticks != chip->image[CS4231_TIMER_LOW]) { + chip->image[CS4231_TIMER_HIGH] = (unsigned char) (ticks >> 8); + snd_wss_out(chip, CS4231_TIMER_HIGH, + chip->image[CS4231_TIMER_HIGH]); + chip->image[CS4231_TIMER_LOW] = (unsigned char) ticks; + snd_wss_out(chip, CS4231_TIMER_LOW, + chip->image[CS4231_TIMER_LOW]); + snd_wss_out(chip, CS4231_ALT_FEATURE_1, + chip->image[CS4231_ALT_FEATURE_1] | + CS4231_TIMER_ENABLE); + } + spin_unlock_irqrestore(&chip->reg_lock, flags); + return 0; +} + +static int snd_wss_timer_stop(struct snd_timer *timer) +{ + unsigned long flags; + struct snd_wss *chip = snd_timer_chip(timer); + spin_lock_irqsave(&chip->reg_lock, flags); + chip->image[CS4231_ALT_FEATURE_1] &= ~CS4231_TIMER_ENABLE; + snd_wss_out(chip, CS4231_ALT_FEATURE_1, + chip->image[CS4231_ALT_FEATURE_1]); + spin_unlock_irqrestore(&chip->reg_lock, flags); + return 0; +} + +static void snd_wss_init(struct snd_wss *chip) +{ + unsigned long flags; + + snd_wss_mce_down(chip); + +#ifdef SNDRV_DEBUG_MCE + snd_printk("init: (1)\n"); +#endif + snd_wss_mce_up(chip); + spin_lock_irqsave(&chip->reg_lock, flags); + chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE | + CS4231_PLAYBACK_PIO | + CS4231_RECORD_ENABLE | + CS4231_RECORD_PIO | + CS4231_CALIB_MODE); + chip->image[CS4231_IFACE_CTRL] |= CS4231_AUTOCALIB; + snd_wss_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]); + spin_unlock_irqrestore(&chip->reg_lock, flags); + snd_wss_mce_down(chip); + +#ifdef SNDRV_DEBUG_MCE + snd_printk("init: (2)\n"); +#endif + + snd_wss_mce_up(chip); + spin_lock_irqsave(&chip->reg_lock, flags); + snd_wss_out(chip, + CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1]); + spin_unlock_irqrestore(&chip->reg_lock, flags); + snd_wss_mce_down(chip); + +#ifdef SNDRV_DEBUG_MCE + snd_printk("init: (3) - afei = 0x%x\n", + chip->image[CS4231_ALT_FEATURE_1]); +#endif + + spin_lock_irqsave(&chip->reg_lock, flags); + snd_wss_out(chip, CS4231_ALT_FEATURE_2, + chip->image[CS4231_ALT_FEATURE_2]); + spin_unlock_irqrestore(&chip->reg_lock, flags); + + snd_wss_mce_up(chip); + spin_lock_irqsave(&chip->reg_lock, flags); + snd_wss_out(chip, CS4231_PLAYBK_FORMAT, + chip->image[CS4231_PLAYBK_FORMAT]); + spin_unlock_irqrestore(&chip->reg_lock, flags); + snd_wss_mce_down(chip); + +#ifdef SNDRV_DEBUG_MCE + snd_printk("init: (4)\n"); +#endif + + snd_wss_mce_up(chip); + spin_lock_irqsave(&chip->reg_lock, flags); + if (!(chip->hardware & WSS_HW_AD1848_MASK)) + snd_wss_out(chip, CS4231_REC_FORMAT, + chip->image[CS4231_REC_FORMAT]); + spin_unlock_irqrestore(&chip->reg_lock, flags); + snd_wss_mce_down(chip); + +#ifdef SNDRV_DEBUG_MCE + snd_printk("init: (5)\n"); +#endif +} + +static int snd_wss_open(struct snd_wss *chip, unsigned int mode) +{ + unsigned long flags; + + mutex_lock(&chip->open_mutex); + if ((chip->mode & mode) || + ((chip->mode & WSS_MODE_OPEN) && chip->single_dma)) { + mutex_unlock(&chip->open_mutex); + return -EAGAIN; + } + if (chip->mode & WSS_MODE_OPEN) { + chip->mode |= mode; + mutex_unlock(&chip->open_mutex); + return 0; + } + /* ok. now enable and ack CODEC IRQ */ + spin_lock_irqsave(&chip->reg_lock, flags); + if (!(chip->hardware & WSS_HW_AD1848_MASK)) { + snd_wss_out(chip, CS4231_IRQ_STATUS, + CS4231_PLAYBACK_IRQ | + CS4231_RECORD_IRQ | + CS4231_TIMER_IRQ); + snd_wss_out(chip, CS4231_IRQ_STATUS, 0); + } + wss_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */ + wss_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */ + chip->image[CS4231_PIN_CTRL] |= CS4231_IRQ_ENABLE; + snd_wss_out(chip, CS4231_PIN_CTRL, chip->image[CS4231_PIN_CTRL]); + if (!(chip->hardware & WSS_HW_AD1848_MASK)) { + snd_wss_out(chip, CS4231_IRQ_STATUS, + CS4231_PLAYBACK_IRQ | + CS4231_RECORD_IRQ | + CS4231_TIMER_IRQ); + snd_wss_out(chip, CS4231_IRQ_STATUS, 0); + } + spin_unlock_irqrestore(&chip->reg_lock, flags); + + chip->mode = mode; + mutex_unlock(&chip->open_mutex); + return 0; +} + +static void snd_wss_close(struct snd_wss *chip, unsigned int mode) +{ + unsigned long flags; + + mutex_lock(&chip->open_mutex); + chip->mode &= ~mode; + if (chip->mode & WSS_MODE_OPEN) { + mutex_unlock(&chip->open_mutex); + return; + } + snd_wss_calibrate_mute(chip, 1); + + /* disable IRQ */ + spin_lock_irqsave(&chip->reg_lock, flags); + if (!(chip->hardware & WSS_HW_AD1848_MASK)) + snd_wss_out(chip, CS4231_IRQ_STATUS, 0); + wss_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */ + wss_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */ + chip->image[CS4231_PIN_CTRL] &= ~CS4231_IRQ_ENABLE; + snd_wss_out(chip, CS4231_PIN_CTRL, chip->image[CS4231_PIN_CTRL]); + + /* now disable record & playback */ + + if (chip->image[CS4231_IFACE_CTRL] & (CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO | + CS4231_RECORD_ENABLE | CS4231_RECORD_PIO)) { + spin_unlock_irqrestore(&chip->reg_lock, flags); + snd_wss_mce_up(chip); + spin_lock_irqsave(&chip->reg_lock, flags); + chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO | + CS4231_RECORD_ENABLE | CS4231_RECORD_PIO); + snd_wss_out(chip, CS4231_IFACE_CTRL, + chip->image[CS4231_IFACE_CTRL]); + spin_unlock_irqrestore(&chip->reg_lock, flags); + snd_wss_mce_down(chip); + spin_lock_irqsave(&chip->reg_lock, flags); + } + + /* clear IRQ again */ + if (!(chip->hardware & WSS_HW_AD1848_MASK)) + snd_wss_out(chip, CS4231_IRQ_STATUS, 0); + wss_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */ + wss_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */ + spin_unlock_irqrestore(&chip->reg_lock, flags); + + snd_wss_calibrate_mute(chip, 0); + + chip->mode = 0; + mutex_unlock(&chip->open_mutex); +} + +/* + * timer open/close + */ + +static int snd_wss_timer_open(struct snd_timer *timer) +{ + struct snd_wss *chip = snd_timer_chip(timer); + snd_wss_open(chip, WSS_MODE_TIMER); + return 0; +} + +static int snd_wss_timer_close(struct snd_timer *timer) +{ + struct snd_wss *chip = snd_timer_chip(timer); + snd_wss_close(chip, WSS_MODE_TIMER); + return 0; +} + +static struct snd_timer_hardware snd_wss_timer_table = +{ + .flags = SNDRV_TIMER_HW_AUTO, + .resolution = 9945, + .ticks = 65535, + .open = snd_wss_timer_open, + .close = snd_wss_timer_close, + .c_resolution = snd_wss_timer_resolution, + .start = snd_wss_timer_start, + .stop = snd_wss_timer_stop, +}; + +/* + * ok.. exported functions.. + */ + +static int snd_wss_playback_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + struct snd_wss *chip = snd_pcm_substream_chip(substream); + unsigned char new_pdfr; + int err; + + if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0) + return err; + new_pdfr = snd_wss_get_format(chip, params_format(hw_params), + params_channels(hw_params)) | + snd_wss_get_rate(params_rate(hw_params)); + chip->set_playback_format(chip, hw_params, new_pdfr); + return 0; +} + +static int snd_wss_playback_hw_free(struct snd_pcm_substream *substream) +{ + return snd_pcm_lib_free_pages(substream); +} + +static int snd_wss_playback_prepare(struct snd_pcm_substream *substream) +{ + struct snd_wss *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + unsigned long flags; + unsigned int size = snd_pcm_lib_buffer_bytes(substream); + unsigned int count = snd_pcm_lib_period_bytes(substream); + + spin_lock_irqsave(&chip->reg_lock, flags); + chip->p_dma_size = size; + chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO); + snd_dma_program(chip->dma1, runtime->dma_addr, size, DMA_MODE_WRITE | DMA_AUTOINIT); + count = snd_wss_get_count(chip->image[CS4231_PLAYBK_FORMAT], count) - 1; + snd_wss_out(chip, CS4231_PLY_LWR_CNT, (unsigned char) count); + snd_wss_out(chip, CS4231_PLY_UPR_CNT, (unsigned char) (count >> 8)); + spin_unlock_irqrestore(&chip->reg_lock, flags); +#if 0 + snd_wss_debug(chip); +#endif + return 0; +} + +static int snd_wss_capture_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + struct snd_wss *chip = snd_pcm_substream_chip(substream); + unsigned char new_cdfr; + int err; + + if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0) + return err; + new_cdfr = snd_wss_get_format(chip, params_format(hw_params), + params_channels(hw_params)) | + snd_wss_get_rate(params_rate(hw_params)); + chip->set_capture_format(chip, hw_params, new_cdfr); + return 0; +} + +static int snd_wss_capture_hw_free(struct snd_pcm_substream *substream) +{ + return snd_pcm_lib_free_pages(substream); +} + +static int snd_wss_capture_prepare(struct snd_pcm_substream *substream) +{ + struct snd_wss *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + unsigned long flags; + unsigned int size = snd_pcm_lib_buffer_bytes(substream); + unsigned int count = snd_pcm_lib_period_bytes(substream); + + spin_lock_irqsave(&chip->reg_lock, flags); + chip->c_dma_size = size; + chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_RECORD_ENABLE | CS4231_RECORD_PIO); + snd_dma_program(chip->dma2, runtime->dma_addr, size, DMA_MODE_READ | DMA_AUTOINIT); + if (chip->hardware & WSS_HW_AD1848_MASK) + count = snd_wss_get_count(chip->image[CS4231_PLAYBK_FORMAT], + count); + else + count = snd_wss_get_count(chip->image[CS4231_REC_FORMAT], + count); + count--; + if (chip->single_dma && chip->hardware != WSS_HW_INTERWAVE) { + snd_wss_out(chip, CS4231_PLY_LWR_CNT, (unsigned char) count); + snd_wss_out(chip, CS4231_PLY_UPR_CNT, + (unsigned char) (count >> 8)); + } else { + snd_wss_out(chip, CS4231_REC_LWR_CNT, (unsigned char) count); + snd_wss_out(chip, CS4231_REC_UPR_CNT, + (unsigned char) (count >> 8)); + } + spin_unlock_irqrestore(&chip->reg_lock, flags); + return 0; +} + +void snd_wss_overrange(struct snd_wss *chip) +{ + unsigned long flags; + unsigned char res; + + spin_lock_irqsave(&chip->reg_lock, flags); + res = snd_wss_in(chip, CS4231_TEST_INIT); + spin_unlock_irqrestore(&chip->reg_lock, flags); + if (res & (0x08 | 0x02)) /* detect overrange only above 0dB; may be user selectable? */ + chip->capture_substream->runtime->overrange++; +} +EXPORT_SYMBOL(snd_wss_overrange); + +irqreturn_t snd_wss_interrupt(int irq, void *dev_id) +{ + struct snd_wss *chip = dev_id; + unsigned char status; + + if (chip->hardware & WSS_HW_AD1848_MASK) + /* pretend it was the only possible irq for AD1848 */ + status = CS4231_PLAYBACK_IRQ; + else + status = snd_wss_in(chip, CS4231_IRQ_STATUS); + if (status & CS4231_TIMER_IRQ) { + if (chip->timer) + snd_timer_interrupt(chip->timer, chip->timer->sticks); + } + if (chip->single_dma && chip->hardware != WSS_HW_INTERWAVE) { + if (status & CS4231_PLAYBACK_IRQ) { + if (chip->mode & WSS_MODE_PLAY) { + if (chip->playback_substream) + snd_pcm_period_elapsed(chip->playback_substream); + } + if (chip->mode & WSS_MODE_RECORD) { + if (chip->capture_substream) { + snd_wss_overrange(chip); + snd_pcm_period_elapsed(chip->capture_substream); + } + } + } + } else { + if (status & CS4231_PLAYBACK_IRQ) { + if (chip->playback_substream) + snd_pcm_period_elapsed(chip->playback_substream); + } + if (status & CS4231_RECORD_IRQ) { + if (chip->capture_substream) { + snd_wss_overrange(chip); + snd_pcm_period_elapsed(chip->capture_substream); + } + } + } + + spin_lock(&chip->reg_lock); + status = ~CS4231_ALL_IRQS | ~status; + if (chip->hardware & WSS_HW_AD1848_MASK) + wss_outb(chip, CS4231P(STATUS), 0); + else + snd_wss_outm(chip, CS4231_IRQ_STATUS, status, 0); + spin_unlock(&chip->reg_lock); + return IRQ_HANDLED; +} +EXPORT_SYMBOL(snd_wss_interrupt); + +static snd_pcm_uframes_t snd_wss_playback_pointer(struct snd_pcm_substream *substream) +{ + struct snd_wss *chip = snd_pcm_substream_chip(substream); + size_t ptr; + + if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE)) + return 0; + ptr = snd_dma_pointer(chip->dma1, chip->p_dma_size); + return bytes_to_frames(substream->runtime, ptr); +} + +static snd_pcm_uframes_t snd_wss_capture_pointer(struct snd_pcm_substream *substream) +{ + struct snd_wss *chip = snd_pcm_substream_chip(substream); + size_t ptr; + + if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE)) + return 0; + ptr = snd_dma_pointer(chip->dma2, chip->c_dma_size); + return bytes_to_frames(substream->runtime, ptr); +} + +/* + + */ + +static int snd_ad1848_probe(struct snd_wss *chip) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(1000); + unsigned long flags; + unsigned char r; + unsigned short hardware = 0; + int err = 0; + int i; + + while (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) { + if (time_after(jiffies, timeout)) + return -ENODEV; + cond_resched(); + } + spin_lock_irqsave(&chip->reg_lock, flags); + + /* set CS423x MODE 1 */ + snd_wss_dout(chip, CS4231_MISC_INFO, 0); + + snd_wss_dout(chip, CS4231_RIGHT_INPUT, 0x45); /* 0x55 & ~0x10 */ + r = snd_wss_in(chip, CS4231_RIGHT_INPUT); + if (r != 0x45) { + /* RMGE always high on AD1847 */ + if ((r & ~CS4231_ENABLE_MIC_GAIN) != 0x45) { + err = -ENODEV; + goto out; + } + hardware = WSS_HW_AD1847; + } else { + snd_wss_dout(chip, CS4231_LEFT_INPUT, 0xaa); + r = snd_wss_in(chip, CS4231_LEFT_INPUT); + /* L/RMGE always low on AT2320 */ + if ((r | CS4231_ENABLE_MIC_GAIN) != 0xaa) { + err = -ENODEV; + goto out; + } + } + + /* clear pending IRQ */ + wss_inb(chip, CS4231P(STATUS)); + wss_outb(chip, CS4231P(STATUS), 0); + mb(); + + if ((chip->hardware & WSS_HW_TYPE_MASK) != WSS_HW_DETECT) + goto out; + + if (hardware) { + chip->hardware = hardware; + goto out; + } + + r = snd_wss_in(chip, CS4231_MISC_INFO); + + /* set CS423x MODE 2 */ + snd_wss_dout(chip, CS4231_MISC_INFO, CS4231_MODE2); + for (i = 0; i < 16; i++) { + if (snd_wss_in(chip, i) != snd_wss_in(chip, 16 + i)) { + /* we have more than 16 registers: check ID */ + if ((r & 0xf) != 0xa) + goto out_mode; + /* + * on CMI8330, CS4231_VERSION is volume control and + * can be set to 0 + */ + snd_wss_dout(chip, CS4231_VERSION, 0); + r = snd_wss_in(chip, CS4231_VERSION) & 0xe7; + if (!r) + chip->hardware = WSS_HW_CMI8330; + goto out_mode; + } + } + if (r & 0x80) + chip->hardware = WSS_HW_CS4248; + else + chip->hardware = WSS_HW_AD1848; +out_mode: + snd_wss_dout(chip, CS4231_MISC_INFO, 0); +out: + spin_unlock_irqrestore(&chip->reg_lock, flags); + return err; +} + +static int snd_wss_probe(struct snd_wss *chip) +{ + unsigned long flags; + int i, id, rev, regnum; + unsigned char *ptr; + unsigned int hw; + + id = snd_ad1848_probe(chip); + if (id < 0) + return id; + + hw = chip->hardware; + if ((hw & WSS_HW_TYPE_MASK) == WSS_HW_DETECT) { + for (i = 0; i < 50; i++) { + mb(); + if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) + msleep(2); + else { + spin_lock_irqsave(&chip->reg_lock, flags); + snd_wss_out(chip, CS4231_MISC_INFO, + CS4231_MODE2); + id = snd_wss_in(chip, CS4231_MISC_INFO) & 0x0f; + spin_unlock_irqrestore(&chip->reg_lock, flags); + if (id == 0x0a) + break; /* this is valid value */ + } + } + snd_printdd("wss: port = 0x%lx, id = 0x%x\n", chip->port, id); + if (id != 0x0a) + return -ENODEV; /* no valid device found */ + + rev = snd_wss_in(chip, CS4231_VERSION) & 0xe7; + snd_printdd("CS4231: VERSION (I25) = 0x%x\n", rev); + if (rev == 0x80) { + unsigned char tmp = snd_wss_in(chip, 23); + snd_wss_out(chip, 23, ~tmp); + if (snd_wss_in(chip, 23) != tmp) + chip->hardware = WSS_HW_AD1845; + else + chip->hardware = WSS_HW_CS4231; + } else if (rev == 0xa0) { + chip->hardware = WSS_HW_CS4231A; + } else if (rev == 0xa2) { + chip->hardware = WSS_HW_CS4232; + } else if (rev == 0xb2) { + chip->hardware = WSS_HW_CS4232A; + } else if (rev == 0x83) { + chip->hardware = WSS_HW_CS4236; + } else if (rev == 0x03) { + chip->hardware = WSS_HW_CS4236B; + } else { + snd_printk("unknown CS chip with version 0x%x\n", rev); + return -ENODEV; /* unknown CS4231 chip? */ + } + } + spin_lock_irqsave(&chip->reg_lock, flags); + wss_inb(chip, CS4231P(STATUS)); /* clear any pendings IRQ */ + wss_outb(chip, CS4231P(STATUS), 0); + mb(); + spin_unlock_irqrestore(&chip->reg_lock, flags); + + if (!(chip->hardware & WSS_HW_AD1848_MASK)) + chip->image[CS4231_MISC_INFO] = CS4231_MODE2; + switch (chip->hardware) { + case WSS_HW_INTERWAVE: + chip->image[CS4231_MISC_INFO] = CS4231_IW_MODE3; + break; + case WSS_HW_CS4235: + case WSS_HW_CS4236B: + case WSS_HW_CS4237B: + case WSS_HW_CS4238B: + case WSS_HW_CS4239: + if (hw == WSS_HW_DETECT3) + chip->image[CS4231_MISC_INFO] = CS4231_4236_MODE3; + else + chip->hardware = WSS_HW_CS4236; + break; + } + + chip->image[CS4231_IFACE_CTRL] = + (chip->image[CS4231_IFACE_CTRL] & ~CS4231_SINGLE_DMA) | + (chip->single_dma ? CS4231_SINGLE_DMA : 0); + if (chip->hardware != WSS_HW_OPTI93X) { + chip->image[CS4231_ALT_FEATURE_1] = 0x80; + chip->image[CS4231_ALT_FEATURE_2] = + chip->hardware == WSS_HW_INTERWAVE ? 0xc2 : 0x01; + } + ptr = (unsigned char *) &chip->image; + regnum = (chip->hardware & WSS_HW_AD1848_MASK) ? 16 : 32; + snd_wss_mce_down(chip); + spin_lock_irqsave(&chip->reg_lock, flags); + for (i = 0; i < regnum; i++) /* ok.. fill all registers */ + snd_wss_out(chip, i, *ptr++); + spin_unlock_irqrestore(&chip->reg_lock, flags); + snd_wss_mce_up(chip); + snd_wss_mce_down(chip); + + mdelay(2); + + /* ok.. try check hardware version for CS4236+ chips */ + if ((hw & WSS_HW_TYPE_MASK) == WSS_HW_DETECT) { + if (chip->hardware == WSS_HW_CS4236B) { + rev = snd_cs4236_ext_in(chip, CS4236_VERSION); + snd_cs4236_ext_out(chip, CS4236_VERSION, 0xff); + id = snd_cs4236_ext_in(chip, CS4236_VERSION); + snd_cs4236_ext_out(chip, CS4236_VERSION, rev); + snd_printdd("CS4231: ext version; rev = 0x%x, id = 0x%x\n", rev, id); + if ((id & 0x1f) == 0x1d) { /* CS4235 */ + chip->hardware = WSS_HW_CS4235; + switch (id >> 5) { + case 4: + case 5: + case 6: + break; + default: + snd_printk("unknown CS4235 chip (enhanced version = 0x%x)\n", id); + } + } else if ((id & 0x1f) == 0x0b) { /* CS4236/B */ + switch (id >> 5) { + case 4: + case 5: + case 6: + case 7: + chip->hardware = WSS_HW_CS4236B; + break; + default: + snd_printk("unknown CS4236 chip (enhanced version = 0x%x)\n", id); + } + } else if ((id & 0x1f) == 0x08) { /* CS4237B */ + chip->hardware = WSS_HW_CS4237B; + switch (id >> 5) { + case 4: + case 5: + case 6: + case 7: + break; + default: + snd_printk("unknown CS4237B chip (enhanced version = 0x%x)\n", id); + } + } else if ((id & 0x1f) == 0x09) { /* CS4238B */ + chip->hardware = WSS_HW_CS4238B; + switch (id >> 5) { + case 5: + case 6: + case 7: + break; + default: + snd_printk("unknown CS4238B chip (enhanced version = 0x%x)\n", id); + } + } else if ((id & 0x1f) == 0x1e) { /* CS4239 */ + chip->hardware = WSS_HW_CS4239; + switch (id >> 5) { + case 4: + case 5: + case 6: + break; + default: + snd_printk("unknown CS4239 chip (enhanced version = 0x%x)\n", id); + } + } else { + snd_printk("unknown CS4236/CS423xB chip (enhanced version = 0x%x)\n", id); + } + } + } + return 0; /* all things are ok.. */ +} + +/* + + */ + +static struct snd_pcm_hardware snd_wss_playback = +{ + .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_RESUME | + SNDRV_PCM_INFO_SYNC_START), + .formats = (SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | SNDRV_PCM_FMTBIT_IMA_ADPCM | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE), + .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000, + .rate_min = 5510, + .rate_max = 48000, + .channels_min = 1, + .channels_max = 2, + .buffer_bytes_max = (128*1024), + .period_bytes_min = 64, + .period_bytes_max = (128*1024), + .periods_min = 1, + .periods_max = 1024, + .fifo_size = 0, +}; + +static struct snd_pcm_hardware snd_wss_capture = +{ + .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_RESUME | + SNDRV_PCM_INFO_SYNC_START), + .formats = (SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | SNDRV_PCM_FMTBIT_IMA_ADPCM | + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE), + .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000, + .rate_min = 5510, + .rate_max = 48000, + .channels_min = 1, + .channels_max = 2, + .buffer_bytes_max = (128*1024), + .period_bytes_min = 64, + .period_bytes_max = (128*1024), + .periods_min = 1, + .periods_max = 1024, + .fifo_size = 0, +}; + +/* + + */ + +static int snd_wss_playback_open(struct snd_pcm_substream *substream) +{ + struct snd_wss *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + int err; + + runtime->hw = snd_wss_playback; + + /* hardware limitation of older chipsets */ + if (chip->hardware & WSS_HW_AD1848_MASK) + runtime->hw.formats &= ~(SNDRV_PCM_FMTBIT_IMA_ADPCM | + SNDRV_PCM_FMTBIT_S16_BE); + + /* hardware bug in InterWave chipset */ + if (chip->hardware == WSS_HW_INTERWAVE && chip->dma1 > 3) + runtime->hw.formats &= ~SNDRV_PCM_FMTBIT_MU_LAW; + + /* hardware limitation of cheap chips */ + if (chip->hardware == WSS_HW_CS4235 || + chip->hardware == WSS_HW_CS4239) + runtime->hw.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE; + + snd_pcm_limit_isa_dma_size(chip->dma1, &runtime->hw.buffer_bytes_max); + snd_pcm_limit_isa_dma_size(chip->dma1, &runtime->hw.period_bytes_max); + + if (chip->claim_dma) { + if ((err = chip->claim_dma(chip, chip->dma_private_data, chip->dma1)) < 0) + return err; + } + + err = snd_wss_open(chip, WSS_MODE_PLAY); + if (err < 0) { + if (chip->release_dma) + chip->release_dma(chip, chip->dma_private_data, chip->dma1); + snd_free_pages(runtime->dma_area, runtime->dma_bytes); + return err; + } + chip->playback_substream = substream; + snd_pcm_set_sync(substream); + chip->rate_constraint(runtime); + return 0; +} + +static int snd_wss_capture_open(struct snd_pcm_substream *substream) +{ + struct snd_wss *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + int err; + + runtime->hw = snd_wss_capture; + + /* hardware limitation of older chipsets */ + if (chip->hardware & WSS_HW_AD1848_MASK) + runtime->hw.formats &= ~(SNDRV_PCM_FMTBIT_IMA_ADPCM | + SNDRV_PCM_FMTBIT_S16_BE); + + /* hardware limitation of cheap chips */ + if (chip->hardware == WSS_HW_CS4235 || + chip->hardware == WSS_HW_CS4239 || + chip->hardware == WSS_HW_OPTI93X) + runtime->hw.formats = SNDRV_PCM_FMTBIT_U8 | + SNDRV_PCM_FMTBIT_S16_LE; + + snd_pcm_limit_isa_dma_size(chip->dma2, &runtime->hw.buffer_bytes_max); + snd_pcm_limit_isa_dma_size(chip->dma2, &runtime->hw.period_bytes_max); + + if (chip->claim_dma) { + if ((err = chip->claim_dma(chip, chip->dma_private_data, chip->dma2)) < 0) + return err; + } + + err = snd_wss_open(chip, WSS_MODE_RECORD); + if (err < 0) { + if (chip->release_dma) + chip->release_dma(chip, chip->dma_private_data, chip->dma2); + snd_free_pages(runtime->dma_area, runtime->dma_bytes); + return err; + } + chip->capture_substream = substream; + snd_pcm_set_sync(substream); + chip->rate_constraint(runtime); + return 0; +} + +static int snd_wss_playback_close(struct snd_pcm_substream *substream) +{ + struct snd_wss *chip = snd_pcm_substream_chip(substream); + + chip->playback_substream = NULL; + snd_wss_close(chip, WSS_MODE_PLAY); + return 0; +} + +static int snd_wss_capture_close(struct snd_pcm_substream *substream) +{ + struct snd_wss *chip = snd_pcm_substream_chip(substream); + + chip->capture_substream = NULL; + snd_wss_close(chip, WSS_MODE_RECORD); + return 0; +} + +static void snd_wss_thinkpad_twiddle(struct snd_wss *chip, int on) +{ + int tmp; + + if (!chip->thinkpad_flag) + return; + + outb(0x1c, AD1848_THINKPAD_CTL_PORT1); + tmp = inb(AD1848_THINKPAD_CTL_PORT2); + + if (on) + /* turn it on */ + tmp |= AD1848_THINKPAD_CS4248_ENABLE_BIT; + else + /* turn it off */ + tmp &= ~AD1848_THINKPAD_CS4248_ENABLE_BIT; + + outb(tmp, AD1848_THINKPAD_CTL_PORT2); +} + +#ifdef CONFIG_PM + +/* lowlevel suspend callback for CS4231 */ +static void snd_wss_suspend(struct snd_wss *chip) +{ + int reg; + unsigned long flags; + + snd_pcm_suspend_all(chip->pcm); + spin_lock_irqsave(&chip->reg_lock, flags); + for (reg = 0; reg < 32; reg++) + chip->image[reg] = snd_wss_in(chip, reg); + spin_unlock_irqrestore(&chip->reg_lock, flags); + if (chip->thinkpad_flag) + snd_wss_thinkpad_twiddle(chip, 0); +} + +/* lowlevel resume callback for CS4231 */ +static void snd_wss_resume(struct snd_wss *chip) +{ + int reg; + unsigned long flags; + /* int timeout; */ + + if (chip->thinkpad_flag) + snd_wss_thinkpad_twiddle(chip, 1); + snd_wss_mce_up(chip); + spin_lock_irqsave(&chip->reg_lock, flags); + for (reg = 0; reg < 32; reg++) { + switch (reg) { + case CS4231_VERSION: + break; + default: + snd_wss_out(chip, reg, chip->image[reg]); + break; + } + } + spin_unlock_irqrestore(&chip->reg_lock, flags); +#if 1 + snd_wss_mce_down(chip); +#else + /* The following is a workaround to avoid freeze after resume on TP600E. + This is the first half of copy of snd_wss_mce_down(), but doesn't + include rescheduling. -- iwai + */ + snd_wss_busy_wait(chip); + spin_lock_irqsave(&chip->reg_lock, flags); + chip->mce_bit &= ~CS4231_MCE; + timeout = wss_inb(chip, CS4231P(REGSEL)); + wss_outb(chip, CS4231P(REGSEL), chip->mce_bit | (timeout & 0x1f)); + spin_unlock_irqrestore(&chip->reg_lock, flags); + if (timeout == 0x80) + snd_printk("down [0x%lx]: serious init problem - codec still busy\n", chip->port); + if ((timeout & CS4231_MCE) == 0 || + !(chip->hardware & (WSS_HW_CS4231_MASK | WSS_HW_CS4232_MASK))) { + return; + } + snd_wss_busy_wait(chip); +#endif +} +#endif /* CONFIG_PM */ + +static int snd_wss_free(struct snd_wss *chip) +{ + release_and_free_resource(chip->res_port); + release_and_free_resource(chip->res_cport); + if (chip->irq >= 0) { + disable_irq(chip->irq); + if (!(chip->hwshare & WSS_HWSHARE_IRQ)) + free_irq(chip->irq, (void *) chip); + } + if (!(chip->hwshare & WSS_HWSHARE_DMA1) && chip->dma1 >= 0) { + snd_dma_disable(chip->dma1); + free_dma(chip->dma1); + } + if (!(chip->hwshare & WSS_HWSHARE_DMA2) && + chip->dma2 >= 0 && chip->dma2 != chip->dma1) { + snd_dma_disable(chip->dma2); + free_dma(chip->dma2); + } + if (chip->timer) + snd_device_free(chip->card, chip->timer); + kfree(chip); + return 0; +} + +static int snd_wss_dev_free(struct snd_device *device) +{ + struct snd_wss *chip = device->device_data; + return snd_wss_free(chip); +} + +const char *snd_wss_chip_id(struct snd_wss *chip) +{ + switch (chip->hardware) { + case WSS_HW_CS4231: + return "CS4231"; + case WSS_HW_CS4231A: + return "CS4231A"; + case WSS_HW_CS4232: + return "CS4232"; + case WSS_HW_CS4232A: + return "CS4232A"; + case WSS_HW_CS4235: + return "CS4235"; + case WSS_HW_CS4236: + return "CS4236"; + case WSS_HW_CS4236B: + return "CS4236B"; + case WSS_HW_CS4237B: + return "CS4237B"; + case WSS_HW_CS4238B: + return "CS4238B"; + case WSS_HW_CS4239: + return "CS4239"; + case WSS_HW_INTERWAVE: + return "AMD InterWave"; + case WSS_HW_OPL3SA2: + return chip->card->shortname; + case WSS_HW_AD1845: + return "AD1845"; + case WSS_HW_OPTI93X: + return "OPTi 93x"; + case WSS_HW_AD1847: + return "AD1847"; + case WSS_HW_AD1848: + return "AD1848"; + case WSS_HW_CS4248: + return "CS4248"; + case WSS_HW_CMI8330: + return "CMI8330/C3D"; + default: + return "???"; + } +} +EXPORT_SYMBOL(snd_wss_chip_id); + +static int snd_wss_new(struct snd_card *card, + unsigned short hardware, + unsigned short hwshare, + struct snd_wss **rchip) +{ + struct snd_wss *chip; + + *rchip = NULL; + chip = kzalloc(sizeof(*chip), GFP_KERNEL); + if (chip == NULL) + return -ENOMEM; + chip->hardware = hardware; + chip->hwshare = hwshare; + + spin_lock_init(&chip->reg_lock); + mutex_init(&chip->mce_mutex); + mutex_init(&chip->open_mutex); + chip->card = card; + chip->rate_constraint = snd_wss_xrate; + chip->set_playback_format = snd_wss_playback_format; + chip->set_capture_format = snd_wss_capture_format; + if (chip->hardware == WSS_HW_OPTI93X) + memcpy(&chip->image, &snd_opti93x_original_image, + sizeof(snd_opti93x_original_image)); + else + memcpy(&chip->image, &snd_wss_original_image, + sizeof(snd_wss_original_image)); + if (chip->hardware & WSS_HW_AD1848_MASK) { + chip->image[CS4231_PIN_CTRL] = 0; + chip->image[CS4231_TEST_INIT] = 0; + } + + *rchip = chip; + return 0; +} + +int snd_wss_create(struct snd_card *card, + unsigned long port, + unsigned long cport, + int irq, int dma1, int dma2, + unsigned short hardware, + unsigned short hwshare, + struct snd_wss **rchip) +{ + static struct snd_device_ops ops = { + .dev_free = snd_wss_dev_free, + }; + struct snd_wss *chip; + int err; + + err = snd_wss_new(card, hardware, hwshare, &chip); + if (err < 0) + return err; + + chip->irq = -1; + chip->dma1 = -1; + chip->dma2 = -1; + + chip->res_port = request_region(port, 4, "WSS"); + if (!chip->res_port) { + snd_printk(KERN_ERR "wss: can't grab port 0x%lx\n", port); + snd_wss_free(chip); + return -EBUSY; + } + chip->port = port; + if ((long)cport >= 0) { + chip->res_cport = request_region(cport, 8, "CS4232 Control"); + if (!chip->res_cport) { + snd_printk(KERN_ERR + "wss: can't grab control port 0x%lx\n", cport); + snd_wss_free(chip); + return -ENODEV; + } + } + chip->cport = cport; + if (!(hwshare & WSS_HWSHARE_IRQ)) + if (request_irq(irq, snd_wss_interrupt, IRQF_DISABLED, + "WSS", (void *) chip)) { + snd_printk(KERN_ERR "wss: can't grab IRQ %d\n", irq); + snd_wss_free(chip); + return -EBUSY; + } + chip->irq = irq; + if (!(hwshare & WSS_HWSHARE_DMA1) && request_dma(dma1, "WSS - 1")) { + snd_printk(KERN_ERR "wss: can't grab DMA1 %d\n", dma1); + snd_wss_free(chip); + return -EBUSY; + } + chip->dma1 = dma1; + if (!(hwshare & WSS_HWSHARE_DMA2) && dma1 != dma2 && + dma2 >= 0 && request_dma(dma2, "WSS - 2")) { + snd_printk(KERN_ERR "wss: can't grab DMA2 %d\n", dma2); + snd_wss_free(chip); + return -EBUSY; + } + if (dma1 == dma2 || dma2 < 0) { + chip->single_dma = 1; + chip->dma2 = chip->dma1; + } else + chip->dma2 = dma2; + + if (hardware == WSS_HW_THINKPAD) { + chip->thinkpad_flag = 1; + chip->hardware = WSS_HW_DETECT; /* reset */ + snd_wss_thinkpad_twiddle(chip, 1); + } + + /* global setup */ + if (snd_wss_probe(chip) < 0) { + snd_wss_free(chip); + return -ENODEV; + } + snd_wss_init(chip); + +#if 0 + if (chip->hardware & WSS_HW_CS4232_MASK) { + if (chip->res_cport == NULL) + snd_printk("CS4232 control port features are not accessible\n"); + } +#endif + + /* Register device */ + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); + if (err < 0) { + snd_wss_free(chip); + return err; + } + +#ifdef CONFIG_PM + /* Power Management */ + chip->suspend = snd_wss_suspend; + chip->resume = snd_wss_resume; +#endif + + *rchip = chip; + return 0; +} +EXPORT_SYMBOL(snd_wss_create); + +static struct snd_pcm_ops snd_wss_playback_ops = { + .open = snd_wss_playback_open, + .close = snd_wss_playback_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_wss_playback_hw_params, + .hw_free = snd_wss_playback_hw_free, + .prepare = snd_wss_playback_prepare, + .trigger = snd_wss_trigger, + .pointer = snd_wss_playback_pointer, +}; + +static struct snd_pcm_ops snd_wss_capture_ops = { + .open = snd_wss_capture_open, + .close = snd_wss_capture_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_wss_capture_hw_params, + .hw_free = snd_wss_capture_hw_free, + .prepare = snd_wss_capture_prepare, + .trigger = snd_wss_trigger, + .pointer = snd_wss_capture_pointer, +}; + +int snd_wss_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm) +{ + struct snd_pcm *pcm; + int err; + + err = snd_pcm_new(chip->card, "WSS", device, 1, 1, &pcm); + if (err < 0) + return err; + + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_wss_playback_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_wss_capture_ops); + + /* global setup */ + pcm->private_data = chip; + pcm->info_flags = 0; + if (chip->single_dma) + pcm->info_flags |= SNDRV_PCM_INFO_HALF_DUPLEX; + if (chip->hardware != WSS_HW_INTERWAVE) + pcm->info_flags |= SNDRV_PCM_INFO_JOINT_DUPLEX; + strcpy(pcm->name, snd_wss_chip_id(chip)); + + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_isa_data(), + 64*1024, chip->dma1 > 3 || chip->dma2 > 3 ? 128*1024 : 64*1024); + + chip->pcm = pcm; + if (rpcm) + *rpcm = pcm; + return 0; +} +EXPORT_SYMBOL(snd_wss_pcm); + +static void snd_wss_timer_free(struct snd_timer *timer) +{ + struct snd_wss *chip = timer->private_data; + chip->timer = NULL; +} + +int snd_wss_timer(struct snd_wss *chip, int device, struct snd_timer **rtimer) +{ + struct snd_timer *timer; + struct snd_timer_id tid; + int err; + + /* Timer initialization */ + tid.dev_class = SNDRV_TIMER_CLASS_CARD; + tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE; + tid.card = chip->card->number; + tid.device = device; + tid.subdevice = 0; + if ((err = snd_timer_new(chip->card, "CS4231", &tid, &timer)) < 0) + return err; + strcpy(timer->name, snd_wss_chip_id(chip)); + timer->private_data = chip; + timer->private_free = snd_wss_timer_free; + timer->hw = snd_wss_timer_table; + chip->timer = timer; + if (rtimer) + *rtimer = timer; + return 0; +} +EXPORT_SYMBOL(snd_wss_timer); + +/* + * MIXER part + */ + +static int snd_wss_info_mux(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + static char *texts[4] = { + "Line", "Aux", "Mic", "Mix" + }; + static char *opl3sa_texts[4] = { + "Line", "CD", "Mic", "Mix" + }; + static char *gusmax_texts[4] = { + "Line", "Synth", "Mic", "Mix" + }; + char **ptexts = texts; + struct snd_wss *chip = snd_kcontrol_chip(kcontrol); + + if (snd_BUG_ON(!chip->card)) + return -EINVAL; + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 2; + uinfo->value.enumerated.items = 4; + if (uinfo->value.enumerated.item > 3) + uinfo->value.enumerated.item = 3; + if (!strcmp(chip->card->driver, "GUS MAX")) + ptexts = gusmax_texts; + switch (chip->hardware) { + case WSS_HW_INTERWAVE: + ptexts = gusmax_texts; + break; + case WSS_HW_OPL3SA2: + ptexts = opl3sa_texts; + break; + } + strcpy(uinfo->value.enumerated.name, ptexts[uinfo->value.enumerated.item]); + return 0; +} + +static int snd_wss_get_mux(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_wss *chip = snd_kcontrol_chip(kcontrol); + unsigned long flags; + + spin_lock_irqsave(&chip->reg_lock, flags); + ucontrol->value.enumerated.item[0] = (chip->image[CS4231_LEFT_INPUT] & CS4231_MIXS_ALL) >> 6; + ucontrol->value.enumerated.item[1] = (chip->image[CS4231_RIGHT_INPUT] & CS4231_MIXS_ALL) >> 6; + spin_unlock_irqrestore(&chip->reg_lock, flags); + return 0; +} + +static int snd_wss_put_mux(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_wss *chip = snd_kcontrol_chip(kcontrol); + unsigned long flags; + unsigned short left, right; + int change; + + if (ucontrol->value.enumerated.item[0] > 3 || + ucontrol->value.enumerated.item[1] > 3) + return -EINVAL; + left = ucontrol->value.enumerated.item[0] << 6; + right = ucontrol->value.enumerated.item[1] << 6; + spin_lock_irqsave(&chip->reg_lock, flags); + left = (chip->image[CS4231_LEFT_INPUT] & ~CS4231_MIXS_ALL) | left; + right = (chip->image[CS4231_RIGHT_INPUT] & ~CS4231_MIXS_ALL) | right; + change = left != chip->image[CS4231_LEFT_INPUT] || + right != chip->image[CS4231_RIGHT_INPUT]; + snd_wss_out(chip, CS4231_LEFT_INPUT, left); + snd_wss_out(chip, CS4231_RIGHT_INPUT, right); + spin_unlock_irqrestore(&chip->reg_lock, flags); + return change; +} + +int snd_wss_info_single(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + int mask = (kcontrol->private_value >> 16) & 0xff; + + uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = mask; + return 0; +} +EXPORT_SYMBOL(snd_wss_info_single); + +int snd_wss_get_single(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_wss *chip = snd_kcontrol_chip(kcontrol); + unsigned long flags; + int reg = kcontrol->private_value & 0xff; + int shift = (kcontrol->private_value >> 8) & 0xff; + int mask = (kcontrol->private_value >> 16) & 0xff; + int invert = (kcontrol->private_value >> 24) & 0xff; + + spin_lock_irqsave(&chip->reg_lock, flags); + ucontrol->value.integer.value[0] = (chip->image[reg] >> shift) & mask; + spin_unlock_irqrestore(&chip->reg_lock, flags); + if (invert) + ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; + return 0; +} +EXPORT_SYMBOL(snd_wss_get_single); + +int snd_wss_put_single(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_wss *chip = snd_kcontrol_chip(kcontrol); + unsigned long flags; + int reg = kcontrol->private_value & 0xff; + int shift = (kcontrol->private_value >> 8) & 0xff; + int mask = (kcontrol->private_value >> 16) & 0xff; + int invert = (kcontrol->private_value >> 24) & 0xff; + int change; + unsigned short val; + + val = (ucontrol->value.integer.value[0] & mask); + if (invert) + val = mask - val; + val <<= shift; + spin_lock_irqsave(&chip->reg_lock, flags); + val = (chip->image[reg] & ~(mask << shift)) | val; + change = val != chip->image[reg]; + snd_wss_out(chip, reg, val); + spin_unlock_irqrestore(&chip->reg_lock, flags); + return change; +} +EXPORT_SYMBOL(snd_wss_put_single); + +int snd_wss_info_double(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + int mask = (kcontrol->private_value >> 24) & 0xff; + + uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = mask; + return 0; +} +EXPORT_SYMBOL(snd_wss_info_double); + +int snd_wss_get_double(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_wss *chip = snd_kcontrol_chip(kcontrol); + unsigned long flags; + int left_reg = kcontrol->private_value & 0xff; + int right_reg = (kcontrol->private_value >> 8) & 0xff; + int shift_left = (kcontrol->private_value >> 16) & 0x07; + int shift_right = (kcontrol->private_value >> 19) & 0x07; + int mask = (kcontrol->private_value >> 24) & 0xff; + int invert = (kcontrol->private_value >> 22) & 1; + + spin_lock_irqsave(&chip->reg_lock, flags); + ucontrol->value.integer.value[0] = (chip->image[left_reg] >> shift_left) & mask; + ucontrol->value.integer.value[1] = (chip->image[right_reg] >> shift_right) & mask; + spin_unlock_irqrestore(&chip->reg_lock, flags); + if (invert) { + ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; + ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1]; + } + return 0; +} +EXPORT_SYMBOL(snd_wss_get_double); + +int snd_wss_put_double(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_wss *chip = snd_kcontrol_chip(kcontrol); + unsigned long flags; + int left_reg = kcontrol->private_value & 0xff; + int right_reg = (kcontrol->private_value >> 8) & 0xff; + int shift_left = (kcontrol->private_value >> 16) & 0x07; + int shift_right = (kcontrol->private_value >> 19) & 0x07; + int mask = (kcontrol->private_value >> 24) & 0xff; + int invert = (kcontrol->private_value >> 22) & 1; + int change; + unsigned short val1, val2; + + val1 = ucontrol->value.integer.value[0] & mask; + val2 = ucontrol->value.integer.value[1] & mask; + if (invert) { + val1 = mask - val1; + val2 = mask - val2; + } + val1 <<= shift_left; + val2 <<= shift_right; + spin_lock_irqsave(&chip->reg_lock, flags); + if (left_reg != right_reg) { + val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1; + val2 = (chip->image[right_reg] & ~(mask << shift_right)) | val2; + change = val1 != chip->image[left_reg] || + val2 != chip->image[right_reg]; + snd_wss_out(chip, left_reg, val1); + snd_wss_out(chip, right_reg, val2); + } else { + mask = (mask << shift_left) | (mask << shift_right); + val1 = (chip->image[left_reg] & ~mask) | val1 | val2; + change = val1 != chip->image[left_reg]; + snd_wss_out(chip, left_reg, val1); + } + spin_unlock_irqrestore(&chip->reg_lock, flags); + return change; +} +EXPORT_SYMBOL(snd_wss_put_double); + +static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0); + +static struct snd_kcontrol_new snd_ad1848_controls[] = { +WSS_DOUBLE("PCM Playback Switch", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, + 7, 7, 1, 1), +WSS_DOUBLE_TLV("PCM Playback Volume", 0, + CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1, + db_scale_6bit), +WSS_DOUBLE("Aux Playback Switch", 0, + CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1), +WSS_DOUBLE_TLV("Aux Playback Volume", 0, + CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1, + db_scale_5bit_12db_max), +WSS_DOUBLE("Aux Playback Switch", 1, + CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1), +WSS_DOUBLE_TLV("Aux Playback Volume", 1, + CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1, + db_scale_5bit_12db_max), +WSS_DOUBLE_TLV("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, + 0, 0, 15, 0, db_scale_rec_gain), +{ + .name = "Capture Source", + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .info = snd_wss_info_mux, + .get = snd_wss_get_mux, + .put = snd_wss_put_mux, +}, +WSS_SINGLE("Loopback Capture Switch", 0, CS4231_LOOPBACK, 0, 1, 0), +WSS_SINGLE_TLV("Loopback Capture Volume", 0, CS4231_LOOPBACK, 1, 63, 0, + db_scale_6bit), +}; + +static struct snd_kcontrol_new snd_wss_controls[] = { +WSS_DOUBLE("PCM Playback Switch", 0, + CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1), +WSS_DOUBLE("PCM Playback Volume", 0, + CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1), +WSS_DOUBLE("Line Playback Switch", 0, + CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1), +WSS_DOUBLE("Line Playback Volume", 0, + CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1), +WSS_DOUBLE("Aux Playback Switch", 0, + CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1), +WSS_DOUBLE("Aux Playback Volume", 0, + CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1), +WSS_DOUBLE("Aux Playback Switch", 1, + CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1), +WSS_DOUBLE("Aux Playback Volume", 1, + CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1), +WSS_SINGLE("Mono Playback Switch", 0, + CS4231_MONO_CTRL, 7, 1, 1), +WSS_SINGLE("Mono Playback Volume", 0, + CS4231_MONO_CTRL, 0, 15, 1), +WSS_SINGLE("Mono Output Playback Switch", 0, + CS4231_MONO_CTRL, 6, 1, 1), +WSS_SINGLE("Mono Output Playback Bypass", 0, + CS4231_MONO_CTRL, 5, 1, 0), +WSS_DOUBLE("Capture Volume", 0, + CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0), +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Source", + .info = snd_wss_info_mux, + .get = snd_wss_get_mux, + .put = snd_wss_put_mux, +}, +WSS_DOUBLE("Mic Boost", 0, + CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 5, 5, 1, 0), +WSS_SINGLE("Loopback Capture Switch", 0, + CS4231_LOOPBACK, 0, 1, 0), +WSS_SINGLE("Loopback Capture Volume", 0, + CS4231_LOOPBACK, 2, 63, 1) +}; + +static struct snd_kcontrol_new snd_opti93x_controls[] = { +WSS_DOUBLE("Master Playback Switch", 0, + OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 7, 7, 1, 1), +WSS_DOUBLE("Master Playback Volume", 0, + OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 1, 1, 31, 1), +WSS_DOUBLE("PCM Playback Switch", 0, + CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1), +WSS_DOUBLE("PCM Playback Volume", 0, + CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 31, 1), +WSS_DOUBLE("FM Playback Switch", 0, + CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1), +WSS_DOUBLE("FM Playback Volume", 0, + CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 1, 1, 15, 1), +WSS_DOUBLE("Line Playback Switch", 0, + CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1), +WSS_DOUBLE("Line Playback Volume", 0, + CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 15, 1), +WSS_DOUBLE("Mic Playback Switch", 0, + OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 7, 7, 1, 1), +WSS_DOUBLE("Mic Playback Volume", 0, + OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 1, 1, 15, 1), +WSS_DOUBLE("Mic Boost", 0, + CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 5, 5, 1, 0), +WSS_DOUBLE("CD Playback Switch", 0, + CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1), +WSS_DOUBLE("CD Playback Volume", 0, + CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 1, 1, 15, 1), +WSS_DOUBLE("Aux Playback Switch", 0, + OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 7, 7, 1, 1), +WSS_DOUBLE("Aux Playback Volume", 0, + OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 1, 1, 15, 1), +WSS_DOUBLE("Capture Volume", 0, + CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0), +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Source", + .info = snd_wss_info_mux, + .get = snd_wss_get_mux, + .put = snd_wss_put_mux, +} +}; + +int snd_wss_mixer(struct snd_wss *chip) +{ + struct snd_card *card; + unsigned int idx; + int err; + + if (snd_BUG_ON(!chip || !chip->pcm)) + return -EINVAL; + + card = chip->card; + + strcpy(card->mixername, chip->pcm->name); + + if (chip->hardware == WSS_HW_OPTI93X) + for (idx = 0; idx < ARRAY_SIZE(snd_opti93x_controls); idx++) { + err = snd_ctl_add(card, + snd_ctl_new1(&snd_opti93x_controls[idx], + chip)); + if (err < 0) + return err; + } + else if (chip->hardware & WSS_HW_AD1848_MASK) + for (idx = 0; idx < ARRAY_SIZE(snd_ad1848_controls); idx++) { + err = snd_ctl_add(card, + snd_ctl_new1(&snd_ad1848_controls[idx], + chip)); + if (err < 0) + return err; + } + else + for (idx = 0; idx < ARRAY_SIZE(snd_wss_controls); idx++) { + err = snd_ctl_add(card, + snd_ctl_new1(&snd_wss_controls[idx], + chip)); + if (err < 0) + return err; + } + return 0; +} +EXPORT_SYMBOL(snd_wss_mixer); + +const struct snd_pcm_ops *snd_wss_get_pcm_ops(int direction) +{ + return direction == SNDRV_PCM_STREAM_PLAYBACK ? + &snd_wss_playback_ops : &snd_wss_capture_ops; +} +EXPORT_SYMBOL(snd_wss_get_pcm_ops); + +/* + * INIT part + */ + +static int __init alsa_wss_init(void) +{ + return 0; +} + +static void __exit alsa_wss_exit(void) +{ +} + +module_init(alsa_wss_init); +module_exit(alsa_wss_exit); |