diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-16 19:13:38 +0200 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-16 19:13:38 +0200 |
commit | fc8a327db6c46de783b1a4276d846841b9abc24c (patch) | |
tree | bee512c142cccea93511debd98ef954581693727 /sound/isa | |
parent | Merge branch 'for-linus' of git://git.kernel.dk/data/git/linux-2.6-block (diff) | |
parent | [ALSA] version 1.0.15 (diff) | |
download | linux-fc8a327db6c46de783b1a4276d846841b9abc24c.tar.xz linux-fc8a327db6c46de783b1a4276d846841b9abc24c.zip |
Merge branch 'linus' of master.kernel.org:/pub/scm/linux/kernel/git/perex/alsa
* 'linus' of master.kernel.org:/pub/scm/linux/kernel/git/perex/alsa: (264 commits)
[ALSA] version 1.0.15
[ALSA] Fix thinko in cs4231 mce down check
[ALSA] sun-cs4231: improved waiting after MCE down
[ALSA] sun-cs4231: use cs4231-regs.h
[ALSA] This simplifies and fixes waiting loops of the mce_down()
[ALSA] This patch adds support for a wavetable chip on
[ALSA] This patch removes open_mutex from the ad1848-lib as
[ALSA] fix bootup crash in snd_gus_interrupt()
[ALSA] hda-codec - Fix SKU ID function for realtek codecs
[ALSA] Support ASUS P701 eeepc [0x1043 0x82a1] support
[ALSA] hda-codec - Add array terminator for dmic in STAC codec
[ALSA] hdsp - Fix zero division
[ALSA] usb-audio - Fix double comment
[ALSA] hda-codec - Fix STAC922x volume knob control
[ALSA] Changed Jaroslav Kysela's e-mail from perex@suse.cz to perex@perex.cz
[ALSA] hda-codec - Fix for Fujitsu Lifebook C1410
[ALSA] mpu-401: remove MPU401_INFO_UART_ONLY flag
[ALSA] mpu-401: do not require an ACK byte for the ENTER_UART command
[ALSA] via82xx - Add DXS quirk for Shuttle AK31v2
[ALSA] hda-codec - Fix input_mux numbers for vaio stac92xx
...
Diffstat (limited to 'sound/isa')
58 files changed, 1189 insertions, 498 deletions
diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig index ea5084abe60f..2639a6ab8f2e 100644 --- a/sound/isa/Kconfig +++ b/sound/isa/Kconfig @@ -191,6 +191,19 @@ config SND_ES18XX To compile this driver as a module, choose M here: the module will be called snd-es18xx. +config SND_SC6000 + tristate "Gallant SC-6000, Audio Excel DSP 16" + depends on SND && HAS_IOPORT + select SND_AD1848_LIB + select SND_OPL3_LIB + select SND_MPU401_UART + help + Say Y here to include support for Gallant SC-6000 card and clones: + Audio Excel DSP 16 and Zoltrix AV302. + + To compile this driver as a module, choose M here: the module + will be called snd-sc6000. + config SND_GUS_SYNTH tristate @@ -414,7 +427,7 @@ config SND_SSCAPE config SND_WAVEFRONT tristate "Turtle Beach Maui,Tropez,Tropez+ (Wavefront)" depends on SND - select FW_LOADER if !SND_WAVEFRONT_FIRMWARE_IN_KERNEL + select FW_LOADER select SND_OPL3_LIB select SND_MPU401_UART select SND_CS4231_LIB @@ -430,8 +443,9 @@ config SND_WAVEFRONT_FIRMWARE_IN_KERNEL depends on SND_WAVEFRONT default y help - Say Y here to include the static firmware built in the kernel - for the Wavefront driver. If you choose N here, you need to - install the firmware files from the alsa-firmware package. + Say Y here to include the static firmware for FX DSP built in + the kernel for the Wavefront driver. If you choose N here, + you need to install the firmware files from the + alsa-firmware package. endmenu diff --git a/sound/isa/Makefile b/sound/isa/Makefile index bb317ccc170f..c0ce7db2a1b5 100644 --- a/sound/isa/Makefile +++ b/sound/isa/Makefile @@ -1,6 +1,6 @@ # # Makefile for ALSA -# Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz> +# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz> # snd-adlib-objs := adlib.o @@ -10,6 +10,7 @@ snd-cmi8330-objs := cmi8330.o snd-dt019x-objs := dt019x.o snd-es18xx-objs := es18xx.o snd-opl3sa2-objs := opl3sa2.o +snd-sc6000-objs := sc6000.o snd-sgalaxy-objs := sgalaxy.o snd-sscape-objs := sscape.o @@ -21,6 +22,7 @@ obj-$(CONFIG_SND_CMI8330) += snd-cmi8330.o obj-$(CONFIG_SND_DT019X) += snd-dt019x.o obj-$(CONFIG_SND_ES18XX) += snd-es18xx.o obj-$(CONFIG_SND_OPL3SA2) += snd-opl3sa2.o +obj-$(CONFIG_SND_SC6000) += snd-sc6000.o obj-$(CONFIG_SND_SGALAXY) += snd-sgalaxy.o obj-$(CONFIG_SND_SSCAPE) += snd-sscape.o diff --git a/sound/isa/ad1816a/Makefile b/sound/isa/ad1816a/Makefile index 90e00e842e49..487ab23860e3 100644 --- a/sound/isa/ad1816a/Makefile +++ b/sound/isa/ad1816a/Makefile @@ -1,6 +1,6 @@ # # Makefile for ALSA -# Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz> +# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz> # snd-ad1816a-objs := ad1816a.o ad1816a_lib.o diff --git a/sound/isa/ad1816a/ad1816a_lib.c b/sound/isa/ad1816a/ad1816a_lib.c index ec9209cd5177..cf18fe4617a1 100644 --- a/sound/isa/ad1816a/ad1816a_lib.c +++ b/sound/isa/ad1816a/ad1816a_lib.c @@ -453,7 +453,6 @@ static int snd_ad1816a_playback_open(struct snd_pcm_substream *substream) if ((error = snd_ad1816a_open(chip, AD1816A_MODE_PLAYBACK)) < 0) return error; - snd_pcm_set_sync(substream); runtime->hw = snd_ad1816a_playback; 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); @@ -469,7 +468,6 @@ static int snd_ad1816a_capture_open(struct snd_pcm_substream *substream) if ((error = snd_ad1816a_open(chip, AD1816A_MODE_CAPTURE)) < 0) return error; - snd_pcm_set_sync(substream); runtime->hw = snd_ad1816a_capture; 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); diff --git a/sound/isa/ad1848/Makefile b/sound/isa/ad1848/Makefile index 45d59998aa69..ae23331e9200 100644 --- a/sound/isa/ad1848/Makefile +++ b/sound/isa/ad1848/Makefile @@ -1,15 +1,12 @@ # # Makefile for ALSA -# Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz> +# 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_CMI8330) += snd-ad1848-lib.o -obj-$(CONFIG_SND_SGALAXY) += snd-ad1848-lib.o -obj-$(CONFIG_SND_AD1848) += snd-ad1848.o snd-ad1848-lib.o -obj-$(CONFIG_SND_OPTI92X_AD1848) += snd-ad1848-lib.o +obj-$(CONFIG_SND_AD1848) += snd-ad1848.o +obj-$(CONFIG_SND_AD1848_LIB) += snd-ad1848-lib.o -obj-m := $(sort $(obj-m)) diff --git a/sound/isa/ad1848/ad1848.c b/sound/isa/ad1848/ad1848.c index d09a7fa86545..a4710b5e214c 100644 --- a/sound/isa/ad1848/ad1848.c +++ b/sound/isa/ad1848/ad1848.c @@ -1,8 +1,8 @@ /* * Generic driver for AD1848/AD1847/CS4248 chips (0.1 Alpha) * Copyright (c) by Tugrul Galatali <galatalt@stuy.edu>, - * Jaroslav Kysela <perex@suse.cz> - * Based on card-4232.c by Jaroslav Kysela <perex@suse.cz> + * Jaroslav Kysela <perex@perex.cz> + * Based on card-4232.c by Jaroslav Kysela <perex@perex.cz> * * * This program is free software; you can redistribute it and/or modify @@ -36,7 +36,7 @@ #define DEV_NAME "ad1848" MODULE_DESCRIPTION(CRD_NAME); -MODULE_AUTHOR("Tugrul Galatali <galatalt@stuy.edu>, Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Tugrul Galatali <galatalt@stuy.edu>, Jaroslav Kysela <perex@perex.cz>"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Analog Devices,AD1848}," "{Analog Devices,AD1847}," diff --git a/sound/isa/ad1848/ad1848_lib.c b/sound/isa/ad1848/ad1848_lib.c index 1bc2e3fd5721..a901cd1ee692 100644 --- a/sound/isa/ad1848/ad1848_lib.c +++ b/sound/isa/ad1848/ad1848_lib.c @@ -1,5 +1,5 @@ /* - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * Routines for control of AD1848/AD1847/CS4248 * * @@ -35,7 +35,7 @@ #include <asm/io.h> #include <asm/dma.h> -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("Routines for control of AD1848/AD1847/CS4248"); MODULE_LICENSE("GPL"); @@ -70,7 +70,7 @@ static unsigned int rates[14] = { }; static struct snd_pcm_hw_constraint_list hw_constraints_rates = { - .count = 14, + .count = ARRAY_SIZE(rates), .list = rates, .mask = 0, }; @@ -99,24 +99,32 @@ static unsigned char snd_ad1848_original_image[16] = * Basic I/O functions */ -void snd_ad1848_out(struct snd_ad1848 *chip, - unsigned char reg, - unsigned char value) +static void snd_ad1848_wait(struct snd_ad1848 *chip) { int timeout; - for (timeout = 250; timeout > 0 && (inb(AD1848P(chip, REGSEL)) & AD1848_INIT); 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); + 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(); -#if 0 - printk("codec out - reg 0x%x = 0x%x\n", chip->mce_bit | reg, value); -#endif + snd_printdd("codec out - reg 0x%x = 0x%x\n", + chip->mce_bit | reg, value); } EXPORT_SYMBOL(snd_ad1848_out); @@ -124,10 +132,7 @@ EXPORT_SYMBOL(snd_ad1848_out); static void snd_ad1848_dout(struct snd_ad1848 *chip, unsigned char reg, unsigned char value) { - int timeout; - - for (timeout = 250; timeout > 0 && (inb(AD1848P(chip, REGSEL)) & AD1848_INIT); timeout--) - udelay(100); + snd_ad1848_wait(chip); outb(chip->mce_bit | reg, AD1848P(chip, REGSEL)); outb(value, AD1848P(chip, REG)); mb(); @@ -135,13 +140,11 @@ static void snd_ad1848_dout(struct snd_ad1848 *chip, static unsigned char snd_ad1848_in(struct snd_ad1848 *chip, unsigned char reg) { - int timeout; - - for (timeout = 250; timeout > 0 && (inb(AD1848P(chip, REGSEL)) & AD1848_INIT); timeout--) - udelay(100); + 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); + snd_printk(KERN_WARNING "auto calibration time out - " + "reg = 0x%x\n", reg); #endif outb(chip->mce_bit | reg, AD1848P(chip, REGSEL)); mb(); @@ -183,8 +186,7 @@ static void snd_ad1848_mce_up(struct snd_ad1848 *chip) unsigned long flags; int timeout; - for (timeout = 250; timeout > 0 && (inb(AD1848P(chip, REGSEL)) & AD1848_INIT); timeout--) - udelay(100); + 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"); @@ -201,9 +203,8 @@ static void snd_ad1848_mce_up(struct snd_ad1848 *chip) static void snd_ad1848_mce_down(struct snd_ad1848 *chip) { - unsigned long flags; - int timeout; - signed long time; + unsigned long flags, timeout; + int reg; spin_lock_irqsave(&chip->reg_lock, flags); for (timeout = 5; timeout > 0; timeout--) @@ -211,61 +212,48 @@ static void snd_ad1848_mce_down(struct snd_ad1848 *chip) /* end of cleanup sequence */ for (timeout = 12000; timeout > 0 && (inb(AD1848P(chip, REGSEL)) & AD1848_INIT); timeout--) udelay(100); -#if 0 - printk("(1) timeout = %i\n", timeout); -#endif + + snd_printdd("(1) timeout = %d\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; - timeout = inb(AD1848P(chip, REGSEL)); - outb(chip->mce_bit | (timeout & 0x1f), AD1848P(chip, REGSEL)); - if (timeout == 0x80) + 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 ((timeout & AD1848_MCE) == 0) { + if ((reg & AD1848_MCE) == 0) { spin_unlock_irqrestore(&chip->reg_lock, flags); return; } - /* calibration process */ - for (timeout = 500; timeout > 0 && (snd_ad1848_in(chip, AD1848_TEST_INIT) & AD1848_CALIB_IN_PROGRESS) == 0; timeout--); - if ((snd_ad1848_in(chip, AD1848_TEST_INIT) & AD1848_CALIB_IN_PROGRESS) == 0) { - snd_printd("mce_down - auto calibration time out (1)\n"); - spin_unlock_irqrestore(&chip->reg_lock, flags); - return; - } -#if 0 - printk("(2) timeout = %i, jiffies = %li\n", timeout, jiffies); -#endif - time = HZ / 4; - while (snd_ad1848_in(chip, AD1848_TEST_INIT) & AD1848_CALIB_IN_PROGRESS) { + /* + * 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); - if (time <= 0) { - snd_printk(KERN_ERR "mce_down - auto calibration time out (2)\n"); - return; - } - time = schedule_timeout(time); + msleep(1); spin_lock_irqsave(&chip->reg_lock, flags); - } -#if 0 - printk("(3) jiffies = %li\n", jiffies); -#endif - time = HZ / 10; - while (inb(AD1848P(chip, REGSEL)) & AD1848_INIT) { - spin_unlock_irqrestore(&chip->reg_lock, flags); - if (time <= 0) { - snd_printk(KERN_ERR "mce_down - auto calibration time out (3)\n"); - return; - } - time = schedule_timeout(time); - 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 0 - printk("(4) jiffies = %li\n", jiffies); - snd_printk("mce_down - exit = 0x%x\n", inb(AD1848P(chip, REGSEL))); -#endif + 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, @@ -319,11 +307,11 @@ static unsigned char snd_ad1848_get_rate(unsigned int rate) { int i; - for (i = 0; i < 14; i++) + for (i = 0; i < ARRAY_SIZE(rates); i++) if (rate == rates[i]) return freq_bits[i]; snd_BUG(); - return freq_bits[13]; + return freq_bits[ARRAY_SIZE(rates) - 1]; } static int snd_ad1848_ioctl(struct snd_pcm_substream *substream, @@ -390,11 +378,9 @@ static int snd_ad1848_open(struct snd_ad1848 *chip, unsigned int mode) { unsigned long flags; - mutex_lock(&chip->open_mutex); - if (chip->mode & AD1848_MODE_OPEN) { - mutex_unlock(&chip->open_mutex); + if (chip->mode & AD1848_MODE_OPEN) return -EAGAIN; - } + snd_ad1848_mce_down(chip); #ifdef SNDRV_DEBUG_MCE @@ -435,7 +421,6 @@ static int snd_ad1848_open(struct snd_ad1848 *chip, unsigned int mode) spin_unlock_irqrestore(&chip->reg_lock, flags); chip->mode = mode; - mutex_unlock(&chip->open_mutex); return 0; } @@ -444,11 +429,8 @@ static void snd_ad1848_close(struct snd_ad1848 *chip) { unsigned long flags; - mutex_lock(&chip->open_mutex); - if (!chip->mode) { - mutex_unlock(&chip->open_mutex); + if (!chip->mode) return; - } /* disable IRQ */ spin_lock_irqsave(&chip->reg_lock, flags); outb(0, AD1848P(chip, STATUS)); /* clear IRQ */ @@ -474,7 +456,6 @@ static void snd_ad1848_close(struct snd_ad1848 *chip) spin_unlock_irqrestore(&chip->reg_lock, flags); chip->mode = 0; - mutex_unlock(&chip->open_mutex); } /* @@ -892,7 +873,6 @@ int snd_ad1848_create(struct snd_card *card, if (chip == NULL) return -ENOMEM; spin_lock_init(&chip->reg_lock); - mutex_init(&chip->open_mutex); chip->card = card; chip->port = port; chip->irq = -1; diff --git a/sound/isa/cs423x/Makefile b/sound/isa/cs423x/Makefile index 2fb4f7409d7c..5067ee001933 100644 --- a/sound/isa/cs423x/Makefile +++ b/sound/isa/cs423x/Makefile @@ -1,6 +1,6 @@ # # Makefile for ALSA -# Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz> +# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz> # snd-cs4231-lib-objs := cs4231_lib.o @@ -10,17 +10,8 @@ snd-cs4232-objs := cs4232.o snd-cs4236-objs := cs4236.o # Toplevel Module Dependency -obj-$(CONFIG_SND_AZT2320) += snd-cs4231-lib.o -obj-$(CONFIG_SND_MIRO) += snd-cs4231-lib.o -obj-$(CONFIG_SND_OPL3SA2) += snd-cs4231-lib.o -obj-$(CONFIG_SND_CS4231) += snd-cs4231.o snd-cs4231-lib.o -obj-$(CONFIG_SND_CS4232) += snd-cs4232.o snd-cs4231-lib.o -obj-$(CONFIG_SND_CS4236) += snd-cs4236.o snd-cs4236-lib.o snd-cs4231-lib.o -obj-$(CONFIG_SND_GUSMAX) += snd-cs4231-lib.o -obj-$(CONFIG_SND_INTERWAVE) += snd-cs4231-lib.o -obj-$(CONFIG_SND_INTERWAVE_STB) += snd-cs4231-lib.o -obj-$(CONFIG_SND_OPTI92X_CS4231) += snd-cs4231-lib.o -obj-$(CONFIG_SND_WAVEFRONT) += snd-cs4231-lib.o -obj-$(CONFIG_SND_SSCAPE) += snd-cs4231-lib.o +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 -obj-m := $(sort $(obj-m)) diff --git a/sound/isa/cs423x/cs4231.c b/sound/isa/cs423x/cs4231.c index ac4041134150..13db6842eaaa 100644 --- a/sound/isa/cs423x/cs4231.c +++ b/sound/isa/cs423x/cs4231.c @@ -1,6 +1,6 @@ /* * Generic driver for CS4231 chips - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * Originally the CS4232/CS4232A driver, modified for use on CS4231 by * Tugrul Galatali <galatalt@stuy.edu> * @@ -36,7 +36,7 @@ #define DEV_NAME "cs4231" MODULE_DESCRIPTION(CRD_NAME); -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Crystal Semiconductors,CS4231}}"); diff --git a/sound/isa/cs423x/cs4231_lib.c b/sound/isa/cs423x/cs4231_lib.c index 914d77b61b0c..a5eb9659b519 100644 --- a/sound/isa/cs423x/cs4231_lib.c +++ b/sound/isa/cs423x/cs4231_lib.c @@ -1,5 +1,5 @@ /* - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * Routines for control of CS4231(A)/CS4232/InterWave & compatible chips * * Bugs: @@ -39,7 +39,7 @@ #include <asm/dma.h> #include <asm/irq.h> -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("Routines for control of CS4231(A)/CS4232/InterWave & compatible chips"); MODULE_LICENSE("GPL"); @@ -74,7 +74,7 @@ static unsigned int rates[14] = { }; static struct snd_pcm_hw_constraint_list hw_constraints_rates = { - .count = 14, + .count = ARRAY_SIZE(rates), .list = rates, .mask = 0, }; @@ -134,29 +134,31 @@ static inline u8 cs4231_inb(struct snd_cs4231 *chip, u8 offset) return inb(chip->port + offset); } -static void snd_cs4231_outm(struct snd_cs4231 *chip, unsigned char reg, - unsigned char mask, unsigned char value) +static void snd_cs4231_wait(struct snd_cs4231 *chip) { int timeout; - unsigned char tmp; 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 - if (chip->calibrate_mute) { - chip->image[reg] &= mask; - chip->image[reg] |= value; - } else { + chip->image[reg] = tmp; + if (!chip->calibrate_mute) { cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg); - mb(); - tmp = (chip->image[reg] & mask) | value; + wmb(); cs4231_outb(chip, CS4231P(REG), tmp); - chip->image[reg] = tmp; mb(); } } @@ -176,12 +178,7 @@ static void snd_cs4231_dout(struct snd_cs4231 *chip, unsigned char reg, unsigned void snd_cs4231_out(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(100); + 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); @@ -190,19 +187,13 @@ void snd_cs4231_out(struct snd_cs4231 *chip, unsigned char reg, unsigned char va cs4231_outb(chip, CS4231P(REG), value); chip->image[reg] = value; mb(); -#if 0 - printk("codec out - reg 0x%x = 0x%x\n", chip->mce_bit | reg, value); -#endif + 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) { - int timeout; - - for (timeout = 250; - timeout > 0 && (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT); - timeout--) - udelay(100); + 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); @@ -304,8 +295,7 @@ void snd_cs4231_mce_up(struct snd_cs4231 *chip) unsigned long flags; int timeout; - for (timeout = 250; timeout > 0 && (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT); timeout--) - udelay(100); + 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"); @@ -323,12 +313,11 @@ void snd_cs4231_mce_up(struct snd_cs4231 *chip) void snd_cs4231_mce_down(struct snd_cs4231 *chip) { unsigned long flags; + unsigned long end_time; int timeout; snd_cs4231_busy_wait(chip); -#if 0 - printk("(1) timeout = %i\n", timeout); -#endif + #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)); @@ -346,42 +335,42 @@ void snd_cs4231_mce_down(struct snd_cs4231 *chip) } snd_cs4231_busy_wait(chip); - /* calibration process */ + /* + * 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); - for (timeout = 500; timeout > 0 && (snd_cs4231_in(chip, CS4231_TEST_INIT) & CS4231_CALIB_IN_PROGRESS) == 0; timeout--) - udelay(10); - if ((snd_cs4231_in(chip, CS4231_TEST_INIT) & CS4231_CALIB_IN_PROGRESS) == 0) { - snd_printd("cs4231_mce_down - auto calibration time out (1)\n"); - return; - } -#if 0 - printk("(2) timeout = %i, jiffies = %li\n", timeout, jiffies); -#endif - /* in 10 ms increments, check condition, up to 250 ms */ - timeout = 25; - while (snd_cs4231_in(chip, CS4231_TEST_INIT) & CS4231_CALIB_IN_PROGRESS) { - if (--timeout < 0) { - snd_printk("mce_down - auto calibration time out (2)\n"); + 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(10); + msleep(1); } -#if 0 - printk("(3) jiffies = %li\n", jiffies); -#endif - /* in 10 ms increments, check condition, up to 100 ms */ - timeout = 10; + + 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 (--timeout < 0) { + if (time_after(jiffies, end_time)) { snd_printk(KERN_ERR "mce_down - auto calibration time out (3)\n"); return; } - msleep(10); + msleep(1); } -#if 0 - printk("(4) jiffies = %li\n", jiffies); - snd_printk("mce_down - exit = 0x%x\n", cs4231_inb(chip, CS4231P(REGSEL))); -#endif + + 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) @@ -459,11 +448,11 @@ static unsigned char snd_cs4231_get_rate(unsigned int rate) { int i; - for (i = 0; i < 14; i++) + for (i = 0; i < ARRAY_SIZE(rates); i++) if (rate == rates[i]) return freq_bits[i]; // snd_BUG(); - return freq_bits[13]; + return freq_bits[ARRAY_SIZE(rates) - 1]; } static unsigned char snd_cs4231_get_format(struct snd_cs4231 *chip, @@ -555,6 +544,8 @@ static void snd_cs4231_playback_format(struct snd_cs4231 *chip, 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); diff --git a/sound/isa/cs423x/cs4236.c b/sound/isa/cs423x/cs4236.c index 1a14f33b6ab0..5784b43f4123 100644 --- a/sound/isa/cs423x/cs4236.c +++ b/sound/isa/cs423x/cs4236.c @@ -1,6 +1,6 @@ /* * Driver for generic CS4232/CS4235/CS4236/CS4236B/CS4237B/CS4238B/CS4239 chips - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * * * This program is free software; you can redistribute it and/or modify @@ -32,7 +32,7 @@ #include <sound/opl3.h> #include <sound/initval.h> -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_LICENSE("GPL"); #ifdef CS4232 MODULE_DESCRIPTION("Cirrus Logic CS4232"); diff --git a/sound/isa/cs423x/cs4236_lib.c b/sound/isa/cs423x/cs4236_lib.c index 7a5a6c71f5e4..6bd064470d4c 100644 --- a/sound/isa/cs423x/cs4236_lib.c +++ b/sound/isa/cs423x/cs4236_lib.c @@ -1,5 +1,5 @@ /* - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * Routines for control of CS4235/4236B/4237B/4238B/4239 chips * * Note: @@ -89,7 +89,7 @@ #include <sound/cs4231.h> #include <sound/asoundef.h> -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("Routines for control of CS4235/4236B/4237B/4238B/4239 chips"); MODULE_LICENSE("GPL"); diff --git a/sound/isa/es1688/Makefile b/sound/isa/es1688/Makefile index 501c8bf903af..aee1e4ddb22a 100644 --- a/sound/isa/es1688/Makefile +++ b/sound/isa/es1688/Makefile @@ -1,6 +1,6 @@ # # Makefile for ALSA -# Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz> +# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz> # snd-es1688-lib-objs := es1688_lib.o diff --git a/sound/isa/es1688/es1688.c b/sound/isa/es1688/es1688.c index edc398712e8b..74bbc92f2e7c 100644 --- a/sound/isa/es1688/es1688.c +++ b/sound/isa/es1688/es1688.c @@ -1,6 +1,6 @@ /* * Driver for generic ESS AudioDrive ESx688 soundcards - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * * * This program is free software; you can redistribute it and/or modify @@ -39,7 +39,7 @@ #define DEV_NAME "es1688" MODULE_DESCRIPTION(CRD_NAME); -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{ESS,ES688 PnP AudioDrive,pnp:ESS0100}," "{ESS,ES1688 PnP AudioDrive,pnp:ESS0102}," diff --git a/sound/isa/es1688/es1688_lib.c b/sound/isa/es1688/es1688_lib.c index a2ab99f2ac35..5c26d495daa8 100644 --- a/sound/isa/es1688/es1688_lib.c +++ b/sound/isa/es1688/es1688_lib.c @@ -1,5 +1,5 @@ /* - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * Routines for control of ESS ES1688/688/488 chip * * @@ -32,7 +32,7 @@ #include <asm/io.h> #include <asm/dma.h> -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("ESS ESx688 lowlevel module"); MODULE_LICENSE("GPL"); diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c index f7732bf90be3..4a7367a8ff9d 100644 --- a/sound/isa/es18xx.c +++ b/sound/isa/es18xx.c @@ -1071,14 +1071,7 @@ static int snd_es18xx_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem return (snd_es18xx_mixer_bits(chip, 0x1c, 0x07, val) != val) || retVal; } -static int snd_es18xx_info_spatializer_enable(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_es18xx_info_spatializer_enable snd_ctl_boolean_mono_info static int snd_es18xx_get_spatializer_enable(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1120,14 +1113,7 @@ static int snd_es18xx_get_hw_volume(struct snd_kcontrol *kcontrol, struct snd_ct return 0; } -static int snd_es18xx_info_hw_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 2; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_es18xx_info_hw_switch snd_ctl_boolean_stereo_info static int snd_es18xx_get_hw_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -2042,6 +2028,7 @@ static int pnpc_registered; static struct pnp_device_id snd_audiodrive_pnpbiosids[] = { { .id = "ESS1869" }, + { .id = "ESS1879" }, { .id = "" } /* end */ }; diff --git a/sound/isa/gus/Makefile b/sound/isa/gus/Makefile index bae5dbd6c8e5..df3d59f25f5e 100644 --- a/sound/isa/gus/Makefile +++ b/sound/isa/gus/Makefile @@ -1,6 +1,6 @@ # # Makefile for ALSA -# Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz> +# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz> # snd-gus-lib-objs := gus_main.o \ diff --git a/sound/isa/gus/gus_dma.c b/sound/isa/gus/gus_dma.c index 44ee5d3674a1..fc905141e8a5 100644 --- a/sound/isa/gus/gus_dma.c +++ b/sound/isa/gus/gus_dma.c @@ -1,6 +1,6 @@ /* * Routines for GF1 DMA control - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * * * This program is free software; you can redistribute it and/or modify diff --git a/sound/isa/gus/gus_dram.c b/sound/isa/gus/gus_dram.c index f22fe7967fcc..9eaa932f6efe 100644 --- a/sound/isa/gus/gus_dram.c +++ b/sound/isa/gus/gus_dram.c @@ -1,5 +1,5 @@ /* - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * DRAM access routines * * diff --git a/sound/isa/gus/gus_instr.c b/sound/isa/gus/gus_instr.c index d0c38e1856ef..bf137ea72329 100644 --- a/sound/isa/gus/gus_instr.c +++ b/sound/isa/gus/gus_instr.c @@ -1,6 +1,6 @@ /* * Routines for Gravis UltraSound soundcards - Synthesizer - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * * * This program is free software; you can redistribute it and/or modify diff --git a/sound/isa/gus/gus_io.c b/sound/isa/gus/gus_io.c index 9b1fe292de4d..3d4f899285ef 100644 --- a/sound/isa/gus/gus_io.c +++ b/sound/isa/gus/gus_io.c @@ -1,5 +1,5 @@ /* - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * I/O routines for GF1/InterWave synthesizer chips * * diff --git a/sound/isa/gus/gus_irq.c b/sound/isa/gus/gus_irq.c index 537d3cfe41f3..cd9a6f1c99e6 100644 --- a/sound/isa/gus/gus_irq.c +++ b/sound/isa/gus/gus_irq.c @@ -1,6 +1,6 @@ /* * Routine for IRQ handling from GF1/InterWave chip - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * * * This program is free software; you can redistribute it and/or modify @@ -45,11 +45,13 @@ __again: // snd_printk("IRQ: status = 0x%x\n", status); if (status & 0x02) { STAT_ADD(gus->gf1.interrupt_stat_midi_in); - gus->gf1.interrupt_handler_midi_in(gus); + if (gus->gf1.interrupt_handler_midi_in) + gus->gf1.interrupt_handler_midi_in(gus); } if (status & 0x01) { STAT_ADD(gus->gf1.interrupt_stat_midi_out); - gus->gf1.interrupt_handler_midi_out(gus); + if (gus->gf1.interrupt_handler_midi_out) + gus->gf1.interrupt_handler_midi_out(gus); } if (status & (0x20 | 0x40)) { unsigned int already, _current_; @@ -85,20 +87,24 @@ __again: } if (status & 0x04) { STAT_ADD(gus->gf1.interrupt_stat_timer1); - gus->gf1.interrupt_handler_timer1(gus); + if (gus->gf1.interrupt_handler_timer1) + gus->gf1.interrupt_handler_timer1(gus); } if (status & 0x08) { STAT_ADD(gus->gf1.interrupt_stat_timer2); - gus->gf1.interrupt_handler_timer2(gus); + if (gus->gf1.interrupt_handler_timer2) + gus->gf1.interrupt_handler_timer2(gus); } if (status & 0x80) { if (snd_gf1_i_look8(gus, SNDRV_GF1_GB_DRAM_DMA_CONTROL) & 0x40) { STAT_ADD(gus->gf1.interrupt_stat_dma_write); - gus->gf1.interrupt_handler_dma_write(gus); + if (gus->gf1.interrupt_handler_dma_write) + gus->gf1.interrupt_handler_dma_write(gus); } if (snd_gf1_i_look8(gus, SNDRV_GF1_GB_REC_DMA_CONTROL) & 0x40) { STAT_ADD(gus->gf1.interrupt_stat_dma_read); - gus->gf1.interrupt_handler_dma_read(gus); + if (gus->gf1.interrupt_handler_dma_read) + gus->gf1.interrupt_handler_dma_read(gus); } } if (--loop > 0) diff --git a/sound/isa/gus/gus_main.c b/sound/isa/gus/gus_main.c index 8ced5e81b9a7..b14d5d6d9a32 100644 --- a/sound/isa/gus/gus_main.c +++ b/sound/isa/gus/gus_main.c @@ -1,6 +1,6 @@ /* * Routines for Gravis UltraSound soundcards - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * * * This program is free software; you can redistribute it and/or modify @@ -31,7 +31,7 @@ #include <asm/dma.h> -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("Routines for Gravis UltraSound soundcards"); MODULE_LICENSE("GPL"); @@ -154,6 +154,14 @@ int snd_gus_create(struct snd_card *card, gus = kzalloc(sizeof(*gus), GFP_KERNEL); if (gus == NULL) return -ENOMEM; + spin_lock_init(&gus->reg_lock); + spin_lock_init(&gus->voice_alloc); + spin_lock_init(&gus->active_voice_lock); + spin_lock_init(&gus->event_lock); + spin_lock_init(&gus->dma_lock); + spin_lock_init(&gus->pcm_volume_level_lock); + spin_lock_init(&gus->uart_cmd_lock); + mutex_init(&gus->dma_mutex); gus->gf1.irq = -1; gus->gf1.dma1 = -1; gus->gf1.dma2 = -1; @@ -218,14 +226,6 @@ int snd_gus_create(struct snd_card *card, gus->gf1.pcm_channels = pcm_channels; gus->gf1.volume_ramp = 25; gus->gf1.smooth_pan = 1; - spin_lock_init(&gus->reg_lock); - spin_lock_init(&gus->voice_alloc); - spin_lock_init(&gus->active_voice_lock); - spin_lock_init(&gus->event_lock); - spin_lock_init(&gus->dma_lock); - spin_lock_init(&gus->pcm_volume_level_lock); - spin_lock_init(&gus->uart_cmd_lock); - mutex_init(&gus->dma_mutex); if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, gus, &ops)) < 0) { snd_gus_free(gus); return err; @@ -398,7 +398,7 @@ static int snd_gus_check_version(struct snd_gus_card * gus) gus->ess_flag = 1; } else { snd_printk(KERN_ERR "unknown GF1 revision number at 0x%lx - 0x%x (0x%x)\n", gus->gf1.port, rev, val); - snd_printk(KERN_ERR " please - report to <perex@suse.cz>\n"); + snd_printk(KERN_ERR " please - report to <perex@perex.cz>\n"); } } } diff --git a/sound/isa/gus/gus_mem.c b/sound/isa/gus/gus_mem.c index 7107753b85b5..bcf4656853c4 100644 --- a/sound/isa/gus/gus_mem.c +++ b/sound/isa/gus/gus_mem.c @@ -1,5 +1,5 @@ /* - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * GUS's memory allocation routines / bottom layer * * diff --git a/sound/isa/gus/gus_mem_proc.c b/sound/isa/gus/gus_mem_proc.c index 80f0a83818b2..f69a44728ebf 100644 --- a/sound/isa/gus/gus_mem_proc.c +++ b/sound/isa/gus/gus_mem_proc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * GUS's memory access via proc filesystem * * diff --git a/sound/isa/gus/gus_mixer.c b/sound/isa/gus/gus_mixer.c index acc25a297200..a96253e16654 100644 --- a/sound/isa/gus/gus_mixer.c +++ b/sound/isa/gus/gus_mixer.c @@ -1,5 +1,5 @@ /* - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * Routines for control of ICS 2101 chip and "mixer" in GF1 chip * * @@ -36,14 +36,7 @@ .get = snd_gf1_get_single, .put = snd_gf1_put_single, \ .private_value = shift | (invert << 8) } -static int snd_gf1_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_gf1_info_single snd_ctl_boolean_mono_info static int snd_gf1_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { diff --git a/sound/isa/gus/gus_pcm.c b/sound/isa/gus/gus_pcm.c index c7f95e7aa018..a7971f5ffe63 100644 --- a/sound/isa/gus/gus_pcm.c +++ b/sound/isa/gus/gus_pcm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * Routines for control of GF1 chip (PCM things) * * InterWave chips supports interleaved DMA, but this feature isn't used in diff --git a/sound/isa/gus/gus_reset.c b/sound/isa/gus/gus_reset.c index b263655c4116..20cfdb87f84a 100644 --- a/sound/isa/gus/gus_reset.c +++ b/sound/isa/gus/gus_reset.c @@ -1,5 +1,5 @@ /* - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * * * This program is free software; you can redistribute it and/or modify diff --git a/sound/isa/gus/gus_sample.c b/sound/isa/gus/gus_sample.c index 9e0c55ab25b2..cba0829a7106 100644 --- a/sound/isa/gus/gus_sample.c +++ b/sound/isa/gus/gus_sample.c @@ -1,6 +1,6 @@ /* * Routines for Gravis UltraSound soundcards - Sample support - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * * * This program is free software; you can redistribute it and/or modify diff --git a/sound/isa/gus/gus_simple.c b/sound/isa/gus/gus_simple.c index dcad6ed0198c..39d121e2c8c4 100644 --- a/sound/isa/gus/gus_simple.c +++ b/sound/isa/gus/gus_simple.c @@ -1,6 +1,6 @@ /* * Routines for Gravis UltraSound soundcards - Simple instrument handlers - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * * * This program is free software; you can redistribute it and/or modify diff --git a/sound/isa/gus/gus_synth.c b/sound/isa/gus/gus_synth.c index 3e4d4d6edd8b..2c2051782aa2 100644 --- a/sound/isa/gus/gus_synth.c +++ b/sound/isa/gus/gus_synth.c @@ -1,6 +1,6 @@ /* * Routines for Gravis UltraSound soundcards - Synthesizer - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * * * This program is free software; you can redistribute it and/or modify @@ -26,7 +26,7 @@ #include <sound/gus.h> #include <sound/seq_device.h> -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("Routines for Gravis UltraSound soundcards - Synthesizer"); MODULE_LICENSE("GPL"); diff --git a/sound/isa/gus/gus_tables.h b/sound/isa/gus/gus_tables.h index 4adf098d3269..42a4ca0d622b 100644 --- a/sound/isa/gus/gus_tables.h +++ b/sound/isa/gus/gus_tables.h @@ -1,5 +1,5 @@ /* - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * * * This program is free software; you can redistribute it and/or modify diff --git a/sound/isa/gus/gus_timer.c b/sound/isa/gus/gus_timer.c index a43b662f17c7..99eac573c414 100644 --- a/sound/isa/gus/gus_timer.c +++ b/sound/isa/gus/gus_timer.c @@ -1,6 +1,6 @@ /* * Routines for Gravis UltraSound soundcards - Timers - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * * GUS have similar timers as AdLib (OPL2/OPL3 chips). * diff --git a/sound/isa/gus/gus_uart.c b/sound/isa/gus/gus_uart.c index 654290a8b21c..e6fd9b01c492 100644 --- a/sound/isa/gus/gus_uart.c +++ b/sound/isa/gus/gus_uart.c @@ -1,5 +1,5 @@ /* - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * Routines for the GF1 MIDI interface - like UART 6850 * * diff --git a/sound/isa/gus/gus_volume.c b/sound/isa/gus/gus_volume.c index dbbc0a6d7659..71a67744a14b 100644 --- a/sound/isa/gus/gus_volume.c +++ b/sound/isa/gus/gus_volume.c @@ -1,5 +1,5 @@ /* - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * * * This program is free software; you can redistribute it and/or modify diff --git a/sound/isa/gus/gusclassic.c b/sound/isa/gus/gusclassic.c index 8f23f433d491..29e422b00b58 100644 --- a/sound/isa/gus/gusclassic.c +++ b/sound/isa/gus/gusclassic.c @@ -1,6 +1,6 @@ /* * Driver for Gravis UltraSound Classic soundcard - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * * * This program is free software; you can redistribute it and/or modify @@ -37,7 +37,7 @@ #define DEV_NAME "gusclassic" MODULE_DESCRIPTION(CRD_NAME); -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Gravis,UltraSound Classic}}"); diff --git a/sound/isa/gus/gusextreme.c b/sound/isa/gus/gusextreme.c index 0aeaa6cf6cf0..fc59536c918e 100644 --- a/sound/isa/gus/gusextreme.c +++ b/sound/isa/gus/gusextreme.c @@ -1,6 +1,6 @@ /* * Driver for Gravis UltraSound Extreme soundcards - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * * * This program is free software; you can redistribute it and/or modify @@ -41,7 +41,7 @@ #define DEV_NAME "gusextreme" MODULE_DESCRIPTION(CRD_NAME); -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Gravis,UltraSound Extreme}}"); diff --git a/sound/isa/gus/gusmax.c b/sound/isa/gus/gusmax.c index 708783d4351f..4922f5da08f9 100644 --- a/sound/isa/gus/gusmax.c +++ b/sound/isa/gus/gusmax.c @@ -1,6 +1,6 @@ /* * Driver for Gravis UltraSound MAX soundcard - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * * * This program is free software; you can redistribute it and/or modify @@ -34,7 +34,7 @@ #define SNDRV_LEGACY_FIND_FREE_DMA #include <sound/initval.h> -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("Gravis UltraSound MAX"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Gravis,UltraSound MAX}}"); diff --git a/sound/isa/gus/interwave.c b/sound/isa/gus/interwave.c index 0220cdbe1a2a..2091c50b2e3e 100644 --- a/sound/isa/gus/interwave.c +++ b/sound/isa/gus/interwave.c @@ -1,6 +1,6 @@ /* * Driver for AMD InterWave soundcard - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * * * This program is free software; you can redistribute it and/or modify @@ -41,7 +41,7 @@ #define SNDRV_LEGACY_FIND_FREE_DMA #include <sound/initval.h> -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_LICENSE("GPL"); #ifndef SNDRV_STB MODULE_DESCRIPTION("AMD InterWave"); diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c index e70db32991d9..59af9ab7191f 100644 --- a/sound/isa/opl3sa2.c +++ b/sound/isa/opl3sa2.c @@ -1,6 +1,6 @@ /* * Driver for Yamaha OPL3-SA[2,3] soundcards - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * * * This program is free software; you can redistribute it and/or modify @@ -37,7 +37,7 @@ #include <asm/io.h> -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("Yamaha OPL3SA2+"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Yamaha,YMF719E-S}," @@ -253,6 +253,7 @@ static int __devinit snd_opl3sa2_detect(struct snd_opl3sa2 *chip) /* 0x03 - YM715B */ /* 0x04 - YM719 - OPL-SA4? */ /* 0x05 - OPL3-SA3 - Libretto 100 */ + /* 0x07 - unknown - Neomagic MagicWave 3D */ break; } str[0] = chip->version + '0'; diff --git a/sound/isa/opti9xx/Makefile b/sound/isa/opti9xx/Makefile index 0e41bfd5a403..b4d894db257a 100644 --- a/sound/isa/opti9xx/Makefile +++ b/sound/isa/opti9xx/Makefile @@ -1,6 +1,6 @@ # # Makefile for ALSA -# Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz> +# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz> # snd-opti92x-ad1848-objs := opti92x-ad1848.o diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c index cd29b30b362e..d295936611f8 100644 --- a/sound/isa/opti9xx/miro.c +++ b/sound/isa/opti9xx/miro.c @@ -242,14 +242,7 @@ static int aci_setvalue(struct snd_miro * miro, unsigned char index, int value) * MIXER part */ -static int snd_miro_info_capture(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - - return 0; -} +#define snd_miro_info_capture snd_ctl_boolean_mono_info static int snd_miro_get_capture(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -344,14 +337,7 @@ static int snd_miro_put_preamp(struct snd_kcontrol *kcontrol, return change; } -static int snd_miro_info_amp(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - - return 0; -} +#define snd_miro_info_amp snd_ctl_boolean_mono_info static int snd_miro_get_amp(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c index 049d479ce2b3..ee1a824d8fc0 100644 --- a/sound/isa/opti9xx/opti92x-ad1848.c +++ b/sound/isa/opti9xx/opti92x-ad1848.c @@ -501,6 +501,16 @@ static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip) (chip->hardware == OPTi9XX_HW_82C930 ? 0x00 : 0x04), 0x34); snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(5), 0x20, 0xbf); + /* + * The BTC 1817DW has QS1000 wavetable which is connected + * to the serial digital input of the OPTI931. + */ + snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(21), 0x82, 0xff); + /* + * This bit sets OPTI931 to automaticaly select FM + * or digital input signal. + */ + snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(26), 0x01, 0x01); break; #endif /* OPTi93X */ @@ -1732,11 +1742,11 @@ static int __devinit snd_card_opti9xx_pnp(struct snd_opti9xx *chip, #ifdef OPTi93X port = pnp_port_start(pdev, 0) - 4; - fm_port = pnp_port_start(pdev, 1); + fm_port = pnp_port_start(pdev, 1) + 8; #else if (pid->driver_data != 0x0924) port = pnp_port_start(pdev, 1); - fm_port = pnp_port_start(pdev, 2); + fm_port = pnp_port_start(pdev, 2) + 8; #endif /* OPTi93X */ irq = pnp_irq(pdev, 0); dma1 = pnp_dma(pdev, 0); diff --git a/sound/isa/sb/Makefile b/sound/isa/sb/Makefile index 556e66928029..c9d1c986d70e 100644 --- a/sound/isa/sb/Makefile +++ b/sound/isa/sb/Makefile @@ -1,6 +1,6 @@ # # Makefile for ALSA -# Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz> +# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz> # snd-sb-common-objs := sb_common.o sb_mixer.o diff --git a/sound/isa/sb/emu8000.c b/sound/isa/sb/emu8000.c index 658179e86142..4eea84cfd4f4 100644 --- a/sound/isa/sb/emu8000.c +++ b/sound/isa/sb/emu8000.c @@ -1,5 +1,5 @@ /* - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * and (c) 1999 Steve Ratcliffe <steve@parabola.demon.co.uk> * Copyright (C) 1999-2000 Takashi Iwai <tiwai@suse.de> * diff --git a/sound/isa/sb/emu8000_synth.c b/sound/isa/sb/emu8000_synth.c index 3d72742b342f..0c7905c85b76 100644 --- a/sound/isa/sb/emu8000_synth.c +++ b/sound/isa/sb/emu8000_synth.c @@ -1,5 +1,5 @@ /* - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * and (c) 1999 Steve Ratcliffe <steve@parabola.demon.co.uk> * Copyright (C) 1999-2000 Takashi Iwai <tiwai@suse.de> * diff --git a/sound/isa/sb/sb16.c b/sound/isa/sb/sb16.c index c4ba24bfd27c..e7f9edd92626 100644 --- a/sound/isa/sb/sb16.c +++ b/sound/isa/sb/sb16.c @@ -1,6 +1,6 @@ /* * Driver for SoundBlaster 16/AWE32/AWE64 soundcards - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * * * This program is free software; you can redistribute it and/or modify @@ -44,7 +44,7 @@ #define PFX "sb16: " #endif -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_LICENSE("GPL"); #ifndef SNDRV_SBAWE MODULE_DESCRIPTION("Sound Blaster 16"); diff --git a/sound/isa/sb/sb16_csp.c b/sound/isa/sb/sb16_csp.c index b279f2308aef..3682059787ab 100644 --- a/sound/isa/sb/sb16_csp.c +++ b/sound/isa/sb/sb16_csp.c @@ -979,14 +979,7 @@ static int snd_sb_csp_restart(struct snd_sb_csp * p) * QSound mixer control for PCM */ -static int snd_sb_qsound_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_sb_qsound_switch_info snd_ctl_boolean_mono_info static int snd_sb_qsound_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { diff --git a/sound/isa/sb/sb16_main.c b/sound/isa/sb/sb16_main.c index 5d4d3aafe2d5..c06754f7ee5d 100644 --- a/sound/isa/sb/sb16_main.c +++ b/sound/isa/sb/sb16_main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * Routines for control of 16-bit SoundBlaster cards and clones * Note: This is very ugly hardware which uses one 8-bit DMA channel and * second 16-bit DMA channel. Unfortunately 8-bit DMA channel can't @@ -45,7 +45,7 @@ #include <sound/control.h> #include <sound/info.h> -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("Routines for control of 16-bit SoundBlaster cards and clones"); MODULE_LICENSE("GPL"); diff --git a/sound/isa/sb/sb8.c b/sound/isa/sb/sb8.c index a1b3786b391e..f933aef7d8a9 100644 --- a/sound/isa/sb/sb8.c +++ b/sound/isa/sb/sb8.c @@ -1,6 +1,6 @@ /* * Driver for SoundBlaster 1.0/2.0/Pro soundcards and compatible - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * * * This program is free software; you can redistribute it and/or modify @@ -31,7 +31,7 @@ #include <sound/opl3.h> #include <sound/initval.h> -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("Sound Blaster 1.0/2.0/Pro"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Creative Labs,SB 1.0/SB 2.0/SB Pro}}"); diff --git a/sound/isa/sb/sb8_main.c b/sound/isa/sb/sb8_main.c index aea9e5ec7b36..bee894b3f5c7 100644 --- a/sound/isa/sb/sb8_main.c +++ b/sound/isa/sb/sb8_main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * Uros Bizjak <uros@kss-loka.si> * * Routines for control of 8-bit SoundBlaster cards and clones @@ -38,7 +38,7 @@ #include <sound/core.h> #include <sound/sb.h> -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Uros Bizjak <uros@kss-loka.si>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Uros Bizjak <uros@kss-loka.si>"); MODULE_DESCRIPTION("Routines for control of 8-bit SoundBlaster cards and clones"); MODULE_LICENSE("GPL"); diff --git a/sound/isa/sb/sb8_midi.c b/sound/isa/sb/sb8_midi.c index 0b67edd7ac6e..e56e5633411c 100644 --- a/sound/isa/sb/sb8_midi.c +++ b/sound/isa/sb/sb8_midi.c @@ -1,5 +1,5 @@ /* - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * Routines for control of SoundBlaster cards - MIDI interface * * This program is free software; you can redistribute it and/or modify diff --git a/sound/isa/sb/sb_common.c b/sound/isa/sb/sb_common.c index efa9d5c2558a..176193c05101 100644 --- a/sound/isa/sb/sb_common.c +++ b/sound/isa/sb/sb_common.c @@ -1,5 +1,5 @@ /* - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * Uros Bizjak <uros@kss-loka.si> * * Lowlevel routines for control of Sound Blaster cards @@ -33,7 +33,7 @@ #include <asm/io.h> #include <asm/dma.h> -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("ALSA lowlevel driver for Sound Blaster cards"); MODULE_LICENSE("GPL"); @@ -234,7 +234,9 @@ int snd_sbdsp_create(struct snd_card *card, chip->dma16 = -1; chip->port = port; - if (request_irq(irq, irq_handler, hardware == SB_HW_ALS4000 ? + if (request_irq(irq, irq_handler, + (hardware == SB_HW_ALS4000 || + hardware == SB_HW_CS5530) ? IRQF_SHARED : IRQF_DISABLED, "SoundBlaster", (void *) chip)) { snd_printk(KERN_ERR "sb: can't grab irq %d\n", irq); diff --git a/sound/isa/sb/sb_mixer.c b/sound/isa/sb/sb_mixer.c index 3d4befcff28e..03241cd5aaef 100644 --- a/sound/isa/sb/sb_mixer.c +++ b/sound/isa/sb/sb_mixer.c @@ -1,5 +1,5 @@ /* - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * Routines for Sound Blaster mixer control * * diff --git a/sound/isa/sc6000.c b/sound/isa/sc6000.c new file mode 100644 index 000000000000..94daf8399994 --- /dev/null +++ b/sound/isa/sc6000.c @@ -0,0 +1,656 @@ +/* + * Driver for Gallant SC-6000 soundcard. This card is also known as + * Audio Excel DSP 16 or Zoltrix AV302. + * These cards use CompuMedia ASC-9308 chip + AD1848 codec. + * + * Copyright (C) 2007 Krzysztof Helt <krzysztof.h1@wp.pl> + * + * I don't have documentation for this card. I used the driver + * for OSS/Free included in the kernel source as reference. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <sound/driver.h> +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/isa.h> +#include <linux/io.h> +#include <asm/dma.h> +#include <sound/core.h> +#include <sound/ad1848.h> +#include <sound/opl3.h> +#include <sound/mpu401.h> +#include <sound/control.h> +#define SNDRV_LEGACY_FIND_FREE_IRQ +#define SNDRV_LEGACY_FIND_FREE_DMA +#include <sound/initval.h> + +MODULE_AUTHOR("Krzysztof Helt"); +MODULE_DESCRIPTION("Gallant SC-6000"); +MODULE_LICENSE("GPL"); +MODULE_SUPPORTED_DEVICE("{{Gallant, SC-6000}," + "{AudioExcel, Audio Excel DSP 16}," + "{Zoltrix, AV302}}"); + +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ +static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ +static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */ +static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x220, 0x240 */ +static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 5, 7, 9, 10, 11 */ +static long mss_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x530, 0xe80 */ +static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; + /* 0x300, 0x310, 0x320, 0x330 */ +static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 5, 7, 9, 10, 0 */ +static int dma[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0, 1, 3 */ + +module_param_array(index, int, NULL, 0444); +MODULE_PARM_DESC(index, "Index value for sc-6000 based soundcard."); +module_param_array(id, charp, NULL, 0444); +MODULE_PARM_DESC(id, "ID string for sc-6000 based soundcard."); +module_param_array(enable, bool, NULL, 0444); +MODULE_PARM_DESC(enable, "Enable sc-6000 based soundcard."); +module_param_array(port, long, NULL, 0444); +MODULE_PARM_DESC(port, "Port # for sc-6000 driver."); +module_param_array(mss_port, long, NULL, 0444); +MODULE_PARM_DESC(mss_port, "MSS Port # for sc-6000 driver."); +module_param_array(mpu_port, long, NULL, 0444); +MODULE_PARM_DESC(mpu_port, "MPU-401 port # for sc-6000 driver."); +module_param_array(irq, int, NULL, 0444); +MODULE_PARM_DESC(irq, "IRQ # for sc-6000 driver."); +module_param_array(mpu_irq, int, NULL, 0444); +MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for sc-6000 driver."); +module_param_array(dma, int, NULL, 0444); +MODULE_PARM_DESC(dma, "DMA # for sc-6000 driver."); + +/* + * Commands of SC6000's DSP (SBPRO+special). + * Some of them are COMMAND_xx, in the future they may change. + */ +#define WRITE_MDIRQ_CFG 0x50 /* Set M&I&DRQ mask (the real config) */ +#define COMMAND_52 0x52 /* */ +#define READ_HARD_CFG 0x58 /* Read Hardware Config (I/O base etc) */ +#define COMMAND_5C 0x5c /* */ +#define COMMAND_60 0x60 /* */ +#define COMMAND_66 0x66 /* */ +#define COMMAND_6C 0x6c /* */ +#define COMMAND_6E 0x6e /* */ +#define COMMAND_88 0x88 /* Unknown command */ +#define DSP_INIT_MSS 0x8c /* Enable Microsoft Sound System mode */ +#define COMMAND_C5 0xc5 /* */ +#define GET_DSP_VERSION 0xe1 /* Get DSP Version */ +#define GET_DSP_COPYRIGHT 0xe3 /* Get DSP Copyright */ + +/* + * Offsets of SC6000 DSP I/O ports. The offset is added to base I/O port + * to have the actual I/O port. + * Register permissions are: + * (wo) == Write Only + * (ro) == Read Only + * (w-) == Write + * (r-) == Read + */ +#define DSP_RESET 0x06 /* offset of DSP RESET (wo) */ +#define DSP_READ 0x0a /* offset of DSP READ (ro) */ +#define DSP_WRITE 0x0c /* offset of DSP WRITE (w-) */ +#define DSP_COMMAND 0x0c /* offset of DSP COMMAND (w-) */ +#define DSP_STATUS 0x0c /* offset of DSP STATUS (r-) */ +#define DSP_DATAVAIL 0x0e /* offset of DSP DATA AVAILABLE (ro) */ + +#define PFX "sc6000: " +#define DRV_NAME "SC-6000" + +/* hardware dependent functions */ + +/* + * sc6000_irq_to_softcfg - Decode irq number into cfg code. + */ +static __devinit unsigned char sc6000_irq_to_softcfg(int irq) +{ + unsigned char val = 0; + + switch (irq) { + case 5: + val = 0x28; + break; + case 7: + val = 0x8; + break; + case 9: + val = 0x10; + break; + case 10: + val = 0x18; + break; + case 11: + val = 0x20; + break; + default: + break; + } + return val; +} + +/* + * sc6000_dma_to_softcfg - Decode dma number into cfg code. + */ +static __devinit unsigned char sc6000_dma_to_softcfg(int dma) +{ + unsigned char val = 0; + + switch (dma) { + case 0: + val = 1; + break; + case 1: + val = 2; + break; + case 3: + val = 3; + break; + default: + break; + } + return val; +} + +/* + * sc6000_mpu_irq_to_softcfg - Decode MPU-401 irq number into cfg code. + */ +static __devinit unsigned char sc6000_mpu_irq_to_softcfg(int mpu_irq) +{ + unsigned char val = 0; + + switch (mpu_irq) { + case 5: + val = 4; + break; + case 7: + val = 0x44; + break; + case 9: + val = 0x84; + break; + case 10: + val = 0xc4; + break; + default: + break; + } + return val; +} + +static __devinit int sc6000_wait_data(char __iomem *vport) +{ + int loop = 1000; + unsigned char val = 0; + + do { + val = ioread8(vport + DSP_DATAVAIL); + if (val & 0x80) + return 0; + cpu_relax(); + } while (loop--); + + return -EAGAIN; +} + +static __devinit int sc6000_read(char __iomem *vport) +{ + if (sc6000_wait_data(vport)) + return -EBUSY; + + return ioread8(vport + DSP_READ); + +} + +static __devinit int sc6000_write(char __iomem *vport, int cmd) +{ + unsigned char val; + int loop = 500000; + + do { + val = ioread8(vport + DSP_STATUS); + /* + * DSP ready to receive data if bit 7 of val == 0 + */ + if (!(val & 0x80)) { + iowrite8(cmd, vport + DSP_COMMAND); + return 0; + } + cpu_relax(); + } while (loop--); + + snd_printk(KERN_ERR "DSP Command (0x%x) timeout.\n", cmd); + + return -EIO; +} + +static int __devinit sc6000_dsp_get_answer(char __iomem *vport, int command, + char *data, int data_len) +{ + int len = 0; + + if (sc6000_write(vport, command)) { + snd_printk(KERN_ERR "CMD 0x%x: failed!\n", command); + return -EIO; + } + + do { + int val = sc6000_read(vport); + + if (val < 0) + break; + + data[len++] = val; + + } while (len < data_len); + + /* + * If no more data available, return to the caller, no error if len>0. + * We have no other way to know when the string is finished. + */ + return len ? len : -EIO; +} + +static int __devinit sc6000_dsp_reset(char __iomem *vport) +{ + iowrite8(1, vport + DSP_RESET); + udelay(10); + iowrite8(0, vport + DSP_RESET); + udelay(20); + if (sc6000_read(vport) == 0xaa) + return 0; + return -ENODEV; +} + +/* detection and initialization */ +static int __devinit sc6000_cfg_write(char __iomem *vport, + unsigned char softcfg) +{ + + if (sc6000_write(vport, WRITE_MDIRQ_CFG)) { + snd_printk(KERN_ERR "CMD 0x%x: failed!\n", WRITE_MDIRQ_CFG); + return -EIO; + } + if (sc6000_write(vport, softcfg)) { + snd_printk(KERN_ERR "sc6000_cfg_write: failed!\n"); + return -EIO; + } + return 0; +} + +static int __devinit sc6000_setup_board(char __iomem *vport, int config) +{ + int loop = 10; + + do { + if (sc6000_write(vport, COMMAND_88)) { + snd_printk(KERN_ERR "CMD 0x%x: failed!\n", + COMMAND_88); + return -EIO; + } + } while ((sc6000_wait_data(vport) < 0) && loop--); + + if (sc6000_read(vport) < 0) { + snd_printk(KERN_ERR "sc6000_read after CMD 0x%x: failed\n", + COMMAND_88); + return -EIO; + } + + if (sc6000_cfg_write(vport, config)) + return -ENODEV; + + return 0; +} + +static int __devinit sc6000_init_mss(char __iomem *vport, int config, + char __iomem *vmss_port, int mss_config) +{ + if (sc6000_write(vport, DSP_INIT_MSS)) { + snd_printk(KERN_ERR "sc6000_init_mss [0x%x]: failed!\n", + DSP_INIT_MSS); + return -EIO; + } + + msleep(10); + + if (sc6000_cfg_write(vport, config)) + return -EIO; + + iowrite8(mss_config, vmss_port); + + return 0; +} + +static int __devinit sc6000_init_board(char __iomem *vport, int irq, int dma, + char __iomem *vmss_port, int mpu_irq) +{ + char answer[15]; + char version[2]; + int mss_config = sc6000_irq_to_softcfg(irq) | + sc6000_dma_to_softcfg(dma); + int config = mss_config | + sc6000_mpu_irq_to_softcfg(mpu_irq); + int err; + + err = sc6000_dsp_reset(vport); + if (err < 0) { + snd_printk(KERN_ERR "sc6000_dsp_reset: failed!\n"); + return err; + } + + memset(answer, 0, sizeof(answer)); + err = sc6000_dsp_get_answer(vport, GET_DSP_COPYRIGHT, answer, 15); + if (err <= 0) { + snd_printk(KERN_ERR "sc6000_dsp_copyright: failed!\n"); + return -ENODEV; + } + /* + * My SC-6000 card return "SC-6000" in DSPCopyright, so + * if we have something different, we have to be warned. + * Mine returns "SC-6000A " - KH + */ + if (strncmp("SC-6000", answer, 7)) + snd_printk(KERN_WARNING "Warning: non SC-6000 audio card!\n"); + + if (sc6000_dsp_get_answer(vport, GET_DSP_VERSION, version, 2) < 2) { + snd_printk(KERN_ERR "sc6000_dsp_version: failed!\n"); + return -ENODEV; + } + printk(KERN_INFO PFX "Detected model: %s, DSP version %d.%d\n", + answer, version[0], version[1]); + + /* + * 0x0A == (IRQ 7, DMA 1, MIRQ 0) + */ + err = sc6000_cfg_write(vport, 0x0a); + if (err < 0) { + snd_printk(KERN_ERR "sc6000_cfg_write: failed!\n"); + return -EFAULT; + } + + err = sc6000_setup_board(vport, config); + if (err < 0) { + snd_printk(KERN_ERR "sc6000_setup_board: failed!\n"); + return -ENODEV; + } + + err = sc6000_init_mss(vport, config, vmss_port, mss_config); + if (err < 0) { + snd_printk(KERN_ERR "Can not initialize" + "Microsoft Sound System mode.\n"); + return -ENODEV; + } + + return 0; +} + +static int __devinit snd_sc6000_mixer(struct snd_ad1848 *chip) +{ + struct snd_card *card = chip->card; + struct snd_ctl_elem_id id1, id2; + int err; + + memset(&id1, 0, sizeof(id1)); + memset(&id2, 0, sizeof(id2)); + id1.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + /* reassign AUX0 to FM */ + strcpy(id1.name, "Aux Playback Switch"); + strcpy(id2.name, "FM Playback Switch"); + err = snd_ctl_rename_id(card, &id1, &id2); + if (err < 0) + return err; + strcpy(id1.name, "Aux Playback Volume"); + strcpy(id2.name, "FM Playback Volume"); + err = snd_ctl_rename_id(card, &id1, &id2); + if (err < 0) + return err; + /* reassign AUX1 to CD */ + strcpy(id1.name, "Aux Playback Switch"); id1.index = 1; + strcpy(id2.name, "CD Playback Switch"); + err = snd_ctl_rename_id(card, &id1, &id2); + if (err < 0) + return err; + strcpy(id1.name, "Aux Playback Volume"); + strcpy(id2.name, "CD Playback Volume"); + err = snd_ctl_rename_id(card, &id1, &id2); + if (err < 0) + return err; + return 0; +} + +static int __devinit snd_sc6000_match(struct device *devptr, unsigned int dev) +{ + if (!enable[dev]) + return 0; + if (port[dev] == SNDRV_AUTO_PORT) { + printk(KERN_ERR PFX "specify IO port\n"); + return 0; + } + if (mss_port[dev] == SNDRV_AUTO_PORT) { + printk(KERN_ERR PFX "specify MSS port\n"); + return 0; + } + if (port[dev] != 0x220 && port[dev] != 0x240) { + printk(KERN_ERR PFX "Port must be 0x220 or 0x240\n"); + return 0; + } + if (mss_port[dev] != 0x530 && mss_port[dev] != 0xe80) { + printk(KERN_ERR PFX "MSS port must be 0x530 or 0xe80\n"); + return 0; + } + if (irq[dev] != SNDRV_AUTO_IRQ && !sc6000_irq_to_softcfg(irq[dev])) { + printk(KERN_ERR PFX "invalid IRQ %d\n", irq[dev]); + return 0; + } + if (dma[dev] != SNDRV_AUTO_DMA && !sc6000_dma_to_softcfg(dma[dev])) { + printk(KERN_ERR PFX "invalid DMA %d\n", dma[dev]); + return 0; + } + if (mpu_port[dev] != SNDRV_AUTO_PORT && + (mpu_port[dev] & ~0x30L) != 0x300) { + printk(KERN_ERR PFX "invalid MPU-401 port %lx\n", + mpu_port[dev]); + return 0; + } + if (mpu_port[dev] != SNDRV_AUTO_PORT && + mpu_irq[dev] != SNDRV_AUTO_IRQ && mpu_irq[dev] != 0 && + !sc6000_mpu_irq_to_softcfg(mpu_irq[dev])) { + printk(KERN_ERR PFX "invalid MPU-401 IRQ %d\n", mpu_irq[dev]); + return 0; + } + return 1; +} + +static int __devinit snd_sc6000_probe(struct device *devptr, unsigned int dev) +{ + static int possible_irqs[] = { 5, 7, 9, 10, 11, -1 }; + static int possible_dmas[] = { 1, 3, 0, -1 }; + int err; + int xirq = irq[dev]; + int xdma = dma[dev]; + struct snd_card *card; + struct snd_ad1848 *chip; + struct snd_opl3 *opl3; + char __iomem *vport; + char __iomem *vmss_port; + + + card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); + if (!card) + return -ENOMEM; + + if (xirq == SNDRV_AUTO_IRQ) { + xirq = snd_legacy_find_free_irq(possible_irqs); + if (xirq < 0) { + snd_printk(KERN_ERR PFX "unable to find a free IRQ\n"); + err = -EBUSY; + goto err_exit; + } + } + + if (xdma == SNDRV_AUTO_DMA) { + xdma = snd_legacy_find_free_dma(possible_dmas); + if (xdma < 0) { + snd_printk(KERN_ERR PFX "unable to find a free DMA\n"); + err = -EBUSY; + goto err_exit; + } + } + + if (!request_region(port[dev], 0x10, DRV_NAME)) { + snd_printk(KERN_ERR PFX + "I/O port region is already in use.\n"); + err = -EBUSY; + goto err_exit; + } + vport = devm_ioport_map(devptr, port[dev], 0x10); + if (!vport) { + snd_printk(KERN_ERR PFX + "I/O port cannot be iomaped.\n"); + err = -EBUSY; + goto err_unmap1; + } + + /* to make it marked as used */ + if (!request_region(mss_port[dev], 4, DRV_NAME)) { + snd_printk(KERN_ERR PFX + "SC-6000 port I/O port region is already in use.\n"); + err = -EBUSY; + goto err_unmap1; + } + vmss_port = devm_ioport_map(devptr, mss_port[dev], 4); + if (!vport) { + snd_printk(KERN_ERR PFX + "MSS port I/O cannot be iomaped.\n"); + err = -EBUSY; + goto err_unmap2; + } + + snd_printd("Initializing BASE[0x%lx] IRQ[%d] DMA[%d] MIRQ[%d]\n", + port[dev], xirq, xdma, + mpu_irq[dev] == SNDRV_AUTO_IRQ ? 0 : mpu_irq[dev]); + + err = sc6000_init_board(vport, xirq, xdma, vmss_port, mpu_irq[dev]); + if (err < 0) + goto err_unmap2; + + err = snd_ad1848_create(card, mss_port[dev] + 4, xirq, xdma, + AD1848_HW_DETECT, &chip); + if (err < 0) + goto err_unmap2; + card->private_data = chip; + + err = snd_ad1848_pcm(chip, 0, NULL); + if (err < 0) { + snd_printk(KERN_ERR PFX + "error creating new ad1848 PCM device\n"); + goto err_unmap2; + } + err = snd_ad1848_mixer(chip); + if (err < 0) { + snd_printk(KERN_ERR PFX "error creating new ad1848 mixer\n"); + goto err_unmap2; + } + err = snd_sc6000_mixer(chip); + if (err < 0) { + snd_printk(KERN_ERR PFX "the mixer rewrite failed\n"); + goto err_unmap2; + } + if (snd_opl3_create(card, + 0x388, 0x388 + 2, + OPL3_HW_AUTO, 0, &opl3) < 0) { + snd_printk(KERN_ERR PFX "no OPL device at 0x%x-0x%x ?\n", + 0x388, 0x388 + 2); + } else { + err = snd_opl3_timer_new(opl3, 0, 1); + if (err < 0) + goto err_unmap2; + + err = snd_opl3_hwdep_new(opl3, 0, 1, NULL); + if (err < 0) + goto err_unmap2; + } + + if (mpu_port[dev] != SNDRV_AUTO_PORT) { + if (mpu_irq[dev] == SNDRV_AUTO_IRQ) + mpu_irq[dev] = -1; + if (snd_mpu401_uart_new(card, 0, + MPU401_HW_MPU401, + mpu_port[dev], 0, + mpu_irq[dev], IRQF_DISABLED, + NULL) < 0) + snd_printk(KERN_ERR "no MPU-401 device at 0x%lx ?\n", + mpu_port[dev]); + } + + strcpy(card->driver, DRV_NAME); + strcpy(card->shortname, "SC-6000"); + sprintf(card->longname, "Gallant SC-6000 at 0x%lx, irq %d, dma %d", + mss_port[dev], xirq, xdma); + + snd_card_set_dev(card, devptr); + + err = snd_card_register(card); + if (err < 0) + goto err_unmap2; + + dev_set_drvdata(devptr, card); + return 0; + +err_unmap2: + release_region(mss_port[dev], 4); +err_unmap1: + release_region(port[dev], 0x10); +err_exit: + snd_card_free(card); + return err; +} + +static int __devexit snd_sc6000_remove(struct device *devptr, unsigned int dev) +{ + release_region(port[dev], 0x10); + release_region(mss_port[dev], 4); + + snd_card_free(dev_get_drvdata(devptr)); + dev_set_drvdata(devptr, NULL); + return 0; +} + +static struct isa_driver snd_sc6000_driver = { + .match = snd_sc6000_match, + .probe = snd_sc6000_probe, + .remove = __devexit_p(snd_sc6000_remove), + /* FIXME: suspend/resume */ + .driver = { + .name = DRV_NAME, + }, +}; + + +static int __init alsa_card_sc6000_init(void) +{ + return isa_register_driver(&snd_sc6000_driver, SNDRV_CARDS); +} + +static void __exit alsa_card_sc6000_exit(void) +{ + isa_unregister_driver(&snd_sc6000_driver); +} + +module_init(alsa_card_sc6000_init) +module_exit(alsa_card_sc6000_exit) diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c index cbad2a51cbaa..1cb921d6137e 100644 --- a/sound/isa/sscape.c +++ b/sound/isa/sscape.c @@ -45,10 +45,12 @@ MODULE_LICENSE("GPL"); static int index[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_IDX; static char* id[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_STR; -static long port[SNDRV_CARDS] __devinitdata = { [0 ... (SNDRV_CARDS-1)] = SNDRV_AUTO_PORT }; +static long port[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_PORT; +static long wss_port[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_PORT; static int irq[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_IRQ; static int mpu_irq[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_IRQ; static int dma[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_DMA; +static int dma2[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_DMA; module_param_array(index, int, NULL, 0444); MODULE_PARM_DESC(index, "Index number for SoundScape soundcard"); @@ -59,6 +61,9 @@ MODULE_PARM_DESC(id, "Description for SoundScape card"); module_param_array(port, long, NULL, 0444); MODULE_PARM_DESC(port, "Port # for SoundScape driver."); +module_param_array(wss_port, long, NULL, 0444); +MODULE_PARM_DESC(wss_port, "WSS Port # for SoundScape driver."); + module_param_array(irq, int, NULL, 0444); MODULE_PARM_DESC(irq, "IRQ # for SoundScape driver."); @@ -68,12 +73,16 @@ MODULE_PARM_DESC(mpu_irq, "MPU401 IRQ # for SoundScape driver."); module_param_array(dma, int, NULL, 0444); MODULE_PARM_DESC(dma, "DMA # for SoundScape driver."); +module_param_array(dma2, int, NULL, 0444); +MODULE_PARM_DESC(dma2, "DMA2 # for SoundScape driver."); + #ifdef CONFIG_PNP static int isa_registered; static int pnp_registered; static struct pnp_card_device_id sscape_pnpids[] = { - { .id = "ENS3081", .devs = { { "ENS0000" } } }, + { .id = "ENS3081", .devs = { { "ENS0000" } } }, /* Soundscape PnP */ + { .id = "ENS4081", .devs = { { "ENS1011" } } }, /* VIVO90 */ { .id = "" } /* end */ }; @@ -124,12 +133,21 @@ enum GA_REG { #define AD1845_FREQ_SEL_MSB 0x16 #define AD1845_FREQ_SEL_LSB 0x17 +enum card_type { + SSCAPE, + SSCAPE_PNP, + SSCAPE_VIVO, +}; + struct soundscape { spinlock_t lock; unsigned io_base; + unsigned wss_base; int codec_type; int ic_type; + enum card_type type; struct resource *io_res; + struct resource *wss_res; struct snd_cs4231 *chip; struct snd_mpu401 *mpu; struct snd_hwdep *hw; @@ -340,8 +358,9 @@ static inline void activate_ad1845_unsafe(unsigned io_base) */ static void soundscape_free(struct snd_card *c) { - register struct soundscape *sscape = get_card_soundscape(c); + struct soundscape *sscape = get_card_soundscape(c); release_and_free_resource(sscape->io_res); + release_and_free_resource(sscape->wss_res); free_dma(sscape->chip->dma1); } @@ -382,7 +401,7 @@ static int obp_startup_ack(struct soundscape *s, unsigned timeout) unsigned long flags; unsigned char x; - schedule_timeout(1); + schedule_timeout_uninterruptible(1); spin_lock_irqsave(&s->lock, flags); x = inb(HOST_DATA_IO(s->io_base)); @@ -409,7 +428,7 @@ static int host_startup_ack(struct soundscape *s, unsigned timeout) unsigned long flags; unsigned char x; - schedule_timeout(1); + schedule_timeout_uninterruptible(1); spin_lock_irqsave(&s->lock, flags); x = inb(HOST_DATA_IO(s->io_base)); @@ -522,7 +541,7 @@ static int upload_dma_data(struct soundscape *s, ret = -EAGAIN; } - _release_dma: +_release_dma: /* * NOTE!!! We are NOT holding any spinlocks at this point !!! */ @@ -802,6 +821,7 @@ static int __devinit detect_sscape(struct soundscape *s) unsigned long flags; unsigned d; int retval = 0; + int codec = s->wss_base; spin_lock_irqsave(&s->lock, flags); @@ -833,9 +853,27 @@ static int __devinit detect_sscape(struct soundscape *s) outb(0xfe, ODIE_ADDR_IO(s->io_base)); if ((inb(ODIE_ADDR_IO(s->io_base)) & 0x9f) != 0x0e) goto _done; - if ((inb(ODIE_DATA_IO(s->io_base)) & 0x9f) != 0x0e) + + outb(0xfe, ODIE_ADDR_IO(s->io_base)); + d = inb(ODIE_DATA_IO(s->io_base)); + if (s->type != SSCAPE_VIVO && (d & 0x9f) != 0x0e) goto _done; + d = sscape_read_unsafe(s->io_base, GA_HMCTL_REG) & 0x3f; + sscape_write_unsafe(s->io_base, GA_HMCTL_REG, d | 0xc0); + + if (s->type == SSCAPE_VIVO) + codec += 4; + /* wait for WSS codec */ + for (d = 0; d < 500; d++) { + if ((inb(codec) & 0x80) == 0) + break; + spin_unlock_irqrestore(&s->lock, flags); + msleep(1); + spin_lock_irqsave(&s->lock, flags); + } + snd_printd(KERN_INFO "init delay = %d ms\n", d); + /* * SoundScape successfully detected! */ @@ -995,21 +1033,23 @@ static void ad1845_capture_format(struct snd_cs4231 * chip, struct snd_pcm_hw_pa * try to support at least some of the extra bits by overriding * some of the CS4231 callback. */ -static int __devinit create_ad1845(struct snd_card *card, unsigned port, int irq, int dma1) +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; int err; -#define CS4231_SHARE_HARDWARE (CS4231_HWSHARE_DMA1 | CS4231_HWSHARE_DMA2) - /* - * The AD1845 PCM device is only half-duplex, and so - * we only give it one DMA channel ... - */ - if ((err = snd_cs4231_create(card, - port, -1, irq, dma1, dma1, - CS4231_HW_DETECT, - CS4231_HWSHARE_DMA1, &chip)) == 0) { + if (sscape->type == SSCAPE_VIVO) + port += 4; + + if (dma1 == dma2) + dma2 = -1; + + err = snd_cs4231_create(card, + port, -1, irq, dma1, dma2, + CS4231_HW_DETECT, CS4231_HWSHARE_DMA1, &chip); + if (!err) { unsigned long flags; struct snd_pcm *pcm; @@ -1031,49 +1071,72 @@ static int __devinit create_ad1845(struct snd_card *card, unsigned port, int irq snd_cs4231_mce_down(chip); */ - /* - * The input clock frequency on the SoundScape must - * be 14.31818 MHz, because we must set this register - * to get the playback to sound correct ... - */ - snd_cs4231_mce_up(chip); - spin_lock_irqsave(&chip->reg_lock, flags); - snd_cs4231_out(chip, AD1845_CRYS_CLOCK_SEL, 0x20); - spin_unlock_irqrestore(&chip->reg_lock, flags); - snd_cs4231_mce_down(chip); + if (sscape->type != SSCAPE_VIVO) { + int val; + /* + * The input clock frequency on the SoundScape must + * be 14.31818 MHz, because we must set this register + * to get the playback to sound correct ... + */ + snd_cs4231_mce_up(chip); + spin_lock_irqsave(&chip->reg_lock, flags); + snd_cs4231_out(chip, AD1845_CRYS_CLOCK_SEL, 0x20); + spin_unlock_irqrestore(&chip->reg_lock, flags); + snd_cs4231_mce_down(chip); - /* - * More custom configuration: - * a) select "mode 2", and provide a current drive of 8 mA - * b) enable frequency selection (for capture/playback) - */ - spin_lock_irqsave(&chip->reg_lock, flags); - snd_cs4231_out(chip, CS4231_MISC_INFO, (CS4231_MODE2 | 0x10)); - snd_cs4231_out(chip, AD1845_PWR_DOWN_CTRL, snd_cs4231_in(chip, AD1845_PWR_DOWN_CTRL) | AD1845_FREQ_SEL_ENABLE); - spin_unlock_irqrestore(&chip->reg_lock, flags); + /* + * More custom configuration: + * a) select "mode 2" and provide a current drive of 8mA + * 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); + spin_unlock_irqrestore(&chip->reg_lock, flags); + } - if ((err = snd_cs4231_pcm(chip, 0, &pcm)) < 0) { - snd_printk(KERN_ERR "sscape: No PCM device for AD1845 chip\n"); + err = snd_cs4231_pcm(chip, 0, &pcm); + if (err < 0) { + snd_printk(KERN_ERR "sscape: No PCM device " + "for AD1845 chip\n"); goto _error; } - if ((err = snd_cs4231_mixer(chip)) < 0) { - snd_printk(KERN_ERR "sscape: No mixer device for AD1845 chip\n"); + err = snd_cs4231_mixer(chip); + if (err < 0) { + snd_printk(KERN_ERR "sscape: No mixer device " + "for AD1845 chip\n"); goto _error; } - - if ((err = snd_ctl_add(card, snd_ctl_new1(&midi_mixer_ctl, chip))) < 0) { - snd_printk(KERN_ERR "sscape: Could not create MIDI mixer control\n"); + err = snd_cs4231_timer(chip, 0, NULL); + if (err < 0) { + snd_printk(KERN_ERR "sscape: No timer device " + "for AD1845 chip\n"); goto _error; } + if (sscape->type != SSCAPE_VIVO) { + err = snd_ctl_add(card, + snd_ctl_new1(&midi_mixer_ctl, chip)); + if (err < 0) { + snd_printk(KERN_ERR "sscape: Could not create " + "MIDI mixer control\n"); + goto _error; + } + chip->set_playback_format = ad1845_playback_format; + chip->set_capture_format = ad1845_capture_format; + } + strcpy(card->driver, "SoundScape"); strcpy(card->shortname, pcm->name); snprintf(card->longname, sizeof(card->longname), - "%s at 0x%lx, IRQ %d, DMA %d\n", - pcm->name, chip->port, chip->irq, chip->dma1); - chip->set_playback_format = ad1845_playback_format; - chip->set_capture_format = ad1845_capture_format; + "%s at 0x%lx, IRQ %d, DMA1 %d, DMA2 %d\n", + pcm->name, chip->port, chip->irq, + chip->dma1, chip->dma2); + sscape->chip = chip; } @@ -1086,15 +1149,15 @@ static int __devinit create_ad1845(struct snd_card *card, unsigned port, int irq * Create an ALSA soundcard entry for the SoundScape, using * the given list of port, IRQ and DMA resources. */ -static int __devinit create_sscape(int dev, struct snd_card **rcardp) +static int __devinit create_sscape(int dev, struct snd_card *card) { - struct snd_card *card; - register struct soundscape *sscape; - register unsigned dma_cfg; + struct soundscape *sscape = get_card_soundscape(card); + unsigned dma_cfg; unsigned irq_cfg; unsigned mpu_irq_cfg; unsigned xport; struct resource *io_res; + struct resource *wss_res; unsigned long flags; int err; @@ -1118,61 +1181,69 @@ static int __devinit create_sscape(int dev, struct snd_card **rcardp) * Grab IO ports that we will need to probe so that we * can detect and control this hardware ... */ - if ((io_res = request_region(xport, 8, "SoundScape")) == NULL) { + io_res = request_region(xport, 8, "SoundScape"); + if (!io_res) { snd_printk(KERN_ERR "sscape: can't grab port 0x%x\n", xport); return -EBUSY; } + wss_res = NULL; + if (sscape->type == SSCAPE_VIVO) { + wss_res = request_region(wss_port[dev], 4, "SoundScape"); + if (!wss_res) { + snd_printk(KERN_ERR "sscape: can't grab port 0x%lx\n", + wss_port[dev]); + err = -EBUSY; + goto _release_region; + } + } /* - * Grab both DMA channels (OK, only one for now) ... + * Grab one DMA channel ... */ - if ((err = request_dma(dma[dev], "SoundScape")) < 0) { + err = request_dma(dma[dev], "SoundScape"); + if (err < 0) { snd_printk(KERN_ERR "sscape: can't grab DMA %d\n", dma[dev]); goto _release_region; } - /* - * Create a new ALSA sound card entry, in anticipation - * of detecting our hardware ... - */ - if ((card = snd_card_new(index[dev], id[dev], THIS_MODULE, - sizeof(struct soundscape))) == NULL) { - err = -ENOMEM; - goto _release_dma; - } - - sscape = get_card_soundscape(card); spin_lock_init(&sscape->lock); spin_lock_init(&sscape->fwlock); sscape->io_res = io_res; + sscape->wss_res = wss_res; sscape->io_base = xport; + sscape->wss_base = wss_port[dev]; if (!detect_sscape(sscape)) { printk(KERN_ERR "sscape: hardware not detected at 0x%x\n", sscape->io_base); err = -ENODEV; - goto _release_card; + goto _release_dma; } printk(KERN_INFO "sscape: hardware detected at 0x%x, using IRQ %d, DMA %d\n", - sscape->io_base, irq[dev], dma[dev]); + sscape->io_base, irq[dev], dma[dev]); - /* - * Now create the hardware-specific device so that we can - * load the microcode into the on-board processor. - * We cannot use the MPU-401 MIDI system until this firmware - * has been loaded into the card. - */ - if ((err = snd_hwdep_new(card, "MC68EC000", 0, &(sscape->hw))) < 0) { - printk(KERN_ERR "sscape: Failed to create firmware device\n"); - goto _release_card; + if (sscape->type != SSCAPE_VIVO) { + /* + * Now create the hardware-specific device so that we can + * load the microcode into the on-board processor. + * We cannot use the MPU-401 MIDI system until this firmware + * has been loaded into the card. + */ + err = snd_hwdep_new(card, "MC68EC000", 0, &(sscape->hw)); + if (err < 0) { + printk(KERN_ERR "sscape: Failed to create " + "firmware device\n"); + goto _release_dma; + } + strlcpy(sscape->hw->name, "SoundScape M68K", + sizeof(sscape->hw->name)); + sscape->hw->name[sizeof(sscape->hw->name) - 1] = '\0'; + sscape->hw->iface = SNDRV_HWDEP_IFACE_SSCAPE; + sscape->hw->ops.open = sscape_hw_open; + sscape->hw->ops.release = sscape_hw_release; + sscape->hw->ops.ioctl = sscape_hw_ioctl; + sscape->hw->private_data = sscape; } - strlcpy(sscape->hw->name, "SoundScape M68K", sizeof(sscape->hw->name)); - sscape->hw->name[sizeof(sscape->hw->name) - 1] = '\0'; - sscape->hw->iface = SNDRV_HWDEP_IFACE_SSCAPE; - sscape->hw->ops.open = sscape_hw_open; - sscape->hw->ops.release = sscape_hw_release; - sscape->hw->ops.ioctl = sscape_hw_ioctl; - sscape->hw->private_data = sscape; /* * Tell the on-board devices where their resources are (I think - @@ -1197,7 +1268,8 @@ static int __devinit create_sscape(int dev, struct snd_card **rcardp) sscape_write_unsafe(sscape->io_base, GA_INTCFG_REG, 0xf0 | (mpu_irq_cfg << 2) | mpu_irq_cfg); sscape_write_unsafe(sscape->io_base, - GA_CDCFG_REG, 0x09 | DMA_8BIT | (dma[dev] << 4) | (irq_cfg << 1)); + GA_CDCFG_REG, 0x09 | DMA_8BIT + | (dma[dev] << 4) | (irq_cfg << 1)); spin_unlock_irqrestore(&sscape->lock, flags); @@ -1205,30 +1277,37 @@ static int __devinit create_sscape(int dev, struct snd_card **rcardp) * We have now enabled the codec chip, and so we should * detect the AD1845 device ... */ - if ((err = create_ad1845(card, CODEC_IO(xport), irq[dev], dma[dev])) < 0) { - printk(KERN_ERR "sscape: No AD1845 device at 0x%x, IRQ %d\n", - CODEC_IO(xport), irq[dev]); - goto _release_card; + err = create_ad1845(card, wss_port[dev], irq[dev], + dma[dev], dma2[dev]); + if (err < 0) { + printk(KERN_ERR "sscape: No AD1845 device at 0x%lx, IRQ %d\n", + wss_port[dev], irq[dev]); + goto _release_dma; } #define MIDI_DEVNUM 0 - if ((err = create_mpu401(card, MIDI_DEVNUM, MPU401_IO(xport), mpu_irq[dev])) < 0) { - printk(KERN_ERR "sscape: Failed to create MPU-401 device at 0x%x\n", - MPU401_IO(xport)); - goto _release_card; - } + if (sscape->type != SSCAPE_VIVO) { + err = create_mpu401(card, MIDI_DEVNUM, + MPU401_IO(xport), mpu_irq[dev]); + if (err < 0) { + printk(KERN_ERR "sscape: Failed to create " + "MPU-401 device at 0x%x\n", + MPU401_IO(xport)); + goto _release_dma; + } - /* - * Enable the master IRQ ... - */ - sscape_write(sscape, GA_INTENA_REG, 0x80); + /* + * Enable the master IRQ ... + */ + sscape_write(sscape, GA_INTENA_REG, 0x80); - /* - * Initialize mixer - */ - sscape->midi_vol = 0; - host_write_ctrl_unsafe(sscape->io_base, CMD_SET_MIDI_VOL, 100); - host_write_ctrl_unsafe(sscape->io_base, 0, 100); - host_write_ctrl_unsafe(sscape->io_base, CMD_XXX_MIDI_VOL, 100); + /* + * Initialize mixer + */ + sscape->midi_vol = 0; + host_write_ctrl_unsafe(sscape->io_base, CMD_SET_MIDI_VOL, 100); + host_write_ctrl_unsafe(sscape->io_base, 0, 100); + host_write_ctrl_unsafe(sscape->io_base, CMD_XXX_MIDI_VOL, 100); + } /* * Now that we have successfully created this sound card, @@ -1237,17 +1316,14 @@ static int __devinit create_sscape(int dev, struct snd_card **rcardp) * function now that our "constructor" has completed. */ card->private_free = soundscape_free; - *rcardp = card; return 0; - _release_card: - snd_card_free(card); - - _release_dma: +_release_dma: free_dma(dma[dev]); - _release_region: +_release_region: + release_and_free_resource(wss_res); release_and_free_resource(io_res); return err; @@ -1276,19 +1352,33 @@ static int __devinit snd_sscape_match(struct device *pdev, unsigned int i) static int __devinit snd_sscape_probe(struct device *pdev, unsigned int dev) { struct snd_card *card; + struct soundscape *sscape; int ret; + card = snd_card_new(index[dev], id[dev], THIS_MODULE, + sizeof(struct soundscape)); + if (!card) + return -ENOMEM; + + sscape = get_card_soundscape(card); + sscape->type = SSCAPE; + dma[dev] &= 0x03; - ret = create_sscape(dev, &card); + ret = create_sscape(dev, card); if (ret < 0) - return ret; + goto _release_card; + snd_card_set_dev(card, pdev); if ((ret = snd_card_register(card)) < 0) { printk(KERN_ERR "sscape: Failed to register sound card\n"); - return ret; + goto _release_card; } dev_set_drvdata(pdev, card); return 0; + +_release_card: + snd_card_free(card); + return ret; } static int __devexit snd_sscape_remove(struct device *devptr, unsigned int dev) @@ -1325,6 +1415,7 @@ static int __devinit sscape_pnp_detect(struct pnp_card_link *pcard, static int idx = 0; struct pnp_dev *dev; struct snd_card *card; + struct soundscape *sscape; int ret; /* @@ -1366,26 +1457,55 @@ static int __devinit sscape_pnp_detect(struct pnp_card_link *pcard, } /* + * Create a new ALSA sound card entry, in anticipation + * of detecting our hardware ... + */ + card = snd_card_new(index[idx], id[idx], THIS_MODULE, + sizeof(struct soundscape)); + if (!card) + return -ENOMEM; + + sscape = get_card_soundscape(card); + + /* + * Identify card model ... + */ + if (!strncmp("ENS4081", pid->id, 7)) + sscape->type = SSCAPE_VIVO; + else + sscape->type = SSCAPE_PNP; + + /* * Read the correct parameters off the ISA PnP bus ... */ port[idx] = pnp_port_start(dev, 0); irq[idx] = pnp_irq(dev, 0); mpu_irq[idx] = pnp_irq(dev, 1); dma[idx] = pnp_dma(dev, 0) & 0x03; + if (sscape->type == SSCAPE_PNP) { + dma2[idx] = dma[idx]; + wss_port[idx] = CODEC_IO(port[idx]); + } else { + wss_port[idx] = pnp_port_start(dev, 1); + dma2[idx] = pnp_dma(dev, 1); + } - ret = create_sscape(idx, &card); + ret = create_sscape(idx, card); if (ret < 0) - return ret; + goto _release_card; + snd_card_set_dev(card, &pcard->card->dev); if ((ret = snd_card_register(card)) < 0) { printk(KERN_ERR "sscape: Failed to register sound card\n"); - snd_card_free(card); - return ret; + goto _release_card; } pnp_set_card_drvdata(pcard, card); ++idx; + return 0; +_release_card: + snd_card_free(card); return ret; } diff --git a/sound/isa/wavefront/Makefile b/sound/isa/wavefront/Makefile index b4cb28422db0..601bdddd44d0 100644 --- a/sound/isa/wavefront/Makefile +++ b/sound/isa/wavefront/Makefile @@ -1,6 +1,6 @@ # # Makefile for ALSA -# Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz> +# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz> # snd-wavefront-objs := wavefront.o wavefront_fx.o wavefront_synth.o wavefront_midi.o diff --git a/sound/isa/wavefront/wavefront_synth.c b/sound/isa/wavefront/wavefront_synth.c index bacc51c86587..a1ebb7c5c684 100644 --- a/sound/isa/wavefront/wavefront_synth.c +++ b/sound/isa/wavefront/wavefront_synth.c @@ -27,6 +27,7 @@ #include <linux/delay.h> #include <linux/time.h> #include <linux/wait.h> +#include <linux/firmware.h> #include <linux/moduleparam.h> #include <sound/core.h> #include <sound/snd_wavefront.h> @@ -53,9 +54,8 @@ static int debug_default = 0; /* you can set this to control debugging /* XXX this needs to be made firmware and hardware version dependent */ -static char *ospath = "/etc/sound/wavefront.os"; /* where to find a processed - version of the WaveFront OS - */ +#define DEFAULT_OSPATH "wavefront.os" +static char *ospath = DEFAULT_OSPATH; /* the firmware file name */ static int wait_usecs = 150; /* This magic number seems to give pretty optimal throughput based on my limited experimentation. @@ -97,7 +97,7 @@ MODULE_PARM_DESC(sleep_interval, "how long to sleep when waiting for reply"); module_param(sleep_tries, int, 0444); MODULE_PARM_DESC(sleep_tries, "how many times to try sleeping during a wait"); module_param(ospath, charp, 0444); -MODULE_PARM_DESC(ospath, "full pathname to processed ICS2115 OS firmware"); +MODULE_PARM_DESC(ospath, "pathname to processed ICS2115 OS firmware"); module_param(reset_time, int, 0444); MODULE_PARM_DESC(reset_time, "how long to wait for a reset to take effect"); module_param(ramcheck_time, int, 0444); @@ -1768,7 +1768,7 @@ snd_wavefront_interrupt_bits (int irq) static void __devinit wavefront_should_cause_interrupt (snd_wavefront_t *dev, - int val, int port, int timeout) + int val, int port, unsigned long timeout) { wait_queue_t wait; @@ -1779,11 +1779,9 @@ wavefront_should_cause_interrupt (snd_wavefront_t *dev, dev->irq_ok = 0; outb (val,port); spin_unlock_irq(&dev->irq_lock); - while (1) { - if ((timeout = schedule_timeout(timeout)) == 0) - return; - if (dev->irq_ok) - return; + while (!dev->irq_ok && time_before(jiffies, timeout)) { + schedule_timeout_uninterruptible(1); + barrier(); } } @@ -1938,111 +1936,75 @@ wavefront_reset_to_cleanliness (snd_wavefront_t *dev) return (1); } -#include <linux/fs.h> -#include <linux/mm.h> -#include <linux/slab.h> -#include <linux/unistd.h> -#include <linux/syscalls.h> -#include <asm/uaccess.h> - - static int __devinit wavefront_download_firmware (snd_wavefront_t *dev, char *path) { - unsigned char section[WF_SECTION_MAX]; - signed char section_length; /* yes, just a char; max value is WF_SECTION_MAX */ + unsigned char *buf; + int len, err; int section_cnt_downloaded = 0; - int fd; - int c; - int i; - mm_segment_t fs; - - /* This tries to be a bit cleverer than the stuff Alan Cox did for - the generic sound firmware, in that it actually knows - something about the structure of the Motorola firmware. In - particular, it uses a version that has been stripped of the - 20K of useless header information, and had section lengths - added, making it possible to load the entire OS without any - [kv]malloc() activity, since the longest entity we ever read is - 42 bytes (well, WF_SECTION_MAX) long. - */ - - fs = get_fs(); - set_fs (get_ds()); + const struct firmware *firmware; - if ((fd = sys_open ((char __user *) path, 0, 0)) < 0) { - snd_printk ("Unable to load \"%s\".\n", - path); + err = request_firmware(&firmware, path, dev->card->dev); + if (err < 0) { + snd_printk(KERN_ERR "firmware (%s) download failed!!!\n", path); return 1; } - while (1) { - int x; - - if ((x = sys_read (fd, (char __user *) §ion_length, sizeof (section_length))) != - sizeof (section_length)) { - snd_printk ("firmware read error.\n"); - goto failure; - } - - if (section_length == 0) { + len = 0; + buf = firmware->data; + for (;;) { + int section_length = *(signed char *)buf; + if (section_length == 0) break; - } - if (section_length < 0 || section_length > WF_SECTION_MAX) { - snd_printk ("invalid firmware section length %d\n", - section_length); + snd_printk(KERN_ERR + "invalid firmware section length %d\n", + section_length); goto failure; } + buf++; + len++; - if (sys_read (fd, (char __user *) section, section_length) != section_length) { - snd_printk ("firmware section " - "read error.\n"); + if (firmware->size < len + section_length) { + snd_printk(KERN_ERR "firmware section read error.\n"); goto failure; } /* Send command */ - - if (wavefront_write (dev, WFC_DOWNLOAD_OS)) { + if (wavefront_write(dev, WFC_DOWNLOAD_OS)) goto failure; - } - for (i = 0; i < section_length; i++) { - if (wavefront_write (dev, section[i])) { + for (; section_length; section_length--) { + if (wavefront_write(dev, *buf)) goto failure; - } + buf++; + len++; } /* get ACK */ - - if (wavefront_wait (dev, STAT_CAN_READ)) { - - if ((c = inb (dev->data_port)) != WF_ACK) { - - snd_printk ("download " - "of section #%d not " - "acknowledged, ack = 0x%x\n", - section_cnt_downloaded + 1, c); - goto failure; - - } - - } else { - snd_printk ("time out for firmware ACK.\n"); + if (!wavefront_wait(dev, STAT_CAN_READ)) { + snd_printk(KERN_ERR "time out for firmware ACK.\n"); + goto failure; + } + err = inb(dev->data_port); + if (err != WF_ACK) { + snd_printk(KERN_ERR + "download of section #%d not " + "acknowledged, ack = 0x%x\n", + section_cnt_downloaded + 1, err); goto failure; } + section_cnt_downloaded++; } - sys_close (fd); - set_fs (fs); + release_firmware(firmware); return 0; failure: - sys_close (fd); - set_fs (fs); - snd_printk ("firmware download failed!!!\n"); + release_firmware(firmware); + snd_printk(KERN_ERR "firmware download failed!!!\n"); return 1; } @@ -2232,3 +2194,5 @@ snd_wavefront_detect (snd_wavefront_card_t *card) return 0; } + +MODULE_FIRMWARE(DEFAULT_OSPATH); |