diff options
Diffstat (limited to 'sound')
325 files changed, 10561 insertions, 17070 deletions
diff --git a/sound/Kconfig b/sound/Kconfig index e48b9b37d22..b2a2db47aff 100644 --- a/sound/Kconfig +++ b/sound/Kconfig @@ -63,6 +63,10 @@ source "sound/aoa/Kconfig" source "sound/arm/Kconfig" +if SPI +source "sound/spi/Kconfig" +endif + source "sound/mips/Kconfig" source "sound/sh/Kconfig" diff --git a/sound/Makefile b/sound/Makefile index 3ead922bd9c..c76d70716fa 100644 --- a/sound/Makefile +++ b/sound/Makefile @@ -5,7 +5,8 @@ obj-$(CONFIG_SOUND) += soundcore.o obj-$(CONFIG_SOUND_PRIME) += sound_firmware.o obj-$(CONFIG_SOUND_PRIME) += oss/ obj-$(CONFIG_DMASOUND) += oss/ -obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ sh/ synth/ usb/ sparc/ parisc/ pcmcia/ mips/ soc/ +obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ sh/ synth/ usb/ \ + sparc/ spi/ parisc/ pcmcia/ mips/ soc/ obj-$(CONFIG_SND_AOA) += aoa/ # This one must be compilable even if sound is configured out diff --git a/sound/aoa/codecs/snd-aoa-codec-onyx.c b/sound/aoa/codecs/snd-aoa-codec-onyx.c index 028852374f2..71e3f936065 100644 --- a/sound/aoa/codecs/snd-aoa-codec-onyx.c +++ b/sound/aoa/codecs/snd-aoa-codec-onyx.c @@ -297,15 +297,7 @@ static struct snd_kcontrol_new capture_source_control = { .put = onyx_snd_capture_source_put, }; -static int onyx_snd_mute_info(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 onyx_snd_mute_info snd_ctl_boolean_stereo_info static int onyx_snd_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -359,15 +351,7 @@ static struct snd_kcontrol_new mute_control = { }; -static int onyx_snd_single_bit_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 onyx_snd_single_bit_info snd_ctl_boolean_mono_info #define FLAG_POLARITY_INVERT 1 #define FLAG_SPDIFLOCK 2 diff --git a/sound/aoa/codecs/snd-aoa-codec-tas.c b/sound/aoa/codecs/snd-aoa-codec-tas.c index 2f771f57c76..70c34168479 100644 --- a/sound/aoa/codecs/snd-aoa-codec-tas.c +++ b/sound/aoa/codecs/snd-aoa-codec-tas.c @@ -272,15 +272,7 @@ static struct snd_kcontrol_new volume_control = { .put = tas_snd_vol_put, }; -static int tas_snd_mute_info(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 tas_snd_mute_info snd_ctl_boolean_stereo_info static int tas_snd_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -431,15 +423,7 @@ static struct snd_kcontrol_new drc_range_control = { .put = tas_snd_drc_range_put, }; -static int tas_snd_drc_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 tas_snd_drc_switch_info snd_ctl_boolean_mono_info static int tas_snd_drc_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -743,6 +727,7 @@ static int tas_switch_clock(struct codec_info_item *cii, enum clock_switch clock return 0; } +#ifdef CONFIG_PM /* we are controlled via i2c and assume that is always up * If that wasn't the case, we'd have to suspend once * our i2c device is suspended, and then take note of that! */ @@ -768,7 +753,6 @@ static int tas_resume(struct tas *tas) return 0; } -#ifdef CONFIG_PM static int _tas_suspend(struct codec_info_item *cii, pm_message_t state) { return tas_suspend(cii->codec_data); @@ -778,7 +762,10 @@ static int _tas_resume(struct codec_info_item *cii) { return tas_resume(cii->codec_data); } -#endif +#else /* CONFIG_PM */ +#define _tas_suspend NULL +#define _tas_resume NULL +#endif /* CONFIG_PM */ static struct codec_info tas_codec_info = { .transfers = tas_transfers, @@ -791,10 +778,8 @@ static struct codec_info tas_codec_info = { .owner = THIS_MODULE, .usable = tas_usable, .switch_clock = tas_switch_clock, -#ifdef CONFIG_PM .suspend = _tas_suspend, .resume = _tas_resume, -#endif }; static int tas_init_codec(struct aoa_codec *codec) diff --git a/sound/aoa/fabrics/snd-aoa-fabric-layout.c b/sound/aoa/fabrics/snd-aoa-fabric-layout.c index 98806283d1b..8b2ba99d7f8 100644 --- a/sound/aoa/fabrics/snd-aoa-fabric-layout.c +++ b/sound/aoa/fabrics/snd-aoa-fabric-layout.c @@ -582,15 +582,7 @@ static int layouts_list_items; * make the fabric handle all the card stuff, etc... */ static struct layout_dev *layout_device; -static int control_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 control_info snd_ctl_boolean_mono_info #define AMP_CONTROL(n, description) \ static int n##_control_get(struct snd_kcontrol *kcontrol, \ diff --git a/sound/aoa/soundbus/core.c b/sound/aoa/soundbus/core.c index 64d16391433..f84f3e50578 100644 --- a/sound/aoa/soundbus/core.c +++ b/sound/aoa/soundbus/core.c @@ -56,13 +56,12 @@ static int soundbus_probe(struct device *dev) } -static int soundbus_uevent(struct device *dev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int soundbus_uevent(struct device *dev, struct kobj_uevent_env *env) { struct soundbus_dev * soundbus_dev; struct of_device * of; const char *compat; - int retval = 0, i = 0, length = 0; + int retval = 0; int cplen, seen = 0; if (!dev) @@ -75,15 +74,11 @@ static int soundbus_uevent(struct device *dev, char **envp, int num_envp, of = &soundbus_dev->ofdev; /* stuff we want to pass to /sbin/hotplug */ - retval = add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "OF_NAME=%s", of->node->name); + retval = add_uevent_var(env, "OF_NAME=%s", of->node->name); if (retval) return retval; - retval = add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "OF_TYPE=%s", of->node->type); + retval = add_uevent_var(env, "OF_TYPE=%s", of->node->type); if (retval) return retval; @@ -93,27 +88,19 @@ static int soundbus_uevent(struct device *dev, char **envp, int num_envp, compat = of_get_property(of->node, "compatible", &cplen); while (compat && cplen > 0) { - int tmp = length; - retval = add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "OF_COMPATIBLE_%d=%s", seen, compat); + int tmp = env->buflen; + retval = add_uevent_var(env, "OF_COMPATIBLE_%d=%s", seen, compat); if (retval) return retval; - compat += length - tmp; - cplen -= length - tmp; + compat += env->buflen - tmp; + cplen -= env->buflen - tmp; seen += 1; } - retval = add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "OF_COMPATIBLE_N=%d", seen); + retval = add_uevent_var(env, "OF_COMPATIBLE_N=%d", seen); if (retval) return retval; - retval = add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "MODALIAS=%s", soundbus_dev->modalias); - - envp[i] = NULL; + retval = add_uevent_var(env, "MODALIAS=%s", soundbus_dev->modalias); return retval; } diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c index b9eca9f3dd2..3b73ba7d03e 100644 --- a/sound/arm/aaci.c +++ b/sound/arm/aaci.c @@ -209,7 +209,7 @@ static void aaci_fifo_irq(struct aaci *aaci, int channel, u32 mask) void *ptr; if (!aacirun->substream || !aacirun->start) { - dev_warn(&aaci->dev->dev, "RX interrupt???"); + dev_warn(&aaci->dev->dev, "RX interrupt???\n"); writel(0, aacirun->base + AACI_IE); return; } @@ -263,7 +263,7 @@ static void aaci_fifo_irq(struct aaci *aaci, int channel, u32 mask) void *ptr; if (!aacirun->substream || !aacirun->start) { - dev_warn(&aaci->dev->dev, "TX interrupt???"); + dev_warn(&aaci->dev->dev, "TX interrupt???\n"); writel(0, aacirun->base + AACI_IE); return; } diff --git a/sound/arm/sa11xx-uda1341.c b/sound/arm/sa11xx-uda1341.c index e7ed868fa7c..81c64b09d35 100644 --- a/sound/arm/sa11xx-uda1341.c +++ b/sound/arm/sa11xx-uda1341.c @@ -79,12 +79,6 @@ #include <asm/mach-types.h> #include <asm/dma.h> -#ifdef CONFIG_H3600_HAL -#include <asm/semaphore.h> -#include <asm/uaccess.h> -#include <asm/arch/h3600_hal.h> -#endif - #include <sound/core.h> #include <sound/pcm.h> #include <sound/initval.h> @@ -100,9 +94,6 @@ * We use DMA stuff from 2.4.18-rmk3-hh24 here to be able to compile this * module for Familiar 0.6.1 */ -#ifdef CONFIG_H3600_HAL -#define HH_VERSION 1 -#endif /* {{{ Type definitions */ @@ -238,11 +229,8 @@ static void sa11xx_uda1341_set_samplerate(struct sa11xx_uda1341 *sa11xx_uda1341, rate = 8000; /* Set the external clock generator */ -#ifdef CONFIG_H3600_HAL - h3600_audio_clock(rate); -#else + sa11xx_uda1341_set_audio_clock(rate); -#endif /* Select the clock divisor */ switch (rate) { @@ -307,13 +295,10 @@ static void sa11xx_uda1341_audio_init(struct sa11xx_uda1341 *sa11xx_uda1341) local_irq_restore(flags); /* Enable the audio power */ -#ifdef CONFIG_H3600_HAL - h3600_audio_power(AUDIO_RATE_DEFAULT); -#else + clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_CODEC_NRESET); set_sa11xx_uda1341_egpio(IPAQ_EGPIO_AUDIO_ON); set_sa11xx_uda1341_egpio(IPAQ_EGPIO_QMUTE); -#endif /* Wait for the UDA1341 to wake up */ mdelay(1); //FIXME - was removed by Perex - Why? @@ -331,21 +316,13 @@ static void sa11xx_uda1341_audio_init(struct sa11xx_uda1341 *sa11xx_uda1341) /* make the left and right channels unswapped (flip the WS latch) */ Ser4SSDR = 0; -#ifdef CONFIG_H3600_HAL - h3600_audio_mute(0); -#else - clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_QMUTE); -#endif + clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_QMUTE); } static void sa11xx_uda1341_audio_shutdown(struct sa11xx_uda1341 *sa11xx_uda1341) { /* mute on */ -#ifdef CONFIG_H3600_HAL - h3600_audio_mute(1); -#else set_sa11xx_uda1341_egpio(IPAQ_EGPIO_QMUTE); -#endif /* disable the audio power and all signals leading to the audio chip */ l3_close(sa11xx_uda1341->uda1341); @@ -354,13 +331,9 @@ static void sa11xx_uda1341_audio_shutdown(struct sa11xx_uda1341 *sa11xx_uda1341) /* power off and mute off */ /* FIXME - is muting off necesary??? */ -#ifdef CONFIG_H3600_HAL - h3600_audio_power(0); - h3600_audio_mute(0); -#else + clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_AUDIO_ON); clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_QMUTE); -#endif } /* }}} */ diff --git a/sound/core/Makefile b/sound/core/Makefile index 5a01c76d02e..267039a97bd 100644 --- a/sound/core/Makefile +++ b/sound/core/Makefile @@ -1,20 +1,17 @@ # # Makefile for ALSA -# Copyright (c) 1999,2001 by Jaroslav Kysela <perex@suse.cz> +# Copyright (c) 1999,2001 by Jaroslav Kysela <perex@perex.cz> # -snd-objs := sound.o init.o memory.o info.o control.o misc.o device.o -ifeq ($(CONFIG_ISA_DMA_API),y) -snd-objs += isadma.o -endif -ifeq ($(CONFIG_SND_OSSEMUL),y) -snd-objs += sound_oss.o info_oss.o -endif +snd-y := sound.o init.o memory.o info.o control.o misc.o device.o +snd-$(CONFIG_ISA_DMA_API) += isadma.o +snd-$(CONFIG_SND_OSSEMUL) += sound_oss.o info_oss.o snd-pcm-objs := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \ pcm_memory.o -snd-page-alloc-objs := memalloc.o sgbuf.o +snd-page-alloc-y := memalloc.o +snd-page-alloc-$(CONFIG_HAS_DMA) += sgbuf.o snd-rawmidi-objs := rawmidi.o snd-timer-objs := timer.o diff --git a/sound/core/control.c b/sound/core/control.c index 1f1ab9c1b66..4c3aa8e1037 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -1,6 +1,6 @@ /* * Routines for driver control interface - * 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 @@ -716,8 +716,6 @@ int snd_ctl_elem_read(struct snd_card *card, struct snd_ctl_elem_value *control) return result; } -EXPORT_SYMBOL(snd_ctl_elem_read); - static int snd_ctl_elem_read_user(struct snd_card *card, struct snd_ctl_elem_value __user *_control) { @@ -781,8 +779,6 @@ int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file, return result; } -EXPORT_SYMBOL(snd_ctl_elem_write); - static int snd_ctl_elem_write_user(struct snd_ctl_file *file, struct snd_ctl_elem_value __user *_control) { @@ -1486,3 +1482,30 @@ int snd_ctl_create(struct snd_card *card) snd_assert(card != NULL, return -ENXIO); return snd_device_new(card, SNDRV_DEV_CONTROL, card, &ops); } + +/* + * Frequently used control callbacks + */ +int snd_ctl_boolean_mono_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; +} + +EXPORT_SYMBOL(snd_ctl_boolean_mono_info); + +int snd_ctl_boolean_stereo_info(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; +} + +EXPORT_SYMBOL(snd_ctl_boolean_stereo_info); diff --git a/sound/core/device.c b/sound/core/device.c index 5858b02b0b1..ea1a0621eef 100644 --- a/sound/core/device.c +++ b/sound/core/device.c @@ -1,6 +1,6 @@ /* * Device management routines - * 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/core/hwdep.c b/sound/core/hwdep.c index 51ad95b7c89..bfd9d182b8a 100644 --- a/sound/core/hwdep.c +++ b/sound/core/hwdep.c @@ -1,6 +1,6 @@ /* * Hardware dependent layer - * 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/hwdep.h> #include <sound/info.h> -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("Hardware dependent layer"); MODULE_LICENSE("GPL"); diff --git a/sound/core/info.c b/sound/core/info.c index bf6dbf99528..1ffd29bb4cd 100644 --- a/sound/core/info.c +++ b/sound/core/info.c @@ -1,6 +1,6 @@ /* * Information interface for ALSA driver - * 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/core/info_oss.c b/sound/core/info_oss.c index a444bfe2cf7..435c9399f7a 100644 --- a/sound/core/info_oss.c +++ b/sound/core/info_oss.c @@ -1,6 +1,6 @@ /* * Information interface for ALSA driver - * 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/core/init.c b/sound/core/init.c index f2fe3573718..2cb7099eb1e 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -1,6 +1,6 @@ /* * Initialization routines - * 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/core/isadma.c b/sound/core/isadma.c index d52398727f0..eb173cef4f0 100644 --- a/sound/core/isadma.c +++ b/sound/core/isadma.c @@ -1,6 +1,6 @@ /* * ISA DMA support functions - * 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/core/memalloc.c b/sound/core/memalloc.c index f057430db0d..9b4992eab47 100644 --- a/sound/core/memalloc.c +++ b/sound/core/memalloc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * Takashi Iwai <tiwai@suse.de> * * Generic memory allocators @@ -27,6 +27,7 @@ #include <linux/pci.h> #include <linux/slab.h> #include <linux/mm.h> +#include <linux/seq_file.h> #include <asm/uaccess.h> #include <linux/dma-mapping.h> #include <linux/moduleparam.h> @@ -37,7 +38,7 @@ #endif -MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>, Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>, Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("Memory allocator for ALSA system."); MODULE_LICENSE("GPL"); @@ -205,6 +206,7 @@ void snd_free_pages(void *ptr, size_t size) * */ +#ifdef CONFIG_HAS_DMA /* allocate the coherent DMA pages */ static void *snd_malloc_dev_pages(struct device *dev, size_t size, dma_addr_t *dma) { @@ -238,6 +240,7 @@ static void snd_free_dev_pages(struct device *dev, size_t size, void *ptr, dec_snd_pages(pg); dma_free_coherent(dev, PAGE_SIZE << pg, ptr, dma); } +#endif /* CONFIG_HAS_DMA */ #ifdef CONFIG_SBUS @@ -311,12 +314,14 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size, dmab->area = snd_malloc_sbus_pages(device, size, &dmab->addr); break; #endif +#ifdef CONFIG_HAS_DMA case SNDRV_DMA_TYPE_DEV: dmab->area = snd_malloc_dev_pages(device, size, &dmab->addr); break; case SNDRV_DMA_TYPE_DEV_SG: snd_malloc_sgbuf_pages(device, size, dmab, NULL); break; +#endif default: printk(KERN_ERR "snd-malloc: invalid device type %d\n", type); dmab->area = NULL; @@ -382,12 +387,14 @@ void snd_dma_free_pages(struct snd_dma_buffer *dmab) snd_free_sbus_pages(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr); break; #endif +#ifdef CONFIG_HAS_DMA case SNDRV_DMA_TYPE_DEV: snd_free_dev_pages(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr); break; case SNDRV_DMA_TYPE_DEV_SG: snd_free_sgbuf_pages(dmab); break; +#endif default: printk(KERN_ERR "snd-malloc: invalid device type %d\n", dmab->dev.type); } @@ -481,53 +488,54 @@ static void free_all_reserved_pages(void) #define SND_MEM_PROC_FILE "driver/snd-page-alloc" static struct proc_dir_entry *snd_mem_proc; -static int snd_mem_proc_read(char *page, char **start, off_t off, - int count, int *eof, void *data) +static int snd_mem_proc_read(struct seq_file *seq, void *offset) { - int len = 0; long pages = snd_allocated_pages >> (PAGE_SHIFT-12); struct snd_mem_list *mem; int devno; static char *types[] = { "UNKNOWN", "CONT", "DEV", "DEV-SG", "SBUS" }; mutex_lock(&list_mutex); - len += snprintf(page + len, count - len, - "pages : %li bytes (%li pages per %likB)\n", - pages * PAGE_SIZE, pages, PAGE_SIZE / 1024); + seq_printf(seq, "pages : %li bytes (%li pages per %likB)\n", + pages * PAGE_SIZE, pages, PAGE_SIZE / 1024); devno = 0; list_for_each_entry(mem, &mem_list_head, list) { devno++; - len += snprintf(page + len, count - len, - "buffer %d : ID %08x : type %s\n", - devno, mem->id, types[mem->buffer.dev.type]); - len += snprintf(page + len, count - len, - " addr = 0x%lx, size = %d bytes\n", - (unsigned long)mem->buffer.addr, (int)mem->buffer.bytes); + seq_printf(seq, "buffer %d : ID %08x : type %s\n", + devno, mem->id, types[mem->buffer.dev.type]); + seq_printf(seq, " addr = 0x%lx, size = %d bytes\n", + (unsigned long)mem->buffer.addr, + (int)mem->buffer.bytes); } mutex_unlock(&list_mutex); - return len; + return 0; +} + +static int snd_mem_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, snd_mem_proc_read, NULL); } /* FIXME: for pci only - other bus? */ #ifdef CONFIG_PCI #define gettoken(bufp) strsep(bufp, " \t\n") -static int snd_mem_proc_write(struct file *file, const char __user *buffer, - unsigned long count, void *data) +static ssize_t snd_mem_proc_write(struct file *file, const char __user * buffer, + size_t count, loff_t * ppos) { char buf[128]; char *token, *p; - if (count > ARRAY_SIZE(buf) - 1) - count = ARRAY_SIZE(buf) - 1; + if (count > sizeof(buf) - 1) + return -EINVAL; if (copy_from_user(buf, buffer, count)) return -EFAULT; - buf[ARRAY_SIZE(buf) - 1] = '\0'; + buf[count] = '\0'; p = buf; token = gettoken(&p); if (! token || *token == '#') - return (int)count; + return count; if (strcmp(token, "add") == 0) { char *endp; int vendor, device, size, buffers; @@ -548,7 +556,7 @@ static int snd_mem_proc_write(struct file *file, const char __user *buffer, (buffers = simple_strtol(token, NULL, 0)) <= 0 || buffers > 4) { printk(KERN_ERR "snd-page-alloc: invalid proc write format\n"); - return (int)count; + return count; } vendor &= 0xffff; device &= 0xffff; @@ -560,7 +568,7 @@ static int snd_mem_proc_write(struct file *file, const char __user *buffer, if (pci_set_dma_mask(pci, mask) < 0 || pci_set_consistent_dma_mask(pci, mask) < 0) { printk(KERN_ERR "snd-page-alloc: cannot set DMA mask %lx for pci %04x:%04x\n", mask, vendor, device); - return (int)count; + return count; } } for (i = 0; i < buffers; i++) { @@ -570,7 +578,7 @@ static int snd_mem_proc_write(struct file *file, const char __user *buffer, size, &dmab) < 0) { printk(KERN_ERR "snd-page-alloc: cannot allocate buffer pages (size = %d)\n", size); pci_dev_put(pci); - return (int)count; + return count; } snd_dma_reserve_buf(&dmab, snd_dma_pci_buf_id(pci)); } @@ -596,9 +604,21 @@ static int snd_mem_proc_write(struct file *file, const char __user *buffer, free_all_reserved_pages(); else printk(KERN_ERR "snd-page-alloc: invalid proc cmd\n"); - return (int)count; + return count; } #endif /* CONFIG_PCI */ + +static const struct file_operations snd_mem_proc_fops = { + .owner = THIS_MODULE, + .open = snd_mem_proc_open, + .read = seq_read, +#ifdef CONFIG_PCI + .write = snd_mem_proc_write, +#endif + .llseek = seq_lseek, + .release = single_release, +}; + #endif /* CONFIG_PROC_FS */ /* @@ -609,12 +629,8 @@ static int __init snd_mem_init(void) { #ifdef CONFIG_PROC_FS snd_mem_proc = create_proc_entry(SND_MEM_PROC_FILE, 0644, NULL); - if (snd_mem_proc) { - snd_mem_proc->read_proc = snd_mem_proc_read; -#ifdef CONFIG_PCI - snd_mem_proc->write_proc = snd_mem_proc_write; -#endif - } + if (snd_mem_proc) + snd_mem_proc->proc_fops = &snd_mem_proc_fops; #endif return 0; } diff --git a/sound/core/memory.c b/sound/core/memory.c index 93537ab7c2a..25b0f056563 100644 --- a/sound/core/memory.c +++ b/sound/core/memory.c @@ -1,5 +1,5 @@ /* - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * * Misc memory accessors * diff --git a/sound/core/misc.c b/sound/core/misc.c index f78cd000e88..6cabab8cc53 100644 --- a/sound/core/misc.c +++ b/sound/core/misc.c @@ -1,6 +1,6 @@ /* * Misc and compatibility things - * 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/core/oss/Makefile b/sound/core/oss/Makefile index e6d5a045ba2..10a79453245 100644 --- a/sound/core/oss/Makefile +++ b/sound/core/oss/Makefile @@ -1,12 +1,13 @@ # # Makefile for ALSA -# Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz> +# Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz> # snd-mixer-oss-objs := mixer_oss.o -snd-pcm-oss-objs := pcm_oss.o pcm_plugin.o \ - io.o copy.o linear.o mulaw.o route.o rate.o +snd-pcm-oss-y := pcm_oss.o +snd-pcm-oss-$(CONFIG_SND_PCM_OSS_PLUGINS) += pcm_plugin.o \ + io.o copy.o linear.o mulaw.o route.o rate.o obj-$(CONFIG_SND_MIXER_OSS) += snd-mixer-oss.o obj-$(CONFIG_SND_PCM_OSS) += snd-pcm-oss.o diff --git a/sound/core/oss/copy.c b/sound/core/oss/copy.c index 6658facc5cd..d6a04c2d5a7 100644 --- a/sound/core/oss/copy.c +++ b/sound/core/oss/copy.c @@ -20,9 +20,6 @@ */ #include <sound/driver.h> - -#ifdef CONFIG_SND_PCM_OSS_PLUGINS - #include <linux/time.h> #include <sound/core.h> #include <sound/pcm.h> @@ -88,5 +85,3 @@ int snd_pcm_plugin_build_copy(struct snd_pcm_substream *plug, *r_plugin = plugin; return 0; } - -#endif diff --git a/sound/core/oss/io.c b/sound/core/oss/io.c index b6e7ce30e5a..3ece39fc48d 100644 --- a/sound/core/oss/io.c +++ b/sound/core/oss/io.c @@ -1,6 +1,6 @@ /* * PCM I/O Plug-In Interface - * Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz> * * * This library is free software; you can redistribute it and/or modify @@ -20,9 +20,6 @@ */ #include <sound/driver.h> - -#ifdef CONFIG_SND_PCM_OSS_PLUGINS - #include <linux/time.h> #include <sound/core.h> #include <sound/pcm.h> @@ -135,5 +132,3 @@ int snd_pcm_plugin_build_io(struct snd_pcm_substream *plug, *r_plugin = plugin; return 0; } - -#endif diff --git a/sound/core/oss/linear.c b/sound/core/oss/linear.c index 5b1bcdc6477..06f96a3e86f 100644 --- a/sound/core/oss/linear.c +++ b/sound/core/oss/linear.c @@ -1,6 +1,6 @@ /* * Linear conversion Plug-In - * Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>, + * Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz>, * Abramo Bagnara <abramo@alsa-project.org> * * @@ -21,9 +21,6 @@ */ #include <sound/driver.h> - -#ifdef CONFIG_SND_PCM_OSS_PLUGINS - #include <linux/time.h> #include <sound/core.h> #include <sound/pcm.h> @@ -34,19 +31,34 @@ */ struct linear_priv { - int conv; + int cvt_endian; /* need endian conversion? */ + unsigned int src_ofs; /* byte offset in source format */ + unsigned int dst_ofs; /* byte soffset in destination format */ + unsigned int copy_ofs; /* byte offset in temporary u32 data */ + unsigned int dst_bytes; /* byte size of destination format */ + unsigned int copy_bytes; /* bytes to copy per conversion */ + unsigned int flip; /* MSB flip for signeness, done after endian conv */ }; +static inline void do_convert(struct linear_priv *data, + unsigned char *dst, unsigned char *src) +{ + unsigned int tmp = 0; + unsigned char *p = (unsigned char *)&tmp; + + memcpy(p + data->copy_ofs, src + data->src_ofs, data->copy_bytes); + if (data->cvt_endian) + tmp = swab32(tmp); + tmp ^= data->flip; + memcpy(dst, p + data->dst_ofs, data->dst_bytes); +} + static void convert(struct snd_pcm_plugin *plugin, const struct snd_pcm_plugin_channel *src_channels, struct snd_pcm_plugin_channel *dst_channels, snd_pcm_uframes_t frames) { -#define CONV_LABELS -#include "plugin_ops.h" -#undef CONV_LABELS struct linear_priv *data = (struct linear_priv *)plugin->extra_data; - void *conv = conv_labels[data->conv]; int channel; int nchannels = plugin->src_format.channels; for (channel = 0; channel < nchannels; ++channel) { @@ -67,11 +79,7 @@ static void convert(struct snd_pcm_plugin *plugin, dst_step = dst_channels[channel].area.step / 8; frames1 = frames; while (frames1-- > 0) { - goto *conv; -#define CONV_END after -#include "plugin_ops.h" -#undef CONV_END - after: + do_convert(data, dst, src); src += src_step; dst += dst_step; } @@ -106,29 +114,36 @@ static snd_pcm_sframes_t linear_transfer(struct snd_pcm_plugin *plugin, return frames; } -static int conv_index(int src_format, int dst_format) +static void init_data(struct linear_priv *data, int src_format, int dst_format) { - int src_endian, dst_endian, sign, src_width, dst_width; - - sign = (snd_pcm_format_signed(src_format) != - snd_pcm_format_signed(dst_format)); -#ifdef SNDRV_LITTLE_ENDIAN - src_endian = snd_pcm_format_big_endian(src_format); - dst_endian = snd_pcm_format_big_endian(dst_format); -#else - src_endian = snd_pcm_format_little_endian(src_format); - dst_endian = snd_pcm_format_little_endian(dst_format); -#endif - - if (src_endian < 0) - src_endian = 0; - if (dst_endian < 0) - dst_endian = 0; - - src_width = snd_pcm_format_width(src_format) / 8 - 1; - dst_width = snd_pcm_format_width(dst_format) / 8 - 1; - - return src_width * 32 + src_endian * 16 + sign * 8 + dst_width * 2 + dst_endian; + int src_le, dst_le, src_bytes, dst_bytes; + + src_bytes = snd_pcm_format_width(src_format) / 8; + dst_bytes = snd_pcm_format_width(dst_format) / 8; + src_le = snd_pcm_format_little_endian(src_format) > 0; + dst_le = snd_pcm_format_little_endian(dst_format) > 0; + + data->dst_bytes = dst_bytes; + data->cvt_endian = src_le != dst_le; + data->copy_bytes = src_bytes < dst_bytes ? src_bytes : dst_bytes; + if (src_le) { + data->copy_ofs = 4 - data->copy_bytes; + data->src_ofs = src_bytes - data->copy_bytes; + } else + data->src_ofs = snd_pcm_format_physical_width(src_format) / 8 - + src_bytes; + if (dst_le) + data->dst_ofs = 4 - data->dst_bytes; + else + data->dst_ofs = snd_pcm_format_physical_width(dst_format) / 8 - + dst_bytes; + if (snd_pcm_format_signed(src_format) != + snd_pcm_format_signed(dst_format)) { + if (dst_le) + data->flip = cpu_to_le32(0x80000000); + else + data->flip = cpu_to_be32(0x80000000); + } } int snd_pcm_plugin_build_linear(struct snd_pcm_substream *plug, @@ -154,10 +169,8 @@ int snd_pcm_plugin_build_linear(struct snd_pcm_substream *plug, if (err < 0) return err; data = (struct linear_priv *)plugin->extra_data; - data->conv = conv_index(src_format->format, dst_format->format); + init_data(data, src_format->format, dst_format->format); plugin->transfer = linear_transfer; *r_plugin = plugin; return 0; } - -#endif diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c index fccad8f0a6b..3ace4a5680b 100644 --- a/sound/core/oss/mixer_oss.c +++ b/sound/core/oss/mixer_oss.c @@ -1,6 +1,6 @@ /* * OSS emulation layer for the mixer interface - * 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 @@ -33,7 +33,7 @@ #define OSS_ALSAEMULVER _SIOR ('M', 249, int) -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("Mixer OSS emulation for ALSA."); MODULE_LICENSE("GPL"); MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_MIXER); diff --git a/sound/core/oss/mulaw.c b/sound/core/oss/mulaw.c index 2eb18807e6d..848db82529e 100644 --- a/sound/core/oss/mulaw.c +++ b/sound/core/oss/mulaw.c @@ -1,6 +1,6 @@ /* * Mu-Law conversion Plug-In Interface - * Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz> * Uros Bizjak <uros@kss-loka.si> * * Based on reference implementation by Sun Microsystems, Inc. @@ -22,9 +22,6 @@ */ #include <sound/driver.h> - -#ifdef CONFIG_SND_PCM_OSS_PLUGINS - #include <linux/time.h> #include <sound/core.h> #include <sound/pcm.h> @@ -149,19 +146,32 @@ typedef void (*mulaw_f)(struct snd_pcm_plugin *plugin, struct mulaw_priv { mulaw_f func; - int conv; + int cvt_endian; /* need endian conversion? */ + unsigned int native_ofs; /* byte offset in native format */ + unsigned int copy_ofs; /* byte offset in s16 format */ + unsigned int native_bytes; /* byte size of the native format */ + unsigned int copy_bytes; /* bytes to copy per conversion */ + u16 flip; /* MSB flip for signedness, done after endian conversion */ }; +static inline void cvt_s16_to_native(struct mulaw_priv *data, + unsigned char *dst, u16 sample) +{ + sample ^= data->flip; + if (data->cvt_endian) + sample = swab16(sample); + if (data->native_bytes > data->copy_bytes) + memset(dst, 0, data->native_bytes); + memcpy(dst + data->native_ofs, (char *)&sample + data->copy_ofs, + data->copy_bytes); +} + static void mulaw_decode(struct snd_pcm_plugin *plugin, const struct snd_pcm_plugin_channel *src_channels, struct snd_pcm_plugin_channel *dst_channels, snd_pcm_uframes_t frames) { -#define PUT_S16_LABELS -#include "plugin_ops.h" -#undef PUT_S16_LABELS struct mulaw_priv *data = (struct mulaw_priv *)plugin->extra_data; - void *put = put_s16_labels[data->conv]; int channel; int nchannels = plugin->src_format.channels; for (channel = 0; channel < nchannels; ++channel) { @@ -183,30 +193,33 @@ static void mulaw_decode(struct snd_pcm_plugin *plugin, frames1 = frames; while (frames1-- > 0) { signed short sample = ulaw2linear(*src); - goto *put; -#define PUT_S16_END after -#include "plugin_ops.h" -#undef PUT_S16_END - after: + cvt_s16_to_native(data, dst, sample); src += src_step; dst += dst_step; } } } +static inline signed short cvt_native_to_s16(struct mulaw_priv *data, + unsigned char *src) +{ + u16 sample = 0; + memcpy((char *)&sample + data->copy_ofs, src + data->native_ofs, + data->copy_bytes); + if (data->cvt_endian) + sample = swab16(sample); + sample ^= data->flip; + return (signed short)sample; +} + static void mulaw_encode(struct snd_pcm_plugin *plugin, const struct snd_pcm_plugin_channel *src_channels, struct snd_pcm_plugin_channel *dst_channels, snd_pcm_uframes_t frames) { -#define GET_S16_LABELS -#include "plugin_ops.h" -#undef GET_S16_LABELS struct mulaw_priv *data = (struct mulaw_priv *)plugin->extra_data; - void *get = get_s16_labels[data->conv]; int channel; int nchannels = plugin->src_format.channels; - signed short sample = 0; for (channel = 0; channel < nchannels; ++channel) { char *src; char *dst; @@ -225,11 +238,7 @@ static void mulaw_encode(struct snd_pcm_plugin *plugin, dst_step = dst_channels[channel].area.step / 8; frames1 = frames; while (frames1-- > 0) { - goto *get; -#define GET_S16_END after -#include "plugin_ops.h" -#undef GET_S16_END - after: + signed short sample = cvt_native_to_s16(data, src); *dst = linear2ulaw(sample); src += src_step; dst += dst_step; @@ -265,23 +274,25 @@ static snd_pcm_sframes_t mulaw_transfer(struct snd_pcm_plugin *plugin, return frames; } -static int getput_index(int format) +static void init_data(struct mulaw_priv *data, int format) { - int sign, width, endian; - sign = !snd_pcm_format_signed(format); - width = snd_pcm_format_width(format) / 8 - 1; - if (width < 0 || width > 3) { - snd_printk(KERN_ERR "snd-pcm-oss: invalid format %d\n", format); - width = 0; - } #ifdef SNDRV_LITTLE_ENDIAN - endian = snd_pcm_format_big_endian(format); + data->cvt_endian = snd_pcm_format_big_endian(format) > 0; #else - endian = snd_pcm_format_little_endian(format); + data->cvt_endian = snd_pcm_format_little_endian(format) > 0; #endif - if (endian < 0) - endian = 0; - return width * 4 + endian * 2 + sign; + if (!snd_pcm_format_signed(format)) + data->flip = 0x8000; + data->native_bytes = snd_pcm_format_physical_width(format) / 8; + data->copy_bytes = data->native_bytes < 2 ? 1 : 2; + if (snd_pcm_format_little_endian(format)) { + data->native_ofs = data->native_bytes - data->copy_bytes; + data->copy_ofs = 2 - data->copy_bytes; + } else { + /* S24 in 4bytes need an 1 byte offset */ + data->native_ofs = data->native_bytes - + snd_pcm_format_width(format) / 8; + } } int snd_pcm_plugin_build_mulaw(struct snd_pcm_substream *plug, @@ -322,11 +333,8 @@ int snd_pcm_plugin_build_mulaw(struct snd_pcm_substream *plug, return err; data = (struct mulaw_priv *)plugin->extra_data; data->func = func; - data->conv = getput_index(format->format); - snd_assert(data->conv >= 0 && data->conv < 4*2*2, return -EINVAL); + init_data(data, format->format); plugin->transfer = mulaw_transfer; *r_plugin = plugin; return 0; } - -#endif diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index fc11572c48c..d0c4ceb9f0b 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -1,6 +1,6 @@ /* * Digital Audio (PCM) abstract layer / OSS 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 @@ -48,7 +48,7 @@ static int dsp_map[SNDRV_CARDS]; static int adsp_map[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 1}; static int nonblock_open = 1; -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Abramo Bagnara <abramo@alsa-project.org>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Abramo Bagnara <abramo@alsa-project.org>"); MODULE_DESCRIPTION("PCM OSS emulation for ALSA."); MODULE_LICENSE("GPL"); module_param_array(dsp_map, int, NULL, 0444); @@ -633,6 +633,22 @@ static long snd_pcm_alsa_frames(struct snd_pcm_substream *substream, long bytes) return bytes_to_frames(runtime, (buffer_size * bytes) / runtime->oss.buffer_bytes); } +/* define extended formats in the recent OSS versions (if any) */ +/* linear formats */ +#define AFMT_S32_LE 0x00001000 +#define AFMT_S32_BE 0x00002000 +#define AFMT_S24_LE 0x00008000 +#define AFMT_S24_BE 0x00010000 +#define AFMT_S24_PACKED 0x00040000 + +/* other supported formats */ +#define AFMT_FLOAT 0x00004000 +#define AFMT_SPDIF_RAW 0x00020000 + +/* unsupported formats */ +#define AFMT_AC3 0x00000400 +#define AFMT_VORBIS 0x00000800 + static int snd_pcm_oss_format_from(int format) { switch (format) { @@ -646,6 +662,13 @@ static int snd_pcm_oss_format_from(int format) case AFMT_U16_LE: return SNDRV_PCM_FORMAT_U16_LE; case AFMT_U16_BE: return SNDRV_PCM_FORMAT_U16_BE; case AFMT_MPEG: return SNDRV_PCM_FORMAT_MPEG; + case AFMT_S32_LE: return SNDRV_PCM_FORMAT_S32_LE; + case AFMT_S32_BE: return SNDRV_PCM_FORMAT_S32_BE; + case AFMT_S24_LE: return SNDRV_PCM_FORMAT_S24_LE; + case AFMT_S24_BE: return SNDRV_PCM_FORMAT_S24_BE; + case AFMT_S24_PACKED: return SNDRV_PCM_FORMAT_S24_3LE; + case AFMT_FLOAT: return SNDRV_PCM_FORMAT_FLOAT; + case AFMT_SPDIF_RAW: return SNDRV_PCM_FORMAT_IEC958_SUBFRAME; default: return SNDRV_PCM_FORMAT_U8; } } @@ -663,6 +686,13 @@ static int snd_pcm_oss_format_to(int format) case SNDRV_PCM_FORMAT_U16_LE: return AFMT_U16_LE; case SNDRV_PCM_FORMAT_U16_BE: return AFMT_U16_BE; case SNDRV_PCM_FORMAT_MPEG: return AFMT_MPEG; + case SNDRV_PCM_FORMAT_S32_LE: return AFMT_S32_LE; + case SNDRV_PCM_FORMAT_S32_BE: return AFMT_S32_BE; + case SNDRV_PCM_FORMAT_S24_LE: return AFMT_S24_LE; + case SNDRV_PCM_FORMAT_S24_BE: return AFMT_S24_BE; + case SNDRV_PCM_FORMAT_S24_3LE: return AFMT_S24_PACKED; + case SNDRV_PCM_FORMAT_FLOAT: return AFMT_FLOAT; + case SNDRV_PCM_FORMAT_IEC958_SUBFRAME: return AFMT_SPDIF_RAW; default: return -EINVAL; } } @@ -1725,7 +1755,10 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file) return AFMT_MU_LAW | AFMT_U8 | AFMT_S16_LE | AFMT_S16_BE | AFMT_S8 | AFMT_U16_LE | - AFMT_U16_BE; + AFMT_U16_BE | + AFMT_S32_LE | AFMT_S32_BE | + AFMT_S24_LE | AFMT_S24_LE | + AFMT_S24_PACKED; params = kmalloc(sizeof(*params), GFP_KERNEL); if (!params) return -ENOMEM; diff --git a/sound/core/oss/pcm_plugin.c b/sound/core/oss/pcm_plugin.c index 0e67dd280a5..14095a927a1 100644 --- a/sound/core/oss/pcm_plugin.c +++ b/sound/core/oss/pcm_plugin.c @@ -1,6 +1,6 @@ /* * PCM Plug-In shared (kernel/library) code - * Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz> * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org> * * @@ -25,9 +25,6 @@ #endif #include <sound/driver.h> - -#ifdef CONFIG_SND_PCM_OSS_PLUGINS - #include <linux/slab.h> #include <linux/time.h> #include <linux/vmalloc.h> @@ -267,6 +264,8 @@ static int snd_pcm_plug_formats(struct snd_mask *mask, int format) SNDRV_PCM_FMTBIT_U16_BE | SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_U24_LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_U24_BE | SNDRV_PCM_FMTBIT_S24_BE | + SNDRV_PCM_FMTBIT_U24_3LE | SNDRV_PCM_FMTBIT_S24_3LE | + SNDRV_PCM_FMTBIT_U24_3BE | SNDRV_PCM_FMTBIT_S24_3BE | SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_BE | SNDRV_PCM_FMTBIT_S32_BE); snd_mask_set(&formats, SNDRV_PCM_FORMAT_MU_LAW); @@ -283,6 +282,10 @@ static int preferred_formats[] = { SNDRV_PCM_FORMAT_S16_BE, SNDRV_PCM_FORMAT_U16_LE, SNDRV_PCM_FORMAT_U16_BE, + SNDRV_PCM_FORMAT_S24_3LE, + SNDRV_PCM_FORMAT_S24_3BE, + SNDRV_PCM_FORMAT_U24_3LE, + SNDRV_PCM_FORMAT_U24_3BE, SNDRV_PCM_FORMAT_S24_LE, SNDRV_PCM_FORMAT_S24_BE, SNDRV_PCM_FORMAT_U24_LE, @@ -297,41 +300,37 @@ static int preferred_formats[] = { int snd_pcm_plug_slave_format(int format, struct snd_mask *format_mask) { + int i; + if (snd_mask_test(format_mask, format)) return format; if (! snd_pcm_plug_formats(format_mask, format)) return -EINVAL; if (snd_pcm_format_linear(format)) { - int width = snd_pcm_format_width(format); - int unsignd = snd_pcm_format_unsigned(format); - int big = snd_pcm_format_big_endian(format); - int format1; - int wid, width1=width; - int dwidth1 = 8; - for (wid = 0; wid < 4; ++wid) { - int end, big1 = big; - for (end = 0; end < 2; ++end) { - int sgn, unsignd1 = unsignd; - for (sgn = 0; sgn < 2; ++sgn) { - format1 = snd_pcm_build_linear_format(width1, unsignd1, big1); - if (format1 >= 0 && - snd_mask_test(format_mask, format1)) - goto _found; - unsignd1 = !unsignd1; - } - big1 = !big1; - } - if (width1 == 32) { - dwidth1 = -dwidth1; - width1 = width; + unsigned int width = snd_pcm_format_width(format); + int unsignd = snd_pcm_format_unsigned(format) > 0; + int big = snd_pcm_format_big_endian(format) > 0; + unsigned int badness, best = -1; + int best_format = -1; + for (i = 0; i < ARRAY_SIZE(preferred_formats); i++) { + int f = preferred_formats[i]; + unsigned int w; + if (!snd_mask_test(format_mask, f)) + continue; + w = snd_pcm_format_width(f); + if (w >= width) + badness = w - width; + else + badness = width - w + 32; + badness += snd_pcm_format_unsigned(f) != unsignd; + badness += snd_pcm_format_big_endian(f) != big; + if (badness < best) { + best_format = f; + best = badness; } - width1 += dwidth1; } - return -EINVAL; - _found: - return format1; + return best_format >= 0 ? best_format : -EINVAL; } else { - unsigned int i; switch (format) { case SNDRV_PCM_FORMAT_MU_LAW: for (i = 0; i < ARRAY_SIZE(preferred_formats); ++i) { @@ -740,5 +739,3 @@ int snd_pcm_area_copy(const struct snd_pcm_channel_area *src_area, size_t src_of } return 0; } - -#endif diff --git a/sound/core/oss/pcm_plugin.h b/sound/core/oss/pcm_plugin.h index 3be91b3d537..ca2f4c39be4 100644 --- a/sound/core/oss/pcm_plugin.h +++ b/sound/core/oss/pcm_plugin.h @@ -3,7 +3,7 @@ /* * Digital Audio (Plugin interface) abstract layer - * 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/core/oss/plugin_ops.h b/sound/core/oss/plugin_ops.h deleted file mode 100644 index 1f5bde4631f..00000000000 --- a/sound/core/oss/plugin_ops.h +++ /dev/null @@ -1,370 +0,0 @@ -/* - * Plugin sample operators with fast switch - * Copyright (c) 2000 by Jaroslav Kysela <perex@suse.cz> - * - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Library 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 Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - - -#define as_u8(ptr) (*(u_int8_t*)(ptr)) -#define as_u16(ptr) (*(u_int16_t*)(ptr)) -#define as_u32(ptr) (*(u_int32_t*)(ptr)) -#define as_u64(ptr) (*(u_int64_t*)(ptr)) -#define as_s8(ptr) (*(int8_t*)(ptr)) -#define as_s16(ptr) (*(int16_t*)(ptr)) -#define as_s32(ptr) (*(int32_t*)(ptr)) -#define as_s64(ptr) (*(int64_t*)(ptr)) - -#ifdef COPY_LABELS -static void *copy_labels[4] = { - &©_8, - &©_16, - &©_32, - &©_64 -}; -#endif - -#ifdef COPY_END -while(0) { -copy_8: as_s8(dst) = as_s8(src); goto COPY_END; -copy_16: as_s16(dst) = as_s16(src); goto COPY_END; -copy_32: as_s32(dst) = as_s32(src); goto COPY_END; -copy_64: as_s64(dst) = as_s64(src); goto COPY_END; -} -#endif - -#ifdef CONV_LABELS -/* src_wid src_endswap sign_toggle dst_wid dst_endswap */ -static void *conv_labels[4 * 2 * 2 * 4 * 2] = { - &&conv_xxx1_xxx1, /* 8h -> 8h */ - &&conv_xxx1_xxx1, /* 8h -> 8s */ - &&conv_xxx1_xx10, /* 8h -> 16h */ - &&conv_xxx1_xx01, /* 8h -> 16s */ - &&conv_xxx1_x100, /* 8h -> 24h */ - &&conv_xxx1_001x, /* 8h -> 24s */ - &&conv_xxx1_1000, /* 8h -> 32h */ - &&conv_xxx1_0001, /* 8h -> 32s */ - &&conv_xxx1_xxx9, /* 8h ^> 8h */ - &&conv_xxx1_xxx9, /* 8h ^> 8s */ - &&conv_xxx1_xx90, /* 8h ^> 16h */ - &&conv_xxx1_xx09, /* 8h ^> 16s */ - &&conv_xxx1_x900, /* 8h ^> 24h */ - &&conv_xxx1_009x, /* 8h ^> 24s */ - &&conv_xxx1_9000, /* 8h ^> 32h */ - &&conv_xxx1_0009, /* 8h ^> 32s */ - &&conv_xxx1_xxx1, /* 8s -> 8h */ - &&conv_xxx1_xxx1, /* 8s -> 8s */ - &&conv_xxx1_xx10, /* 8s -> 16h */ - &&conv_xxx1_xx01, /* 8s -> 16s */ - &&conv_xxx1_x100, /* 8s -> 24h */ - &&conv_xxx1_001x, /* 8s -> 24s */ - &&conv_xxx1_1000, /* 8s -> 32h */ - &&conv_xxx1_0001, /* 8s -> 32s */ - &&conv_xxx1_xxx9, /* 8s ^> 8h */ - &&conv_xxx1_xxx9, /* 8s ^> 8s */ - &&conv_xxx1_xx90, /* 8s ^> 16h */ - &&conv_xxx1_xx09, /* 8s ^> 16s */ - &&conv_xxx1_x900, /* 8s ^> 24h */ - &&conv_xxx1_009x, /* 8s ^> 24s */ - &&conv_xxx1_9000, /* 8s ^> 32h */ - &&conv_xxx1_0009, /* 8s ^> 32s */ - &&conv_xx12_xxx1, /* 16h -> 8h */ - &&conv_xx12_xxx1, /* 16h -> 8s */ - &&conv_xx12_xx12, /* 16h -> 16h */ - &&conv_xx12_xx21, /* 16h -> 16s */ - &&conv_xx12_x120, /* 16h -> 24h */ - &&conv_xx12_021x, /* 16h -> 24s */ - &&conv_xx12_1200, /* 16h -> 32h */ - &&conv_xx12_0021, /* 16h -> 32s */ - &&conv_xx12_xxx9, /* 16h ^> 8h */ - &&conv_xx12_xxx9, /* 16h ^> 8s */ - &&conv_xx12_xx92, /* 16h ^> 16h */ - &&conv_xx12_xx29, /* 16h ^> 16s */ - &&conv_xx12_x920, /* 16h ^> 24h */ - &&conv_xx12_029x, /* 16h ^> 24s */ - &&conv_xx12_9200, /* 16h ^> 32h */ - &&conv_xx12_0029, /* 16h ^> 32s */ - &&conv_xx12_xxx2, /* 16s -> 8h */ - &&conv_xx12_xxx2, /* 16s -> 8s */ - &&conv_xx12_xx21, /* 16s -> 16h */ - &&conv_xx12_xx12, /* 16s -> 16s */ - &&conv_xx12_x210, /* 16s -> 24h */ - &&conv_xx12_012x, /* 16s -> 24s */ - &&conv_xx12_2100, /* 16s -> 32h */ - &&conv_xx12_0012, /* 16s -> 32s */ - &&conv_xx12_xxxA, /* 16s ^> 8h */ - &&conv_xx12_xxxA, /* 16s ^> 8s */ - &&conv_xx12_xxA1, /* 16s ^> 16h */ - &&conv_xx12_xx1A, /* 16s ^> 16s */ - &&conv_xx12_xA10, /* 16s ^> 24h */ - &&conv_xx12_01Ax, /* 16s ^> 24s */ - &&conv_xx12_A100, /* 16s ^> 32h */ - &&conv_xx12_001A, /* 16s ^> 32s */ - &&conv_x123_xxx1, /* 24h -> 8h */ - &&conv_x123_xxx1, /* 24h -> 8s */ - &&conv_x123_xx12, /* 24h -> 16h */ - &&conv_x123_xx21, /* 24h -> 16s */ - &&conv_x123_x123, /* 24h -> 24h */ - &&conv_x123_321x, /* 24h -> 24s */ - &&conv_x123_1230, /* 24h -> 32h */ - &&conv_x123_0321, /* 24h -> 32s */ - &&conv_x123_xxx9, /* 24h ^> 8h */ - &&conv_x123_xxx9, /* 24h ^> 8s */ - &&conv_x123_xx92, /* 24h ^> 16h */ - &&conv_x123_xx29, /* 24h ^> 16s */ - &&conv_x123_x923, /* 24h ^> 24h */ - &&conv_x123_329x, /* 24h ^> 24s */ - &&conv_x123_9230, /* 24h ^> 32h */ - &&conv_x123_0329, /* 24h ^> 32s */ - &&conv_123x_xxx3, /* 24s -> 8h */ - &&conv_123x_xxx3, /* 24s -> 8s */ - &&conv_123x_xx32, /* 24s -> 16h */ - &&conv_123x_xx23, /* 24s -> 16s */ - &&conv_123x_x321, /* 24s -> 24h */ - &&conv_123x_123x, /* 24s -> 24s */ - &&conv_123x_3210, /* 24s -> 32h */ - &&conv_123x_0123, /* 24s -> 32s */ - &&conv_123x_xxxB, /* 24s ^> 8h */ - &&conv_123x_xxxB, /* 24s ^> 8s */ - &&conv_123x_xxB2, /* 24s ^> 16h */ - &&conv_123x_xx2B, /* 24s ^> 16s */ - &&conv_123x_xB21, /* 24s ^> 24h */ - &&conv_123x_12Bx, /* 24s ^> 24s */ - &&conv_123x_B210, /* 24s ^> 32h */ - &&conv_123x_012B, /* 24s ^> 32s */ - &&conv_1234_xxx1, /* 32h -> 8h */ - &&conv_1234_xxx1, /* 32h -> 8s */ - &&conv_1234_xx12, /* 32h -> 16h */ - &&conv_1234_xx21, /* 32h -> 16s */ - &&conv_1234_x123, /* 32h -> 24h */ - &&conv_1234_321x, /* 32h -> 24s */ - &&conv_1234_1234, /* 32h -> 32h */ - &&conv_1234_4321, /* 32h -> 32s */ - &&conv_1234_xxx9, /* 32h ^> 8h */ - &&conv_1234_xxx9, /* 32h ^> 8s */ - &&conv_1234_xx92, /* 32h ^> 16h */ - &&conv_1234_xx29, /* 32h ^> 16s */ - &&conv_1234_x923, /* 32h ^> 24h */ - &&conv_1234_329x, /* 32h ^> 24s */ - &&conv_1234_9234, /* 32h ^> 32h */ - &&conv_1234_4329, /* 32h ^> 32s */ - &&conv_1234_xxx4, /* 32s -> 8h */ - &&conv_1234_xxx4, /* 32s -> 8s */ - &&conv_1234_xx43, /* 32s -> 16h */ - &&conv_1234_xx34, /* 32s -> 16s */ - &&conv_1234_x432, /* 32s -> 24h */ - &&conv_1234_234x, /* 32s -> 24s */ - &&conv_1234_4321, /* 32s -> 32h */ - &&conv_1234_1234, /* 32s -> 32s */ - &&conv_1234_xxxC, /* 32s ^> 8h */ - &&conv_1234_xxxC, /* 32s ^> 8s */ - &&conv_1234_xxC3, /* 32s ^> 16h */ - &&conv_1234_xx3C, /* 32s ^> 16s */ - &&conv_1234_xC32, /* 32s ^> 24h */ - &&conv_1234_23Cx, /* 32s ^> 24s */ - &&conv_1234_C321, /* 32s ^> 32h */ - &&conv_1234_123C, /* 32s ^> 32s */ -}; -#endif - -#ifdef CONV_END -while(0) { -conv_xxx1_xxx1: as_u8(dst) = as_u8(src); goto CONV_END; -conv_xxx1_xx10: as_u16(dst) = (u_int16_t)as_u8(src) << 8; goto CONV_END; -conv_xxx1_xx01: as_u16(dst) = (u_int16_t)as_u8(src); goto CONV_END; -conv_xxx1_x100: as_u32(dst) = (u_int32_t)as_u8(src) << 16; goto CONV_END; -conv_xxx1_001x: as_u32(dst) = (u_int32_t)as_u8(src) << 8; goto CONV_END; -conv_xxx1_1000: as_u32(dst) = (u_int32_t)as_u8(src) << 24; goto CONV_END; -conv_xxx1_0001: as_u32(dst) = (u_int32_t)as_u8(src); goto CONV_END; -conv_xxx1_xxx9: as_u8(dst) = as_u8(src) ^ 0x80; goto CONV_END; -conv_xxx1_xx90: as_u16(dst) = (u_int16_t)(as_u8(src) ^ 0x80) << 8; goto CONV_END; -conv_xxx1_xx09: as_u16(dst) = (u_int16_t)(as_u8(src) ^ 0x80); goto CONV_END; -conv_xxx1_x900: as_u32(dst) = (u_int32_t)(as_u8(src) ^ 0x80) << 16; goto CONV_END; -conv_xxx1_009x: as_u32(dst) = (u_int32_t)(as_u8(src) ^ 0x80) << 8; goto CONV_END; -conv_xxx1_9000: as_u32(dst) = (u_int32_t)(as_u8(src) ^ 0x80) << 24; goto CONV_END; -conv_xxx1_0009: as_u32(dst) = (u_int32_t)(as_u8(src) ^ 0x80); goto CONV_END; -conv_xx12_xxx1: as_u8(dst) = as_u16(src) >> 8; goto CONV_END; -conv_xx12_xx12: as_u16(dst) = as_u16(src); goto CONV_END; -conv_xx12_xx21: as_u16(dst) = swab16(as_u16(src)); goto CONV_END; -conv_xx12_x120: as_u32(dst) = (u_int32_t)as_u16(src) << 8; goto CONV_END; -conv_xx12_021x: as_u32(dst) = (u_int32_t)swab16(as_u16(src)) << 8; goto CONV_END; -conv_xx12_1200: as_u32(dst) = (u_int32_t)as_u16(src) << 16; goto CONV_END; -conv_xx12_0021: as_u32(dst) = (u_int32_t)swab16(as_u16(src)); goto CONV_END; -conv_xx12_xxx9: as_u8(dst) = (as_u16(src) >> 8) ^ 0x80; goto CONV_END; -conv_xx12_xx92: as_u16(dst) = as_u16(src) ^ 0x8000; goto CONV_END; -conv_xx12_xx29: as_u16(dst) = swab16(as_u16(src)) ^ 0x80; goto CONV_END; -conv_xx12_x920: as_u32(dst) = (u_int32_t)(as_u16(src) ^ 0x8000) << 8; goto CONV_END; -conv_xx12_029x: as_u32(dst) = (u_int32_t)(swab16(as_u16(src)) ^ 0x80) << 8; goto CONV_END; -conv_xx12_9200: as_u32(dst) = (u_int32_t)(as_u16(src) ^ 0x8000) << 16; goto CONV_END; -conv_xx12_0029: as_u32(dst) = (u_int32_t)(swab16(as_u16(src)) ^ 0x80); goto CONV_END; -conv_xx12_xxx2: as_u8(dst) = as_u16(src) & 0xff; goto CONV_END; -conv_xx12_x210: as_u32(dst) = (u_int32_t)swab16(as_u16(src)) << 8; goto CONV_END; -conv_xx12_012x: as_u32(dst) = (u_int32_t)as_u16(src) << 8; goto CONV_END; -conv_xx12_2100: as_u32(dst) = (u_int32_t)swab16(as_u16(src)) << 16; goto CONV_END; -conv_xx12_0012: as_u32(dst) = (u_int32_t)as_u16(src); goto CONV_END; -conv_xx12_xxxA: as_u8(dst) = (as_u16(src) ^ 0x80) & 0xff; goto CONV_END; -conv_xx12_xxA1: as_u16(dst) = swab16(as_u16(src) ^ 0x80); goto CONV_END; -conv_xx12_xx1A: as_u16(dst) = as_u16(src) ^ 0x80; goto CONV_END; -conv_xx12_xA10: as_u32(dst) = (u_int32_t)swab16(as_u16(src) ^ 0x80) << 8; goto CONV_END; -conv_xx12_01Ax: as_u32(dst) = (u_int32_t)(as_u16(src) ^ 0x80) << 8; goto CONV_END; -conv_xx12_A100: as_u32(dst) = (u_int32_t)swab16(as_u16(src) ^ 0x80) << 16; goto CONV_END; -conv_xx12_001A: as_u32(dst) = (u_int32_t)(as_u16(src) ^ 0x80); goto CONV_END; -conv_x123_xxx1: as_u8(dst) = as_u32(src) >> 16; goto CONV_END; -conv_x123_xx12: as_u16(dst) = as_u32(src) >> 8; goto CONV_END; -conv_x123_xx21: as_u16(dst) = swab16(as_u32(src) >> 8); goto CONV_END; -conv_x123_x123: as_u32(dst) = as_u32(src); goto CONV_END; -conv_x123_321x: as_u32(dst) = swab32(as_u32(src)); goto CONV_END; -conv_x123_1230: as_u32(dst) = as_u32(src) << 8; goto CONV_END; -conv_x123_0321: as_u32(dst) = swab32(as_u32(src)) >> 8; goto CONV_END; -conv_x123_xxx9: as_u8(dst) = (as_u32(src) >> 16) ^ 0x80; goto CONV_END; -conv_x123_xx92: as_u16(dst) = (as_u32(src) >> 8) ^ 0x8000; goto CONV_END; -conv_x123_xx29: as_u16(dst) = swab16(as_u32(src) >> 8) ^ 0x80; goto CONV_END; -conv_x123_x923: as_u32(dst) = as_u32(src) ^ 0x800000; goto CONV_END; -conv_x123_329x: as_u32(dst) = swab32(as_u32(src)) ^ 0x8000; goto CONV_END; -conv_x123_9230: as_u32(dst) = (as_u32(src) ^ 0x800000) << 8; goto CONV_END; -conv_x123_0329: as_u32(dst) = (swab32(as_u32(src)) >> 8) ^ 0x80; goto CONV_END; -conv_123x_xxx3: as_u8(dst) = (as_u32(src) >> 8) & 0xff; goto CONV_END; -conv_123x_xx32: as_u16(dst) = swab16(as_u32(src) >> 8); goto CONV_END; -conv_123x_xx23: as_u16(dst) = (as_u32(src) >> 8) & 0xffff; goto CONV_END; -conv_123x_x321: as_u32(dst) = swab32(as_u32(src)); goto CONV_END; -conv_123x_123x: as_u32(dst) = as_u32(src); goto CONV_END; -conv_123x_3210: as_u32(dst) = swab32(as_u32(src)) << 8; goto CONV_END; -conv_123x_0123: as_u32(dst) = as_u32(src) >> 8; goto CONV_END; -conv_123x_xxxB: as_u8(dst) = ((as_u32(src) >> 8) & 0xff) ^ 0x80; goto CONV_END; -conv_123x_xxB2: as_u16(dst) = swab16((as_u32(src) >> 8) ^ 0x80); goto CONV_END; -conv_123x_xx2B: as_u16(dst) = ((as_u32(src) >> 8) & 0xffff) ^ 0x80; goto CONV_END; -conv_123x_xB21: as_u32(dst) = swab32(as_u32(src)) ^ 0x800000; goto CONV_END; -conv_123x_12Bx: as_u32(dst) = as_u32(src) ^ 0x8000; goto CONV_END; -conv_123x_B210: as_u32(dst) = swab32(as_u32(src) ^ 0x8000) << 8; goto CONV_END; -conv_123x_012B: as_u32(dst) = (as_u32(src) >> 8) ^ 0x80; goto CONV_END; -conv_1234_xxx1: as_u8(dst) = as_u32(src) >> 24; goto CONV_END; -conv_1234_xx12: as_u16(dst) = as_u32(src) >> 16; goto CONV_END; -conv_1234_xx21: as_u16(dst) = swab16(as_u32(src) >> 16); goto CONV_END; -conv_1234_x123: as_u32(dst) = as_u32(src) >> 8; goto CONV_END; -conv_1234_321x: as_u32(dst) = swab32(as_u32(src)) << 8; goto CONV_END; -conv_1234_1234: as_u32(dst) = as_u32(src); goto CONV_END; -conv_1234_4321: as_u32(dst) = swab32(as_u32(src)); goto CONV_END; -conv_1234_xxx9: as_u8(dst) = (as_u32(src) >> 24) ^ 0x80; goto CONV_END; -conv_1234_xx92: as_u16(dst) = (as_u32(src) >> 16) ^ 0x8000; goto CONV_END; -conv_1234_xx29: as_u16(dst) = swab16(as_u32(src) >> 16) ^ 0x80; goto CONV_END; -conv_1234_x923: as_u32(dst) = (as_u32(src) >> 8) ^ 0x800000; goto CONV_END; -conv_1234_329x: as_u32(dst) = (swab32(as_u32(src)) ^ 0x80) << 8; goto CONV_END; -conv_1234_9234: as_u32(dst) = as_u32(src) ^ 0x80000000; goto CONV_END; -conv_1234_4329: as_u32(dst) = swab32(as_u32(src)) ^ 0x80; goto CONV_END; -conv_1234_xxx4: as_u8(dst) = as_u32(src) & 0xff; goto CONV_END; -conv_1234_xx43: as_u16(dst) = swab16(as_u32(src)); goto CONV_END; -conv_1234_xx34: as_u16(dst) = as_u32(src) & 0xffff; goto CONV_END; -conv_1234_x432: as_u32(dst) = swab32(as_u32(src)) >> 8; goto CONV_END; -conv_1234_234x: as_u32(dst) = as_u32(src) << 8; goto CONV_END; -conv_1234_xxxC: as_u8(dst) = (as_u32(src) & 0xff) ^ 0x80; goto CONV_END; -conv_1234_xxC3: as_u16(dst) = swab16(as_u32(src) ^ 0x80); goto CONV_END; -conv_1234_xx3C: as_u16(dst) = (as_u32(src) & 0xffff) ^ 0x80; goto CONV_END; -conv_1234_xC32: as_u32(dst) = (swab32(as_u32(src)) >> 8) ^ 0x800000; goto CONV_END; -conv_1234_23Cx: as_u32(dst) = (as_u32(src) ^ 0x80) << 8; goto CONV_END; -conv_1234_C321: as_u32(dst) = swab32(as_u32(src) ^ 0x80); goto CONV_END; -conv_1234_123C: as_u32(dst) = as_u32(src) ^ 0x80; goto CONV_END; -} -#endif - -#ifdef GET_S16_LABELS -/* src_wid src_endswap unsigned */ -static void *get_s16_labels[4 * 2 * 2] = { - &&get_s16_xxx1_xx10, /* 8h -> 16h */ - &&get_s16_xxx1_xx90, /* 8h ^> 16h */ - &&get_s16_xxx1_xx10, /* 8s -> 16h */ - &&get_s16_xxx1_xx90, /* 8s ^> 16h */ - &&get_s16_xx12_xx12, /* 16h -> 16h */ - &&get_s16_xx12_xx92, /* 16h ^> 16h */ - &&get_s16_xx12_xx21, /* 16s -> 16h */ - &&get_s16_xx12_xxA1, /* 16s ^> 16h */ - &&get_s16_x123_xx12, /* 24h -> 16h */ - &&get_s16_x123_xx92, /* 24h ^> 16h */ - &&get_s16_123x_xx32, /* 24s -> 16h */ - &&get_s16_123x_xxB2, /* 24s ^> 16h */ - &&get_s16_1234_xx12, /* 32h -> 16h */ - &&get_s16_1234_xx92, /* 32h ^> 16h */ - &&get_s16_1234_xx43, /* 32s -> 16h */ - &&get_s16_1234_xxC3, /* 32s ^> 16h */ -}; -#endif - -#ifdef GET_S16_END -while(0) { -get_s16_xxx1_xx10: sample = (u_int16_t)as_u8(src) << 8; goto GET_S16_END; -get_s16_xxx1_xx90: sample = (u_int16_t)(as_u8(src) ^ 0x80) << 8; goto GET_S16_END; -get_s16_xx12_xx12: sample = as_u16(src); goto GET_S16_END; -get_s16_xx12_xx92: sample = as_u16(src) ^ 0x8000; goto GET_S16_END; -get_s16_xx12_xx21: sample = swab16(as_u16(src)); goto GET_S16_END; -get_s16_xx12_xxA1: sample = swab16(as_u16(src) ^ 0x80); goto GET_S16_END; -get_s16_x123_xx12: sample = as_u32(src) >> 8; goto GET_S16_END; -get_s16_x123_xx92: sample = (as_u32(src) >> 8) ^ 0x8000; goto GET_S16_END; -get_s16_123x_xx32: sample = swab16(as_u32(src) >> 8); goto GET_S16_END; -get_s16_123x_xxB2: sample = swab16((as_u32(src) >> 8) ^ 0x8000); goto GET_S16_END; -get_s16_1234_xx12: sample = as_u32(src) >> 16; goto GET_S16_END; -get_s16_1234_xx92: sample = (as_u32(src) >> 16) ^ 0x8000; goto GET_S16_END; -get_s16_1234_xx43: sample = swab16(as_u32(src)); goto GET_S16_END; -get_s16_1234_xxC3: sample = swab16(as_u32(src) ^ 0x80); goto GET_S16_END; -} -#endif - -#ifdef PUT_S16_LABELS -/* dst_wid dst_endswap unsigned */ -static void *put_s16_labels[4 * 2 * 2] = { - &&put_s16_xx12_xxx1, /* 16h -> 8h */ - &&put_s16_xx12_xxx9, /* 16h ^> 8h */ - &&put_s16_xx12_xxx1, /* 16h -> 8s */ - &&put_s16_xx12_xxx9, /* 16h ^> 8s */ - &&put_s16_xx12_xx12, /* 16h -> 16h */ - &&put_s16_xx12_xx92, /* 16h ^> 16h */ - &&put_s16_xx12_xx21, /* 16h -> 16s */ - &&put_s16_xx12_xx29, /* 16h ^> 16s */ - &&put_s16_xx12_x120, /* 16h -> 24h */ - &&put_s16_xx12_x920, /* 16h ^> 24h */ - &&put_s16_xx12_021x, /* 16h -> 24s */ - &&put_s16_xx12_029x, /* 16h ^> 24s */ - &&put_s16_xx12_1200, /* 16h -> 32h */ - &&put_s16_xx12_9200, /* 16h ^> 32h */ - &&put_s16_xx12_0021, /* 16h -> 32s */ - &&put_s16_xx12_0029, /* 16h ^> 32s */ -}; -#endif - -#ifdef PUT_S16_END -while (0) { -put_s16_xx12_xxx1: as_u8(dst) = sample >> 8; goto PUT_S16_END; -put_s16_xx12_xxx9: as_u8(dst) = (sample >> 8) ^ 0x80; goto PUT_S16_END; -put_s16_xx12_xx12: as_u16(dst) = sample; goto PUT_S16_END; -put_s16_xx12_xx92: as_u16(dst) = sample ^ 0x8000; goto PUT_S16_END; -put_s16_xx12_xx21: as_u16(dst) = swab16(sample); goto PUT_S16_END; -put_s16_xx12_xx29: as_u16(dst) = swab16(sample) ^ 0x80; goto PUT_S16_END; -put_s16_xx12_x120: as_u32(dst) = (u_int32_t)sample << 8; goto PUT_S16_END; -put_s16_xx12_x920: as_u32(dst) = (u_int32_t)(sample ^ 0x8000) << 8; goto PUT_S16_END; -put_s16_xx12_021x: as_u32(dst) = (u_int32_t)swab16(sample) << 8; goto PUT_S16_END; -put_s16_xx12_029x: as_u32(dst) = (u_int32_t)(swab16(sample) ^ 0x80) << 8; goto PUT_S16_END; -put_s16_xx12_1200: as_u32(dst) = (u_int32_t)sample << 16; goto PUT_S16_END; -put_s16_xx12_9200: as_u32(dst) = (u_int32_t)(sample ^ 0x8000) << 16; goto PUT_S16_END; -put_s16_xx12_0021: as_u32(dst) = (u_int32_t)swab16(sample); goto PUT_S16_END; -put_s16_xx12_0029: as_u32(dst) = (u_int32_t)swab16(sample) ^ 0x80; goto PUT_S16_END; -} -#endif - -#undef as_u8 -#undef as_u16 -#undef as_u32 -#undef as_s8 -#undef as_s16 -#undef as_s32 diff --git a/sound/core/oss/rate.c b/sound/core/oss/rate.c index 18d8a0f4e81..9eb267913c3 100644 --- a/sound/core/oss/rate.c +++ b/sound/core/oss/rate.c @@ -1,6 +1,6 @@ /* * Rate conversion Plug-In - * Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz> * * * This library is free software; you can redistribute it and/or modify @@ -20,9 +20,6 @@ */ #include <sound/driver.h> - -#ifdef CONFIG_SND_PCM_OSS_PLUGINS - #include <linux/time.h> #include <sound/core.h> #include <sound/pcm.h> @@ -340,5 +337,3 @@ int snd_pcm_plugin_build_rate(struct snd_pcm_substream *plug, *r_plugin = plugin; return 0; } - -#endif diff --git a/sound/core/oss/route.c b/sound/core/oss/route.c index 46917dc0196..de3ffdeaf7e 100644 --- a/sound/core/oss/route.c +++ b/sound/core/oss/route.c @@ -20,9 +20,6 @@ */ #include <sound/driver.h> - -#ifdef CONFIG_SND_PCM_OSS_PLUGINS - #include <linux/slab.h> #include <linux/time.h> #include <sound/core.h> @@ -108,5 +105,3 @@ int snd_pcm_plugin_build_route(struct snd_pcm_substream *plug, *r_plugin = plugin; return 0; } - -#endif diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 2743414fc8f..cf9b9493d41 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -1,6 +1,6 @@ /* * Digital Audio (PCM) abstract layer - * 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 @@ -30,7 +30,7 @@ #include <sound/control.h> #include <sound/info.h> -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Abramo Bagnara <abramo@alsa-project.org>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Abramo Bagnara <abramo@alsa-project.org>"); MODULE_DESCRIPTION("Midlevel PCM code for ALSA."); MODULE_LICENSE("GPL"); diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 9fefcaa2c32..806f1fba544 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -1,6 +1,6 @@ /* * Digital Audio (PCM) abstract layer - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * Abramo Bagnara <abramo@alsa-project.org> * * diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index 95b1b2f0b1e..a13e38cfd2c 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c @@ -1,6 +1,6 @@ /* * Digital Audio (PCM) abstract layer - * 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/core/pcm_misc.c b/sound/core/pcm_misc.c index 0019c59a779..dd9aa51d8c8 100644 --- a/sound/core/pcm_misc.c +++ b/sound/core/pcm_misc.c @@ -1,6 +1,6 @@ /* * PCM Interface - misc routines - * Copyright (c) 1998 by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) 1998 by Jaroslav Kysela <perex@perex.cz> * * * This library is free software; you can redistribute it and/or modify @@ -422,38 +422,6 @@ int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int EXPORT_SYMBOL(snd_pcm_format_set_silence); -/* [width][unsigned][bigendian] */ -static int linear_formats[4][2][2] = { - {{ SNDRV_PCM_FORMAT_S8, SNDRV_PCM_FORMAT_S8}, - { SNDRV_PCM_FORMAT_U8, SNDRV_PCM_FORMAT_U8}}, - {{SNDRV_PCM_FORMAT_S16_LE, SNDRV_PCM_FORMAT_S16_BE}, - {SNDRV_PCM_FORMAT_U16_LE, SNDRV_PCM_FORMAT_U16_BE}}, - {{SNDRV_PCM_FORMAT_S24_LE, SNDRV_PCM_FORMAT_S24_BE}, - {SNDRV_PCM_FORMAT_U24_LE, SNDRV_PCM_FORMAT_U24_BE}}, - {{SNDRV_PCM_FORMAT_S32_LE, SNDRV_PCM_FORMAT_S32_BE}, - {SNDRV_PCM_FORMAT_U32_LE, SNDRV_PCM_FORMAT_U32_BE}} -}; - -/** - * snd_pcm_build_linear_format - return the suitable linear format for the given condition - * @width: the bit-width - * @unsignd: 1 if unsigned, 0 if signed. - * @big_endian: 1 if big-endian, 0 if little-endian - * - * Returns the suitable linear format for the given condition. - */ -snd_pcm_format_t snd_pcm_build_linear_format(int width, int unsignd, int big_endian) -{ - if (width & 7) - return SND_PCM_FORMAT_UNKNOWN; - width = (width / 8) - 1; - if (width < 0 || width >= 4) - return SND_PCM_FORMAT_UNKNOWN; - return linear_formats[width][!!unsignd][!!big_endian]; -} - -EXPORT_SYMBOL(snd_pcm_build_linear_format); - /** * snd_pcm_limit_hw_rates - determine rate_min/rate_max fields * @runtime: the runtime instance @@ -465,21 +433,16 @@ EXPORT_SYMBOL(snd_pcm_build_linear_format); */ int snd_pcm_limit_hw_rates(struct snd_pcm_runtime *runtime) { - static unsigned rates[] = { - /* ATTENTION: these values depend on the definition in pcm.h! */ - 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, - 64000, 88200, 96000, 176400, 192000 - }; int i; - for (i = 0; i < (int)ARRAY_SIZE(rates); i++) { + for (i = 0; i < (int)snd_pcm_known_rates.count; i++) { if (runtime->hw.rates & (1 << i)) { - runtime->hw.rate_min = rates[i]; + runtime->hw.rate_min = snd_pcm_known_rates.list[i]; break; } } - for (i = (int)ARRAY_SIZE(rates) - 1; i >= 0; i--) { + for (i = (int)snd_pcm_known_rates.count - 1; i >= 0; i--) { if (runtime->hw.rates & (1 << i)) { - runtime->hw.rate_max = rates[i]; + runtime->hw.rate_max = snd_pcm_known_rates.list[i]; break; } } @@ -487,3 +450,21 @@ int snd_pcm_limit_hw_rates(struct snd_pcm_runtime *runtime) } EXPORT_SYMBOL(snd_pcm_limit_hw_rates); + +/** + * snd_pcm_rate_to_rate_bit - converts sample rate to SNDRV_PCM_RATE_xxx bit + * @rate: the sample rate to convert + * + * Returns the SNDRV_PCM_RATE_xxx flag that corresponds to the given rate, or + * SNDRV_PCM_RATE_KNOT for an unknown rate. + */ +unsigned int snd_pcm_rate_to_rate_bit(unsigned int rate) +{ + unsigned int i; + + for (i = 0; i < snd_pcm_known_rates.count; i++) + if (snd_pcm_known_rates.list[i] == rate) + return 1u << i; + return SNDRV_PCM_RATE_KNOT; +} +EXPORT_SYMBOL(snd_pcm_rate_to_rate_bit); diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 59b29cd482a..fb3dde4db04 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1,6 +1,6 @@ /* * Digital Audio (PCM) abstract layer - * 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 @@ -1787,12 +1787,18 @@ static int snd_pcm_hw_rule_sample_bits(struct snd_pcm_hw_params *params, static unsigned int rates[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, 88200, 96000, 176400, 192000 }; +const struct snd_pcm_hw_constraint_list snd_pcm_known_rates = { + .count = ARRAY_SIZE(rates), + .list = rates, +}; + static int snd_pcm_hw_rule_rate(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { struct snd_pcm_hardware *hw = rule->private; return snd_interval_list(hw_param_interval(params, rule->var), - ARRAY_SIZE(rates), rates, hw->rates); + snd_pcm_known_rates.count, + snd_pcm_known_rates.list, hw->rates); } static int snd_pcm_hw_rule_buffer_bytes_max(struct snd_pcm_hw_params *params, diff --git a/sound/core/pcm_timer.c b/sound/core/pcm_timer.c index d94ed16d21e..23aa9a27e21 100644 --- a/sound/core/pcm_timer.c +++ b/sound/core/pcm_timer.c @@ -1,6 +1,6 @@ /* * Digital Audio (PCM) abstract layer - * 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/core/rawmidi.c b/sound/core/rawmidi.c index e470c3c7d61..b8e700b94e5 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -1,6 +1,6 @@ /* * Abstract layer for MIDI v1.0 stream - * 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 @@ -30,14 +30,13 @@ #include <linux/mutex.h> #include <linux/moduleparam.h> #include <linux/delay.h> -#include <linux/wait.h> #include <sound/rawmidi.h> #include <sound/info.h> #include <sound/control.h> #include <sound/minors.h> #include <sound/initval.h> -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("Midlevel RawMidi code for ALSA."); MODULE_LICENSE("GPL"); diff --git a/sound/core/seq/Makefile b/sound/core/seq/Makefile index 402e2b4a34c..ceef14afee3 100644 --- a/sound/core/seq/Makefile +++ b/sound/core/seq/Makefile @@ -1,6 +1,6 @@ # # Makefile for ALSA -# Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz> +# Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz> # obj-$(CONFIG_SND) += instr/ diff --git a/sound/core/seq/instr/Makefile b/sound/core/seq/instr/Makefile index 69138f30a29..60896036481 100644 --- a/sound/core/seq/instr/Makefile +++ b/sound/core/seq/instr/Makefile @@ -1,6 +1,6 @@ # # Makefile for ALSA -# Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz> +# Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz> # snd-ainstr-fm-objs := ainstr_fm.o diff --git a/sound/core/seq/instr/ainstr_gf1.c b/sound/core/seq/instr/ainstr_gf1.c index c640e1cf854..49400262b1e 100644 --- a/sound/core/seq/instr/ainstr_gf1.c +++ b/sound/core/seq/instr/ainstr_gf1.c @@ -1,6 +1,6 @@ /* * GF1 (GUS) Patch - Instrument routines - * Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz> * * 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 @@ -26,7 +26,7 @@ #include <sound/initval.h> #include <asm/uaccess.h> -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("Advanced Linux Sound Architecture GF1 (GUS) Patch support."); MODULE_LICENSE("GPL"); diff --git a/sound/core/seq/instr/ainstr_iw.c b/sound/core/seq/instr/ainstr_iw.c index 5367baee2d0..6c40eb73fa9 100644 --- a/sound/core/seq/instr/ainstr_iw.c +++ b/sound/core/seq/instr/ainstr_iw.c @@ -1,6 +1,6 @@ /* * IWFFFF - AMD InterWave (tm) - Instrument routines - * Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz> * * 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 @@ -26,7 +26,7 @@ #include <sound/initval.h> #include <asm/uaccess.h> -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("Advanced Linux Sound Architecture IWFFFF support."); MODULE_LICENSE("GPL"); diff --git a/sound/core/seq/instr/ainstr_simple.c b/sound/core/seq/instr/ainstr_simple.c index ac717bef9d7..78f68bee24f 100644 --- a/sound/core/seq/instr/ainstr_simple.c +++ b/sound/core/seq/instr/ainstr_simple.c @@ -1,6 +1,6 @@ /* * Simple (MOD player) - Instrument routines - * Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz> * * 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 @@ -26,7 +26,7 @@ #include <sound/initval.h> #include <asm/uaccess.h> -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("Advanced Linux Sound Architecture Simple Instrument support."); MODULE_LICENSE("GPL"); diff --git a/sound/core/seq/oss/Makefile b/sound/core/seq/oss/Makefile index a37ddedf710..b38406b8463 100644 --- a/sound/core/seq/oss/Makefile +++ b/sound/core/seq/oss/Makefile @@ -1,6 +1,6 @@ # # Makefile for ALSA -# Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz> +# Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz> # snd-seq-oss-objs := seq_oss.o seq_oss_init.o seq_oss_timer.o seq_oss_ioctl.o \ diff --git a/sound/core/seq/oss/seq_oss_init.c b/sound/core/seq/oss/seq_oss_init.c index ca5a2ed4d7c..d0d721c22ea 100644 --- a/sound/core/seq/oss/seq_oss_init.c +++ b/sound/core/seq/oss/seq_oss_init.c @@ -176,29 +176,29 @@ snd_seq_oss_open(struct file *file, int level) int i, rc; struct seq_oss_devinfo *dp; - if ((dp = kzalloc(sizeof(*dp), GFP_KERNEL)) == NULL) { + dp = kzalloc(sizeof(*dp), GFP_KERNEL); + if (!dp) { snd_printk(KERN_ERR "can't malloc device info\n"); return -ENOMEM; } debug_printk(("oss_open: dp = %p\n", dp)); + dp->cseq = system_client; + dp->port = -1; + dp->queue = -1; + for (i = 0; i < SNDRV_SEQ_OSS_MAX_CLIENTS; i++) { if (client_table[i] == NULL) break; } + + dp->index = i; if (i >= SNDRV_SEQ_OSS_MAX_CLIENTS) { snd_printk(KERN_ERR "too many applications\n"); - kfree(dp); - return -ENOMEM; + rc = -ENOMEM; + goto _error; } - dp->index = i; - dp->cseq = system_client; - dp->port = -1; - dp->queue = -1; - dp->readq = NULL; - dp->writeq = NULL; - /* look up synth and midi devices */ snd_seq_oss_synth_setup(dp); snd_seq_oss_midi_setup(dp); @@ -211,14 +211,16 @@ snd_seq_oss_open(struct file *file, int level) /* create port */ debug_printk(("create new port\n")); - if ((rc = create_port(dp)) < 0) { + rc = create_port(dp); + if (rc < 0) { snd_printk(KERN_ERR "can't create port\n"); goto _error; } /* allocate queue */ debug_printk(("allocate queue\n")); - if ((rc = alloc_seq_queue(dp)) < 0) + rc = alloc_seq_queue(dp); + if (rc < 0) goto _error; /* set address */ @@ -235,7 +237,8 @@ snd_seq_oss_open(struct file *file, int level) /* initialize read queue */ debug_printk(("initialize read queue\n")); if (is_read_mode(dp->file_mode)) { - if ((dp->readq = snd_seq_oss_readq_new(dp, maxqlen)) == NULL) { + dp->readq = snd_seq_oss_readq_new(dp, maxqlen); + if (!dp->readq) { rc = -ENOMEM; goto _error; } @@ -245,7 +248,7 @@ snd_seq_oss_open(struct file *file, int level) debug_printk(("initialize write queue\n")); if (is_write_mode(dp->file_mode)) { dp->writeq = snd_seq_oss_writeq_new(dp, maxqlen); - if (dp->writeq == NULL) { + if (!dp->writeq) { rc = -ENOMEM; goto _error; } @@ -253,7 +256,8 @@ snd_seq_oss_open(struct file *file, int level) /* initialize timer */ debug_printk(("initialize timer\n")); - if ((dp->timer = snd_seq_oss_timer_new(dp)) == NULL) { + dp->timer = snd_seq_oss_timer_new(dp); + if (!dp->timer) { snd_printk(KERN_ERR "can't alloc timer\n"); rc = -ENOMEM; goto _error; @@ -276,11 +280,13 @@ snd_seq_oss_open(struct file *file, int level) return 0; _error: + snd_seq_oss_writeq_delete(dp->writeq); + snd_seq_oss_readq_delete(dp->readq); snd_seq_oss_synth_cleanup(dp); snd_seq_oss_midi_cleanup(dp); - i = dp->queue; delete_port(dp); - delete_seq_queue(i); + delete_seq_queue(dp->queue); + kfree(dp); return rc; } diff --git a/sound/core/seq/oss/seq_oss_writeq.c b/sound/core/seq/oss/seq_oss_writeq.c index 5c8495601a3..21742485819 100644 --- a/sound/core/seq/oss/seq_oss_writeq.c +++ b/sound/core/seq/oss/seq_oss_writeq.c @@ -63,8 +63,10 @@ snd_seq_oss_writeq_new(struct seq_oss_devinfo *dp, int maxlen) void snd_seq_oss_writeq_delete(struct seq_oss_writeq *q) { - snd_seq_oss_writeq_clear(q); /* to be sure */ - kfree(q); + if (q) { + snd_seq_oss_writeq_clear(q); /* to be sure */ + kfree(q); + } } diff --git a/sound/core/seq/seq.c b/sound/core/seq/seq.c index 2f0d8773ac6..1878208a802 100644 --- a/sound/core/seq/seq.c +++ b/sound/core/seq/seq.c @@ -53,7 +53,7 @@ int seq_default_timer_device = int seq_default_timer_subdevice = 0; int seq_default_timer_resolution = 0; /* Hz */ -MODULE_AUTHOR("Frank van de Pol <fvdpol@coil.demon.nl>, Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Frank van de Pol <fvdpol@coil.demon.nl>, Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("Advanced Linux Sound Architecture sequencer."); MODULE_LICENSE("GPL"); diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index b31b5282a2c..2e3fa25ab19 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -1,7 +1,7 @@ /* * ALSA sequencer Client Manager * Copyright (c) 1998-2001 by Frank van de Pol <fvdpol@coil.demon.nl> - * Jaroslav Kysela <perex@suse.cz> + * Jaroslav Kysela <perex@perex.cz> * Takashi Iwai <tiwai@suse.de> * * diff --git a/sound/core/seq/seq_instr.c b/sound/core/seq/seq_instr.c index 5efe6523a58..9a6fd56c910 100644 --- a/sound/core/seq/seq_instr.c +++ b/sound/core/seq/seq_instr.c @@ -1,6 +1,6 @@ /* * Generic Instrument routines for ALSA sequencer - * Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz> * * 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 @@ -26,7 +26,7 @@ #include <sound/seq_instr.h> #include <sound/initval.h> -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("Advanced Linux Sound Architecture sequencer instrument library."); MODULE_LICENSE("GPL"); @@ -109,7 +109,7 @@ void snd_seq_instr_list_free(struct snd_seq_kinstr_list **list_ptr) spin_lock_irqsave(&list->lock, flags); while (instr->use) { spin_unlock_irqrestore(&list->lock, flags); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); spin_lock_irqsave(&list->lock, flags); } spin_unlock_irqrestore(&list->lock, flags); @@ -198,8 +198,10 @@ int snd_seq_instr_list_free_cond(struct snd_seq_kinstr_list *list, while (flist) { instr = flist; flist = instr->next; - while (instr->use) - schedule_timeout(1); + while (instr->use) { + schedule_timeout_uninterruptible(1); + barrier(); + } if (snd_seq_instr_free(instr, atomic)<0) snd_printk(KERN_WARNING "instrument free problem\n"); instr = next; @@ -555,7 +557,7 @@ static int instr_free(struct snd_seq_kinstr_ops *ops, SNDRV_SEQ_INSTR_NOTIFY_REMOVE); while (instr->use) { spin_unlock_irqrestore(&list->lock, flags); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); spin_lock_irqsave(&list->lock, flags); } spin_unlock_irqrestore(&list->lock, flags); diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c index a3dc5e01e9f..a72a1945bf8 100644 --- a/sound/core/seq/seq_memory.c +++ b/sound/core/seq/seq_memory.c @@ -1,7 +1,7 @@ /* * ALSA sequencer Memory Manager * Copyright (c) 1998 by Frank van de Pol <fvdpol@coil.demon.nl> - * Jaroslav Kysela <perex@suse.cz> + * Jaroslav Kysela <perex@perex.cz> * 2000 by Takashi Iwai <tiwai@suse.de> * * This program is free software; you can redistribute it and/or modify diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c index 1daa5b069c7..5929aaf1df9 100644 --- a/sound/core/seq/seq_midi.c +++ b/sound/core/seq/seq_midi.c @@ -1,7 +1,7 @@ /* * Generic MIDI synth driver for ALSA sequencer * Copyright (c) 1998 by Frank van de Pol <fvdpol@coil.demon.nl> - * Jaroslav Kysela <perex@suse.cz> + * Jaroslav Kysela <perex@perex.cz> * * 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 @@ -40,7 +40,7 @@ Possible options for midisynth module: #include <sound/seq_midi_event.h> #include <sound/initval.h> -MODULE_AUTHOR("Frank van de Pol <fvdpol@coil.demon.nl>, Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Frank van de Pol <fvdpol@coil.demon.nl>, Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("Advanced Linux Sound Architecture sequencer MIDI synth."); MODULE_LICENSE("GPL"); static int output_buffer_size = PAGE_SIZE; diff --git a/sound/core/seq/seq_midi_event.c b/sound/core/seq/seq_midi_event.c index 5ff80b77690..b6820a5a73f 100644 --- a/sound/core/seq/seq_midi_event.c +++ b/sound/core/seq/seq_midi_event.c @@ -2,7 +2,7 @@ * MIDI byte <-> sequencer event coder * * Copyright (C) 1998,99 Takashi Iwai <tiwai@suse.de>, - * Jaroslav Kysela <perex@suse.cz> + * Jaroslav Kysela <perex@perex.cz> * * 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 @@ -28,14 +28,13 @@ #include <sound/seq_midi_event.h> #include <sound/asoundef.h> -MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>, Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>, Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("MIDI byte <-> sequencer event coder"); MODULE_LICENSE("GPL"); -/* queue type */ -/* from 0 to 7 are normal commands (note off, on, etc.) */ -#define ST_NOTEOFF 0 -#define ST_NOTEON 1 +/* event type, index into status_event[] */ +/* from 0 to 6 are normal commands (note off, on, etc.) for 0x9?-0xe? */ +#define ST_INVALID 7 #define ST_SPECIAL 8 #define ST_SYSEX ST_SPECIAL /* from 8 to 15 are events for 0xf0-0xf7 */ @@ -65,32 +64,33 @@ static struct status_event_list { void (*encode)(struct snd_midi_event *dev, struct snd_seq_event *ev); void (*decode)(struct snd_seq_event *ev, unsigned char *buf); } status_event[] = { - /* 0x80 - 0xf0 */ - {SNDRV_SEQ_EVENT_NOTEOFF, 2, note_event, note_decode}, - {SNDRV_SEQ_EVENT_NOTEON, 2, note_event, note_decode}, - {SNDRV_SEQ_EVENT_KEYPRESS, 2, note_event, note_decode}, - {SNDRV_SEQ_EVENT_CONTROLLER, 2, two_param_ctrl_event, two_param_decode}, - {SNDRV_SEQ_EVENT_PGMCHANGE, 1, one_param_ctrl_event, one_param_decode}, - {SNDRV_SEQ_EVENT_CHANPRESS, 1, one_param_ctrl_event, one_param_decode}, - {SNDRV_SEQ_EVENT_PITCHBEND, 2, pitchbend_ctrl_event, pitchbend_decode}, - {SNDRV_SEQ_EVENT_NONE, 0, NULL, NULL}, /* 0xf0 */ + /* 0x80 - 0xef */ + {SNDRV_SEQ_EVENT_NOTEOFF, 2, note_event, note_decode}, + {SNDRV_SEQ_EVENT_NOTEON, 2, note_event, note_decode}, + {SNDRV_SEQ_EVENT_KEYPRESS, 2, note_event, note_decode}, + {SNDRV_SEQ_EVENT_CONTROLLER, 2, two_param_ctrl_event, two_param_decode}, + {SNDRV_SEQ_EVENT_PGMCHANGE, 1, one_param_ctrl_event, one_param_decode}, + {SNDRV_SEQ_EVENT_CHANPRESS, 1, one_param_ctrl_event, one_param_decode}, + {SNDRV_SEQ_EVENT_PITCHBEND, 2, pitchbend_ctrl_event, pitchbend_decode}, + /* invalid */ + {SNDRV_SEQ_EVENT_NONE, -1, NULL, NULL}, /* 0xf0 - 0xff */ - {SNDRV_SEQ_EVENT_SYSEX, 1, NULL, NULL}, /* sysex: 0xf0 */ - {SNDRV_SEQ_EVENT_QFRAME, 1, one_param_event, one_param_decode}, /* 0xf1 */ - {SNDRV_SEQ_EVENT_SONGPOS, 2, songpos_event, songpos_decode}, /* 0xf2 */ - {SNDRV_SEQ_EVENT_SONGSEL, 1, one_param_event, one_param_decode}, /* 0xf3 */ - {SNDRV_SEQ_EVENT_NONE, 0, NULL, NULL}, /* 0xf4 */ - {SNDRV_SEQ_EVENT_NONE, 0, NULL, NULL}, /* 0xf5 */ - {SNDRV_SEQ_EVENT_TUNE_REQUEST, 0, NULL, NULL}, /* 0xf6 */ - {SNDRV_SEQ_EVENT_NONE, 0, NULL, NULL}, /* 0xf7 */ - {SNDRV_SEQ_EVENT_CLOCK, 0, NULL, NULL}, /* 0xf8 */ - {SNDRV_SEQ_EVENT_NONE, 0, NULL, NULL}, /* 0xf9 */ - {SNDRV_SEQ_EVENT_START, 0, NULL, NULL}, /* 0xfa */ - {SNDRV_SEQ_EVENT_CONTINUE, 0, NULL, NULL}, /* 0xfb */ - {SNDRV_SEQ_EVENT_STOP, 0, NULL, NULL}, /* 0xfc */ - {SNDRV_SEQ_EVENT_NONE, 0, NULL, NULL}, /* 0xfd */ - {SNDRV_SEQ_EVENT_SENSING, 0, NULL, NULL}, /* 0xfe */ - {SNDRV_SEQ_EVENT_RESET, 0, NULL, NULL}, /* 0xff */ + {SNDRV_SEQ_EVENT_SYSEX, 1, NULL, NULL}, /* sysex: 0xf0 */ + {SNDRV_SEQ_EVENT_QFRAME, 1, one_param_event, one_param_decode}, /* 0xf1 */ + {SNDRV_SEQ_EVENT_SONGPOS, 2, songpos_event, songpos_decode}, /* 0xf2 */ + {SNDRV_SEQ_EVENT_SONGSEL, 1, one_param_event, one_param_decode}, /* 0xf3 */ + {SNDRV_SEQ_EVENT_NONE, -1, NULL, NULL}, /* 0xf4 */ + {SNDRV_SEQ_EVENT_NONE, -1, NULL, NULL}, /* 0xf5 */ + {SNDRV_SEQ_EVENT_TUNE_REQUEST, 0, NULL, NULL}, /* 0xf6 */ + {SNDRV_SEQ_EVENT_NONE, -1, NULL, NULL}, /* 0xf7 */ + {SNDRV_SEQ_EVENT_CLOCK, 0, NULL, NULL}, /* 0xf8 */ + {SNDRV_SEQ_EVENT_NONE, -1, NULL, NULL}, /* 0xf9 */ + {SNDRV_SEQ_EVENT_START, 0, NULL, NULL}, /* 0xfa */ + {SNDRV_SEQ_EVENT_CONTINUE, 0, NULL, NULL}, /* 0xfb */ + {SNDRV_SEQ_EVENT_STOP, 0, NULL, NULL}, /* 0xfc */ + {SNDRV_SEQ_EVENT_NONE, -1, NULL, NULL}, /* 0xfd */ + {SNDRV_SEQ_EVENT_SENSING, 0, NULL, NULL}, /* 0xfe */ + {SNDRV_SEQ_EVENT_RESET, 0, NULL, NULL}, /* 0xff */ }; static int extra_decode_ctrl14(struct snd_midi_event *dev, unsigned char *buf, int len, @@ -129,6 +129,7 @@ int snd_midi_event_new(int bufsize, struct snd_midi_event **rdev) } dev->bufsize = bufsize; dev->lastcmd = 0xff; + dev->type = ST_INVALID; spin_lock_init(&dev->lock); *rdev = dev; return 0; @@ -149,7 +150,7 @@ static inline void reset_encode(struct snd_midi_event *dev) { dev->read = 0; dev->qlen = 0; - dev->type = 0; + dev->type = ST_INVALID; } void snd_midi_event_reset_encode(struct snd_midi_event *dev) @@ -251,29 +252,31 @@ int snd_midi_event_encode_byte(struct snd_midi_event *dev, int c, ev->type = status_event[ST_SPECIAL + c - 0xf0].event; ev->flags &= ~SNDRV_SEQ_EVENT_LENGTH_MASK; ev->flags |= SNDRV_SEQ_EVENT_LENGTH_FIXED; - return 1; + return ev->type != SNDRV_SEQ_EVENT_NONE; } spin_lock_irqsave(&dev->lock, flags); - if (dev->qlen > 0) { - /* rest of command */ - dev->buf[dev->read++] = c; - if (dev->type != ST_SYSEX) - dev->qlen--; - } else { + if ((c & 0x80) && + (c != MIDI_CMD_COMMON_SYSEX_END || dev->type != ST_SYSEX)) { /* new command */ + dev->buf[0] = c; + if ((c & 0xf0) == 0xf0) /* system messages */ + dev->type = (c & 0x0f) + ST_SPECIAL; + else + dev->type = (c >> 4) & 0x07; dev->read = 1; - if (c & 0x80) { - dev->buf[0] = c; - if ((c & 0xf0) == 0xf0) /* special events */ - dev->type = (c & 0x0f) + ST_SPECIAL; - else - dev->type = (c >> 4) & 0x07; - dev->qlen = status_event[dev->type].qlen; - } else { - /* process this byte as argument */ + dev->qlen = status_event[dev->type].qlen; + } else { + if (dev->qlen > 0) { + /* rest of command */ dev->buf[dev->read++] = c; + if (dev->type != ST_SYSEX) + dev->qlen--; + } else { + /* running status */ + dev->buf[1] = c; dev->qlen = status_event[dev->type].qlen - 1; + dev->read = 2; } } if (dev->qlen == 0) { @@ -282,6 +285,8 @@ int snd_midi_event_encode_byte(struct snd_midi_event *dev, int c, ev->flags |= SNDRV_SEQ_EVENT_LENGTH_FIXED; if (status_event[dev->type].encode) /* set data values */ status_event[dev->type].encode(dev, ev); + if (dev->type >= ST_SPECIAL) + dev->type = ST_INVALID; rc = 1; } else if (dev->type == ST_SYSEX) { if (c == MIDI_CMD_COMMON_SYSEX_END || diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c index eefd1cf872b..b6e23ad12ab 100644 --- a/sound/core/seq/seq_ports.c +++ b/sound/core/seq/seq_ports.c @@ -1,7 +1,7 @@ /* * ALSA sequencer Ports * Copyright (c) 1998 by Frank van de Pol <fvdpol@coil.demon.nl> - * Jaroslav Kysela <perex@suse.cz> + * Jaroslav Kysela <perex@perex.cz> * * * This program is free software; you can redistribute it and/or modify diff --git a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c index b4b9a132cb1..8716352afc8 100644 --- a/sound/core/seq/seq_timer.c +++ b/sound/core/seq/seq_timer.c @@ -1,7 +1,7 @@ /* * ALSA sequencer Timer * Copyright (c) 1998-1999 by Frank van de Pol <fvdpol@coil.demon.nl> - * Jaroslav Kysela <perex@suse.cz> + * Jaroslav Kysela <perex@perex.cz> * * * This program is free software; you can redistribute it and/or modify diff --git a/sound/core/sound.c b/sound/core/sound.c index 8dc7a3b32b9..7b486c4d70d 100644 --- a/sound/core/sound.c +++ b/sound/core/sound.c @@ -1,6 +1,6 @@ /* * Advanced Linux Sound Architecture - * 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 @@ -42,7 +42,7 @@ EXPORT_SYMBOL(snd_major); static int cards_limit = 1; -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("Advanced Linux Sound Architecture driver for soundcards."); MODULE_LICENSE("GPL"); module_param(major, int, 0444); @@ -266,6 +266,14 @@ int snd_register_device_for_dev(int type, struct snd_card *card, int dev, snd_minors[minor] = preg; preg->dev = device_create(sound_class, device, MKDEV(major, minor), "%s", name); + if (IS_ERR(preg->dev)) { + snd_minors[minor] = NULL; + mutex_unlock(&sound_mutex); + minor = PTR_ERR(preg->dev); + kfree(preg); + return minor; + } + if (preg->dev) dev_set_drvdata(preg->dev, private_data); diff --git a/sound/core/sound_oss.c b/sound/core/sound_oss.c index 4566df41912..dc73313b733 100644 --- a/sound/core/sound_oss.c +++ b/sound/core/sound_oss.c @@ -1,6 +1,6 @@ /* * Advanced Linux Sound Architecture - * 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/core/timer.c b/sound/core/timer.c index f2bbacedd56..e7dc56ca4b9 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -1,6 +1,6 @@ /* * Timers abstract layer - * 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 @@ #endif static int timer_limit = DEFAULT_TIMER_LIMIT; -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Takashi Iwai <tiwai@suse.de>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Takashi Iwai <tiwai@suse.de>"); MODULE_DESCRIPTION("ALSA timer interface"); MODULE_LICENSE("GPL"); module_param(timer_limit, int, 0444); diff --git a/sound/drivers/Makefile b/sound/drivers/Makefile index 04112642611..80aeff5ccde 100644 --- a/sound/drivers/Makefile +++ b/sound/drivers/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-dummy-objs := dummy.o diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index 4360ae9de19..e008f3c58ea 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c @@ -1,6 +1,6 @@ /* * Dummy 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 * it under the terms of the GNU General Public License as published by @@ -34,7 +34,7 @@ #include <sound/rawmidi.h> #include <sound/initval.h> -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("Dummy soundcard (/dev/null)"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{ALSA,Dummy soundcard}}"); @@ -510,15 +510,7 @@ static const DECLARE_TLV_DB_SCALE(db_scale_dummy, -4500, 30, 0); .get = snd_dummy_capsrc_get, .put = snd_dummy_capsrc_put, \ .private_value = addr } -static int snd_dummy_capsrc_info(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_dummy_capsrc_info snd_ctl_boolean_stereo_info static int snd_dummy_capsrc_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/drivers/mpu401/Makefile b/sound/drivers/mpu401/Makefile index 3fe185d19ae..918f83f34c1 100644 --- a/sound/drivers/mpu401/Makefile +++ b/sound/drivers/mpu401/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-mpu401-objs := mpu401.o diff --git a/sound/drivers/mpu401/mpu401.c b/sound/drivers/mpu401/mpu401.c index 67c6e974541..1fc95dadde1 100644 --- a/sound/drivers/mpu401/mpu401.c +++ b/sound/drivers/mpu401/mpu401.c @@ -1,6 +1,6 @@ /* * Driver for generic MPU-401 boards (UART mode only) - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * Copyright (c) 2004 by Castet Matthieu <castet.matthieu@free.fr> * * @@ -30,7 +30,7 @@ #include <sound/mpu401.h> #include <sound/initval.h> -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("MPU-401 UART"); MODULE_LICENSE("GPL"); @@ -70,6 +70,9 @@ static int snd_mpu401_create(int dev, struct snd_card **rcard) struct snd_card *card; int err; + if (!uart_enter[dev]) + snd_printk(KERN_ERR "the uart_enter option is obsolete; remove it\n"); + *rcard = NULL; card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); if (card == NULL) @@ -83,8 +86,7 @@ static int snd_mpu401_create(int dev, struct snd_card **rcard) strcat(card->longname, "polled"); } - err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, port[dev], - uart_enter[dev] ? 0 : MPU401_INFO_UART_ONLY, + err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, port[dev], 0, irq[dev], irq[dev] >= 0 ? IRQF_DISABLED : 0, NULL); if (err < 0) { diff --git a/sound/drivers/mpu401/mpu401_uart.c b/sound/drivers/mpu401/mpu401_uart.c index 85aedc348e2..3306ecd4924 100644 --- a/sound/drivers/mpu401/mpu401_uart.c +++ b/sound/drivers/mpu401/mpu401_uart.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 MPU-401 in UART mode * * MPU-401 supports UART mode which is not capable generate transmit @@ -39,7 +39,7 @@ #include <sound/core.h> #include <sound/mpu401.h> -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("Routines for control of MPU-401 in UART mode"); MODULE_LICENSE("GPL"); @@ -270,8 +270,7 @@ static int snd_mpu401_do_reset(struct snd_mpu401 *mpu) { if (snd_mpu401_uart_cmd(mpu, MPU401_RESET, 1)) return -EIO; - if (!(mpu->info_flags & MPU401_INFO_UART_ONLY) && - snd_mpu401_uart_cmd(mpu, MPU401_ENTER_UART, 1)) + if (snd_mpu401_uart_cmd(mpu, MPU401_ENTER_UART, 0)) return -EIO; return 0; } diff --git a/sound/drivers/mts64.c b/sound/drivers/mts64.c index 2025db5947a..911c159bb3d 100644 --- a/sound/drivers/mts64.c +++ b/sound/drivers/mts64.c @@ -440,15 +440,7 @@ static void mts64_write_midi(struct mts64 *mts, u8 c, *********************************************************************/ /* SMPTE Switch */ -static int snd_mts64_ctl_smpte_switch_info(struct snd_kcontrol *kctl, - 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_mts64_ctl_smpte_switch_info snd_ctl_boolean_mono_info static int snd_mts64_ctl_smpte_switch_get(struct snd_kcontrol* kctl, struct snd_ctl_elem_value *uctl) diff --git a/sound/drivers/opl3/Makefile b/sound/drivers/opl3/Makefile index 12059785b5c..19767a6a5c5 100644 --- a/sound/drivers/opl3/Makefile +++ b/sound/drivers/opl3/Makefile @@ -1,13 +1,11 @@ # # Makefile for ALSA -# Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz> +# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz> # snd-opl3-lib-objs := opl3_lib.o opl3_synth.o -snd-opl3-synth-objs := opl3_seq.o opl3_midi.o opl3_drums.o -ifeq ($(CONFIG_SND_SEQUENCER_OSS),y) -snd-opl3-synth-objs += opl3_oss.o -endif +snd-opl3-synth-y := opl3_seq.o opl3_midi.o opl3_drums.o +snd-opl3-synth-$(CONFIG_SND_SEQUENCER_OSS) += opl3_oss.o # # this function returns: diff --git a/sound/drivers/opl3/opl3_lib.c b/sound/drivers/opl3/opl3_lib.c index 87fe376f38f..a2b9ce06029 100644 --- a/sound/drivers/opl3/opl3_lib.c +++ b/sound/drivers/opl3/opl3_lib.c @@ -1,5 +1,5 @@ /* - * Copyright (c) by Jaroslav Kysela <perex@suse.cz>, + * Copyright (c) by Jaroslav Kysela <perex@perex.cz>, * Hannu Savolainen 1993-1996, * Rob Hooft * @@ -31,7 +31,7 @@ #include <linux/ioport.h> #include <sound/minors.h> -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Hannu Savolainen 1993-1996, Rob Hooft"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Hannu Savolainen 1993-1996, Rob Hooft"); MODULE_DESCRIPTION("Routines for control of AdLib FM cards (OPL2/OPL3/OPL4 chips)"); MODULE_LICENSE("GPL"); diff --git a/sound/drivers/opl4/Makefile b/sound/drivers/opl4/Makefile index 141aacbaf31..d178b39ffa6 100644 --- a/sound/drivers/opl4/Makefile +++ b/sound/drivers/opl4/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-opl4-lib-objs := opl4_lib.o opl4_mixer.o opl4_proc.o diff --git a/sound/drivers/serial-u16550.c b/sound/drivers/serial-u16550.c index d3e6a20edd3..65de3a755dd 100644 --- a/sound/drivers/serial-u16550.c +++ b/sound/drivers/serial-u16550.c @@ -1,6 +1,6 @@ /* * serial.c - * Copyright (c) by Jaroslav Kysela <perex@suse.cz>, + * Copyright (c) by Jaroslav Kysela <perex@perex.cz>, * Isaku Yamahata <yamahata@private.email.ne.jp>, * George Hansper <ghansper@apana.org.au>, * Hannu Savolainen diff --git a/sound/drivers/vx/Makefile b/sound/drivers/vx/Makefile index 269bd8544a5..9a168a3c156 100644 --- a/sound/drivers/vx/Makefile +++ b/sound/drivers/vx/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-vx-lib-objs := vx_core.o vx_hwdep.o vx_pcm.o vx_mixer.o vx_cmd.o vx_uer.o diff --git a/sound/drivers/vx/vx_mixer.c b/sound/drivers/vx/vx_mixer.c index f63152a6a22..b8fcd79a7e1 100644 --- a/sound/drivers/vx/vx_mixer.c +++ b/sound/drivers/vx/vx_mixer.c @@ -647,14 +647,7 @@ static int vx_audio_monitor_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el return 0; } -static int vx_audio_sw_info(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 vx_audio_sw_info snd_ctl_boolean_stereo_info static int vx_audio_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -865,14 +858,7 @@ static int vx_peak_meter_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_ return 0; } -static int vx_saturation_info(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 vx_saturation_info snd_ctl_boolean_stereo_info static int vx_saturation_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { diff --git a/sound/i2c/Makefile b/sound/i2c/Makefile index 45902d48c89..37970666a45 100644 --- a/sound/i2c/Makefile +++ b/sound/i2c/Makefile @@ -1,15 +1,13 @@ # # Makefile for ALSA -# Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz> +# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz> # snd-i2c-objs := i2c.o snd-cs8427-objs := cs8427.o snd-tea6330t-objs := tea6330t.o -ifeq ($(subst m,y,$(CONFIG_L3)),y) - obj-$(CONFIG_L3) += l3/ -endif +obj-$(CONFIG_L3) += l3/ obj-$(CONFIG_SND) += other/ diff --git a/sound/i2c/cs8427.c b/sound/i2c/cs8427.c index 64388cb8d6e..744366b7234 100644 --- a/sound/i2c/cs8427.c +++ b/sound/i2c/cs8427.c @@ -1,7 +1,7 @@ /* * Routines for control of the CS8427 via i2c bus * IEC958 (S/PDIF) receiver & transmitter by Cirrus Logic - * 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 @@ static void snd_cs8427_reset(struct snd_i2c_device *cs8427); -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("IEC958 (S/PDIF) receiver & transmitter by Cirrus Logic"); MODULE_LICENSE("GPL"); @@ -229,6 +229,12 @@ int snd_cs8427_create(struct snd_i2c_bus *bus, snd_i2c_lock(bus); err = snd_cs8427_reg_read(device, CS8427_REG_ID_AND_VER); if (err != CS8427_VER8427A) { + /* give second chance */ + snd_printk(KERN_WARNING "invalid CS8427 signature 0x%x: " + "let me try again...\n", err); + err = snd_cs8427_reg_read(device, CS8427_REG_ID_AND_VER); + } + if (err != CS8427_VER8427A) { snd_i2c_unlock(bus); snd_printk(KERN_ERR "unable to find CS8427 signature " "(expected 0x%x, read 0x%x),\n", diff --git a/sound/i2c/i2c.c b/sound/i2c/i2c.c index b60fb189282..1e58a963b2a 100644 --- a/sound/i2c/i2c.c +++ b/sound/i2c/i2c.c @@ -2,7 +2,7 @@ * Generic i2c interface for ALSA * * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de> - * Modified for the ALSA driver by Jaroslav Kysela <perex@suse.cz> + * Modified for the ALSA driver by Jaroslav Kysela <perex@perex.cz> * * 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 @@ -28,7 +28,7 @@ #include <sound/core.h> #include <sound/i2c.h> -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("Generic i2c interface for ALSA"); MODULE_LICENSE("GPL"); diff --git a/sound/i2c/other/Makefile b/sound/i2c/other/Makefile index 77a8a7c75dd..703d954238f 100644 --- a/sound/i2c/other/Makefile +++ b/sound/i2c/other/Makefile @@ -1,6 +1,6 @@ # # Makefile for ALSA -# Copyright (c) 2003 by Jaroslav Kysela <perex@suse.cz> +# Copyright (c) 2003 by Jaroslav Kysela <perex@perex.cz> # snd-ak4114-objs := ak4114.o diff --git a/sound/i2c/other/ak4114.c b/sound/i2c/other/ak4114.c index 1efb973137a..facde46f957 100644 --- a/sound/i2c/other/ak4114.c +++ b/sound/i2c/other/ak4114.c @@ -1,7 +1,7 @@ /* * Routines for control of the AK4114 via I2C and 4-wire serial interface * IEC958 (S/PDIF) receiver by Asahi Kasei - * 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 @@ -29,7 +29,7 @@ #include <sound/ak4114.h> #include <sound/asoundef.h> -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("AK4114 IEC958 (S/PDIF) receiver by Asahi Kasei"); MODULE_LICENSE("GPL"); @@ -200,15 +200,7 @@ static int snd_ak4114_in_error_get(struct snd_kcontrol *kcontrol, return 0; } -static int snd_ak4114_in_bit_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_ak4114_in_bit_info snd_ctl_boolean_mono_info static int snd_ak4114_in_bit_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/i2c/other/ak4117.c b/sound/i2c/other/ak4117.c index c022f29da2f..ee1585aec99 100644 --- a/sound/i2c/other/ak4117.c +++ b/sound/i2c/other/ak4117.c @@ -1,7 +1,7 @@ /* * Routines for control of the AK4117 via 4-wire serial interface * IEC958 (S/PDIF) receiver by Asahi Kasei - * 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 @@ -29,7 +29,7 @@ #include <sound/ak4117.h> #include <sound/asoundef.h> -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("AK4117 IEC958 (S/PDIF) receiver by Asahi Kasei"); MODULE_LICENSE("GPL"); @@ -181,15 +181,7 @@ static int snd_ak4117_in_error_get(struct snd_kcontrol *kcontrol, return 0; } -static int snd_ak4117_in_bit_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_ak4117_in_bit_info snd_ctl_boolean_mono_info static int snd_ak4117_in_bit_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c index fd335159f84..de03f689fa2 100644 --- a/sound/i2c/other/ak4xxx-adda.c +++ b/sound/i2c/other/ak4xxx-adda.c @@ -2,7 +2,7 @@ * ALSA driver for AK4524 / AK4528 / AK4529 / AK4355 / AK4358 / AK4381 * AD and DA converters * - * Copyright (c) 2000-2004 Jaroslav Kysela <perex@suse.cz>, + * Copyright (c) 2000-2004 Jaroslav Kysela <perex@perex.cz>, * Takashi Iwai <tiwai@suse.de> * * This program is free software; you can redistribute it and/or modify @@ -31,7 +31,7 @@ #include <sound/tlv.h> #include <sound/ak4xxx-adda.h> -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Takashi Iwai <tiwai@suse.de>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Takashi Iwai <tiwai@suse.de>"); MODULE_DESCRIPTION("Routines for control of AK452x / AK43xx AD/DA converters"); MODULE_LICENSE("GPL"); @@ -463,15 +463,7 @@ static int snd_akm4xxx_deemphasis_put(struct snd_kcontrol *kcontrol, return change; } -static int ak4xxx_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 ak4xxx_switch_info snd_ctl_boolean_mono_info static int ak4xxx_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/i2c/other/pt2258.c b/sound/i2c/other/pt2258.c index e91cc3b44de..00c83d8b32b 100644 --- a/sound/i2c/other/pt2258.c +++ b/sound/i2c/other/pt2258.c @@ -140,15 +140,7 @@ static int pt2258_stereo_volume_put(struct snd_kcontrol *kcontrol, return -EIO; } -static int pt2258_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 pt2258_switch_info snd_ctl_boolean_mono_info static int pt2258_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/i2c/other/tea575x-tuner.c b/sound/i2c/other/tea575x-tuner.c index 4c2fd14c105..fe31bb5cffb 100644 --- a/sound/i2c/other/tea575x-tuner.c +++ b/sound/i2c/other/tea575x-tuner.c @@ -1,7 +1,7 @@ /* * ALSA driver for TEA5757/5759 Philips AM/FM radio tuner chips * - * Copyright (c) 2004 Jaroslav Kysela <perex@suse.cz> + * Copyright (c) 2004 Jaroslav Kysela <perex@perex.cz> * * * This program is free software; you can redistribute it and/or modify @@ -28,7 +28,7 @@ #include <sound/core.h> #include <sound/tea575x-tuner.h> -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("Routines for control of TEA5757/5759 Philips AM/FM radio tuner chips"); MODULE_LICENSE("GPL"); diff --git a/sound/i2c/tea6330t.c b/sound/i2c/tea6330t.c index ae5b1e3a68c..9bab744af0e 100644 --- a/sound/i2c/tea6330t.c +++ b/sound/i2c/tea6330t.c @@ -1,7 +1,7 @@ /* * Routines for control of the TEA6330T circuit via i2c bus * Sound fader control circuit for car radios by Philips Semiconductors - * 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 @@ -27,7 +27,7 @@ #include <sound/control.h> #include <sound/tea6330t.h> -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("Routines for control of the TEA6330T circuit via i2c bus"); MODULE_LICENSE("GPL"); @@ -142,15 +142,7 @@ static int snd_tea6330t_put_master_volume(struct snd_kcontrol *kcontrol, .info = snd_tea6330t_info_master_switch, \ .get = snd_tea6330t_get_master_switch, .put = snd_tea6330t_put_master_switch } -static int snd_tea6330t_info_master_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_tea6330t_info_master_switch snd_ctl_boolean_stereo_info static int snd_tea6330t_get_master_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig index ea5084abe60..2639a6ab8f2 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 bb317ccc170..c0ce7db2a1b 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 90e00e842e4..487ab23860e 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 ec9209cd517..cf18fe4617a 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 45d59998aa6..ae23331e920 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 d09a7fa8654..a4710b5e214 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 1bc2e3fd572..a901cd1ee69 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 2fb4f7409d7..5067ee00193 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 ac404113415..13db6842eaa 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 914d77b61b0..a5eb9659b51 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 1a14f33b6ab..5784b43f412 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 7a5a6c71f5e..6bd064470d4 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 501c8bf903a..aee1e4ddb22 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 edc398712e8..74bbc92f2e7 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 a2ab99f2ac3..5c26d495daa 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 f7732bf90be..4a7367a8ff9 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 bae5dbd6c8e..df3d59f25f5 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 44ee5d3674a..fc905141e8a 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 f22fe7967fc..9eaa932f6ef 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 d0c38e1856e..bf137ea7232 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 9b1fe292de4..3d4f899285e 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 537d3cfe41f..cd9a6f1c99e 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 8ced5e81b9a..b14d5d6d9a3 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 7107753b85b..bcf4656853c 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 80f0a83818b..f69a44728eb 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 acc25a29720..a96253e1665 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 c7f95e7aa01..a7971f5ffe6 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 b263655c411..20cfdb87f84 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 9e0c55ab25b..cba0829a710 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 dcad6ed0198..39d121e2c8c 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 3e4d4d6edd8..2c2051782aa 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 4adf098d326..42a4ca0d622 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 a43b662f17c..99eac573c41 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 654290a8b21..e6fd9b01c49 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 dbbc0a6d765..71a67744a14 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 8f23f433d49..29e422b00b5 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 0aeaa6cf6cf..fc59536c918 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 708783d4351..4922f5da08f 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 0220cdbe1a2..2091c50b2e3 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 e70db32991d..59af9ab7191 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 0e41bfd5a40..b4d894db257 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 cd29b30b362..d295936611f 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 049d479ce2b..ee1a824d8fc 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 556e6692802..c9d1c986d70 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 658179e8614..4eea84cfd4f 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 3d72742b342..0c7905c85b7 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 c4ba24bfd27..e7f9edd9262 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 b279f2308ae..3682059787a 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 5d4d3aafe2d..c06754f7ee5 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 a1b3786b391..f933aef7d8a 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 aea9e5ec7b3..bee894b3f5c 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 0b67edd7ac6..e56e5633411 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 efa9d5c2558..176193c0510 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 3d4befcff28..03241cd5aae 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 00000000000..94daf839999 --- /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 cbad2a51cba..1cb921d6137 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 b4cb28422db..601bdddd44d 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 bacc51c8658..a1ebb7c5c68 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); diff --git a/sound/last.c b/sound/last.c index 964314efff5..282b0cdb058 100644 --- a/sound/last.c +++ b/sound/last.c @@ -1,6 +1,6 @@ /* * Advanced Linux Sound Architecture - * 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/oss/Makefile b/sound/oss/Makefile index 1200670017b..f883c4b676a 100644 --- a/sound/oss/Makefile +++ b/sound/oss/Makefile @@ -36,7 +36,6 @@ obj-$(CONFIG_SOUND_MSNDCLAS) += msnd.o msnd_classic.o obj-$(CONFIG_SOUND_MSNDPIN) += msnd.o msnd_pinnacle.o obj-$(CONFIG_SOUND_VWSND) += vwsnd.o obj-$(CONFIG_SOUND_ICH) += i810_audio.o ac97_codec.o -obj-$(CONFIG_SOUND_ES1371) += es1371.o ac97_codec.o obj-$(CONFIG_SOUND_AU1550_AC97) += au1550_ac97.o ac97_codec.o obj-$(CONFIG_SOUND_TRIDENT) += trident.o ac97_codec.o obj-$(CONFIG_SOUND_BCM_CS4297A) += swarm_cs4297a.o diff --git a/sound/oss/dmasound/Makefile b/sound/oss/dmasound/Makefile index 4611636b1a8..3c1531652d1 100644 --- a/sound/oss/dmasound/Makefile +++ b/sound/oss/dmasound/Makefile @@ -2,12 +2,6 @@ # Makefile for the DMA sound driver # -dmasound_pmac-y += dmasound_awacs.o \ - trans_16.o dac3550a.o tas_common.o \ - tas3001c.o tas3001c_tables.o \ - tas3004.o tas3004_tables.o - obj-$(CONFIG_DMASOUND_ATARI) += dmasound_core.o dmasound_atari.o -obj-$(CONFIG_DMASOUND_PMAC) += dmasound_core.o dmasound_pmac.o obj-$(CONFIG_DMASOUND_PAULA) += dmasound_core.o dmasound_paula.o obj-$(CONFIG_DMASOUND_Q40) += dmasound_core.o dmasound_q40.o diff --git a/sound/oss/dmasound/awacs_defs.h b/sound/oss/dmasound/awacs_defs.h deleted file mode 100644 index 2194f46b046..00000000000 --- a/sound/oss/dmasound/awacs_defs.h +++ /dev/null @@ -1,251 +0,0 @@ -/*********************************************************/ -/* This file was written by someone, somewhere, sometime */ -/* And is released into the Public Domain */ -/*********************************************************/ - -#ifndef _AWACS_DEFS_H_ -#define _AWACS_DEFS_H_ - -/*******************************/ -/* AWACs Audio Register Layout */ -/*******************************/ - -struct awacs_regs { - unsigned control; /* Audio control register */ - unsigned pad0[3]; - unsigned codec_ctrl; /* Codec control register */ - unsigned pad1[3]; - unsigned codec_stat; /* Codec status register */ - unsigned pad2[3]; - unsigned clip_count; /* Clipping count register */ - unsigned pad3[3]; - unsigned byteswap; /* Data is little-endian if 1 */ -}; - -/*******************/ -/* Audio Bit Masks */ -/*******************/ - -/* Audio Control Reg Bit Masks */ -/* ----- ------- --- --- ----- */ -#define MASK_ISFSEL (0xf) /* Input SubFrame Select */ -#define MASK_OSFSEL (0xf << 4) /* Output SubFrame Select */ -#define MASK_RATE (0x7 << 8) /* Sound Rate */ -#define MASK_CNTLERR (0x1 << 11) /* Error */ -#define MASK_PORTCHG (0x1 << 12) /* Port Change */ -#define MASK_IEE (0x1 << 13) /* Enable Interrupt on Error */ -#define MASK_IEPC (0x1 << 14) /* Enable Interrupt on Port Change */ -#define MASK_SSFSEL (0x3 << 15) /* Status SubFrame Select */ - -/* Audio Codec Control Reg Bit Masks */ -/* ----- ----- ------- --- --- ----- */ -#define MASK_NEWECMD (0x1 << 24) /* Lock: don't write to reg when 1 */ -#define MASK_EMODESEL (0x3 << 22) /* Send info out on which frame? */ -#define MASK_EXMODEADDR (0x3ff << 12) /* Extended Mode Address -- 10 bits */ -#define MASK_EXMODEDATA (0xfff) /* Extended Mode Data -- 12 bits */ - -/* Audio Codec Control Address Values / Masks */ -/* ----- ----- ------- ------- ------ - ----- */ -#define MASK_ADDR0 (0x0 << 12) /* Expanded Data Mode Address 0 */ -#define MASK_ADDR_MUX MASK_ADDR0 /* Mux Control */ -#define MASK_ADDR_GAIN MASK_ADDR0 - -#define MASK_ADDR1 (0x1 << 12) /* Expanded Data Mode Address 1 */ -#define MASK_ADDR_MUTE MASK_ADDR1 -#define MASK_ADDR_RATE MASK_ADDR1 - -#define MASK_ADDR2 (0x2 << 12) /* Expanded Data Mode Address 2 */ -#define MASK_ADDR_VOLA MASK_ADDR2 /* Volume Control A -- Headphones */ -#define MASK_ADDR_VOLHD MASK_ADDR2 - -#define MASK_ADDR4 (0x4 << 12) /* Expanded Data Mode Address 4 */ -#define MASK_ADDR_VOLC MASK_ADDR4 /* Volume Control C -- Speaker */ -#define MASK_ADDR_VOLSPK MASK_ADDR4 - -/* additional registers of screamer */ -#define MASK_ADDR5 (0x5 << 12) /* Expanded Data Mode Address 5 */ -#define MASK_ADDR6 (0x6 << 12) /* Expanded Data Mode Address 6 */ -#define MASK_ADDR7 (0x7 << 12) /* Expanded Data Mode Address 7 */ - -/* Address 0 Bit Masks & Macros */ -/* ------- - --- ----- - ------ */ -#define MASK_GAINRIGHT (0xf) /* Gain Right Mask */ -#define MASK_GAINLEFT (0xf << 4) /* Gain Left Mask */ -#define MASK_GAINLINE (0x1 << 8) /* Disable Mic preamp */ -#define MASK_GAINMIC (0x0 << 8) /* Enable Mic preamp */ - -#define MASK_MUX_CD (0x1 << 9) /* Select CD in MUX */ -#define MASK_MUX_MIC (0x1 << 10) /* Select Mic in MUX */ -#define MASK_MUX_AUDIN (0x1 << 11) /* Select Audio In in MUX */ -#define MASK_MUX_LINE MASK_MUX_AUDIN - -#define GAINRIGHT(x) ((x) & MASK_GAINRIGHT) -#define GAINLEFT(x) (((x) << 4) & MASK_GAINLEFT) - -#define DEF_CD_GAIN 0x00bb -#define DEF_MIC_GAIN 0x00cc - -/* Address 1 Bit Masks */ -/* ------- - --- ----- */ -#define MASK_ADDR1RES1 (0x3) /* Reserved */ -#define MASK_RECALIBRATE (0x1 << 2) /* Recalibrate */ -#define MASK_SAMPLERATE (0x7 << 3) /* Sample Rate: */ -#define MASK_LOOPTHRU (0x1 << 6) /* Loopthrough Enable */ -#define MASK_CMUTE (0x1 << 7) /* Output C (Speaker) Mute when 1 */ -#define MASK_SPKMUTE MASK_CMUTE -#define MASK_ADDR1RES2 (0x1 << 8) /* Reserved */ -#define MASK_AMUTE (0x1 << 9) /* Output A (Headphone) Mute when 1 */ -#define MASK_HDMUTE MASK_AMUTE -#define MASK_PAROUT0 (0x1 << 10) /* Parallel Output 0 */ -#define MASK_PAROUT1 (0x2 << 10) /* Parallel Output 1 */ - -#define MASK_MIC_BOOST (0x4) /* screamer mic boost */ - -#define SAMPLERATE_48000 (0x0 << 3) /* 48 or 44.1 kHz */ -#define SAMPLERATE_32000 (0x1 << 3) /* 32 or 29.4 kHz */ -#define SAMPLERATE_24000 (0x2 << 3) /* 24 or 22.05 kHz */ -#define SAMPLERATE_19200 (0x3 << 3) /* 19.2 or 17.64 kHz */ -#define SAMPLERATE_16000 (0x4 << 3) /* 16 or 14.7 kHz */ -#define SAMPLERATE_12000 (0x5 << 3) /* 12 or 11.025 kHz */ -#define SAMPLERATE_9600 (0x6 << 3) /* 9.6 or 8.82 kHz */ -#define SAMPLERATE_8000 (0x7 << 3) /* 8 or 7.35 kHz */ - -/* Address 2 & 4 Bit Masks & Macros */ -/* ------- - - - --- ----- - ------ */ -#define MASK_OUTVOLRIGHT (0xf) /* Output Right Volume */ -#define MASK_ADDR2RES1 (0x2 << 4) /* Reserved */ -#define MASK_ADDR4RES1 MASK_ADDR2RES1 -#define MASK_OUTVOLLEFT (0xf << 6) /* Output Left Volume */ -#define MASK_ADDR2RES2 (0x2 << 10) /* Reserved */ -#define MASK_ADDR4RES2 MASK_ADDR2RES2 - -#define VOLRIGHT(x) (((~(x)) & MASK_OUTVOLRIGHT)) -#define VOLLEFT(x) (((~(x)) << 6) & MASK_OUTVOLLEFT) - -/* Audio Codec Status Reg Bit Masks */ -/* ----- ----- ------ --- --- ----- */ -#define MASK_EXTEND (0x1 << 23) /* Extend */ -#define MASK_VALID (0x1 << 22) /* Valid Data? */ -#define MASK_OFLEFT (0x1 << 21) /* Overflow Left */ -#define MASK_OFRIGHT (0x1 << 20) /* Overflow Right */ -#define MASK_ERRCODE (0xf << 16) /* Error Code */ -#define MASK_REVISION (0xf << 12) /* Revision Number */ -#define MASK_MFGID (0xf << 8) /* Mfg. ID */ -#define MASK_CODSTATRES (0xf << 4) /* bits 4 - 7 reserved */ -#define MASK_INPPORT (0xf) /* Input Port */ -#define MASK_HDPCONN 8 /* headphone plugged in */ - -/* Clipping Count Reg Bit Masks */ -/* -------- ----- --- --- ----- */ -#define MASK_CLIPLEFT (0xff << 7) /* Clipping Count, Left Channel */ -#define MASK_CLIPRIGHT (0xff) /* Clipping Count, Right Channel */ - -/* DBDMA ChannelStatus Bit Masks */ -/* ----- ------------- --- ----- */ -#define MASK_CSERR (0x1 << 7) /* Error */ -#define MASK_EOI (0x1 << 6) /* End of Input -- only for Input Channel */ -#define MASK_CSUNUSED (0x1f << 1) /* bits 1-5 not used */ -#define MASK_WAIT (0x1) /* Wait */ - -/* Various Rates */ -/* ------- ----- */ -#define RATE_48000 (0x0 << 8) /* 48 kHz */ -#define RATE_44100 (0x0 << 8) /* 44.1 kHz */ -#define RATE_32000 (0x1 << 8) /* 32 kHz */ -#define RATE_29400 (0x1 << 8) /* 29.4 kHz */ -#define RATE_24000 (0x2 << 8) /* 24 kHz */ -#define RATE_22050 (0x2 << 8) /* 22.05 kHz */ -#define RATE_19200 (0x3 << 8) /* 19.2 kHz */ -#define RATE_17640 (0x3 << 8) /* 17.64 kHz */ -#define RATE_16000 (0x4 << 8) /* 16 kHz */ -#define RATE_14700 (0x4 << 8) /* 14.7 kHz */ -#define RATE_12000 (0x5 << 8) /* 12 kHz */ -#define RATE_11025 (0x5 << 8) /* 11.025 kHz */ -#define RATE_9600 (0x6 << 8) /* 9.6 kHz */ -#define RATE_8820 (0x6 << 8) /* 8.82 kHz */ -#define RATE_8000 (0x7 << 8) /* 8 kHz */ -#define RATE_7350 (0x7 << 8) /* 7.35 kHz */ - -#define RATE_LOW 1 /* HIGH = 48kHz, etc; LOW = 44.1kHz, etc. */ - -/*******************/ -/* Burgundy values */ -/*******************/ - -#define MASK_ADDR_BURGUNDY_INPSEL21 (0x11 << 12) -#define MASK_ADDR_BURGUNDY_INPSEL3 (0x12 << 12) - -#define MASK_ADDR_BURGUNDY_GAINCH1 (0x13 << 12) -#define MASK_ADDR_BURGUNDY_GAINCH2 (0x14 << 12) -#define MASK_ADDR_BURGUNDY_GAINCH3 (0x15 << 12) -#define MASK_ADDR_BURGUNDY_GAINCH4 (0x16 << 12) - -#define MASK_ADDR_BURGUNDY_VOLCH1 (0x20 << 12) -#define MASK_ADDR_BURGUNDY_VOLCH2 (0x21 << 12) -#define MASK_ADDR_BURGUNDY_VOLCH3 (0x22 << 12) -#define MASK_ADDR_BURGUNDY_VOLCH4 (0x23 << 12) - -#define MASK_ADDR_BURGUNDY_OUTPUTSELECTS (0x2B << 12) -#define MASK_ADDR_BURGUNDY_OUTPUTENABLES (0x2F << 12) - -#define MASK_ADDR_BURGUNDY_MASTER_VOLUME (0x30 << 12) - -#define MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES (0x60 << 12) - -#define MASK_ADDR_BURGUNDY_ATTENSPEAKER (0x62 << 12) -#define MASK_ADDR_BURGUNDY_ATTENLINEOUT (0x63 << 12) -#define MASK_ADDR_BURGUNDY_ATTENHP (0x64 << 12) - -#define MASK_ADDR_BURGUNDY_VOLCD (MASK_ADDR_BURGUNDY_VOLCH1) -#define MASK_ADDR_BURGUNDY_VOLLINE (MASK_ADDR_BURGUNDY_VOLCH2) -#define MASK_ADDR_BURGUNDY_VOLMIC (MASK_ADDR_BURGUNDY_VOLCH3) -#define MASK_ADDR_BURGUNDY_VOLMODEM (MASK_ADDR_BURGUNDY_VOLCH4) - -#define MASK_ADDR_BURGUNDY_GAINCD (MASK_ADDR_BURGUNDY_GAINCH1) -#define MASK_ADDR_BURGUNDY_GAINLINE (MASK_ADDR_BURGUNDY_GAINCH2) -#define MASK_ADDR_BURGUNDY_GAINMIC (MASK_ADDR_BURGUNDY_GAINCH3) -#define MASK_ADDR_BURGUNDY_GAINMODEM (MASK_ADDR_BURGUNDY_VOLCH4) - - -/* These are all default values for the burgundy */ -#define DEF_BURGUNDY_INPSEL21 (0xAA) -#define DEF_BURGUNDY_INPSEL3 (0x0A) - -#define DEF_BURGUNDY_GAINCD (0x33) -#define DEF_BURGUNDY_GAINLINE (0x44) -#define DEF_BURGUNDY_GAINMIC (0x44) -#define DEF_BURGUNDY_GAINMODEM (0x06) - -/* Remember: lowest volume here is 0x9b */ -#define DEF_BURGUNDY_VOLCD (0xCCCCCCCC) -#define DEF_BURGUNDY_VOLLINE (0x00000000) -#define DEF_BURGUNDY_VOLMIC (0x00000000) -#define DEF_BURGUNDY_VOLMODEM (0xCCCCCCCC) - -#define DEF_BURGUNDY_OUTPUTSELECTS (0x010f010f) -#define DEF_BURGUNDY_OUTPUTENABLES (0x0A) - -#define DEF_BURGUNDY_MASTER_VOLUME (0xFFFFFFFF) - -#define DEF_BURGUNDY_MORE_OUTPUTENABLES (0x7E) - -#define DEF_BURGUNDY_ATTENSPEAKER (0x44) -#define DEF_BURGUNDY_ATTENLINEOUT (0xCC) -#define DEF_BURGUNDY_ATTENHP (0xCC) - -/*********************/ -/* i2s layout values */ -/*********************/ - -#define I2S_REG_INT_CTL 0x00 -#define I2S_REG_SERIAL_FORMAT 0x10 -#define I2S_REG_CODEC_MSG_OUT 0x20 -#define I2S_REG_CODEC_MSG_IN 0x30 -#define I2S_REG_FRAME_COUNT 0x40 -#define I2S_REG_FRAME_MATCH 0x50 -#define I2S_REG_DATAWORD_SIZES 0x60 -#define I2S_REG_PEAKLEVEL_SEL 0x70 -#define I2S_REG_PEAKLEVEL_IN0 0x80 -#define I2S_REG_PEAKLEVEL_IN1 0x90 - -#endif /* _AWACS_DEFS_H_ */ diff --git a/sound/oss/dmasound/dac3550a.c b/sound/oss/dmasound/dac3550a.c deleted file mode 100644 index 0f0d03a55da..00000000000 --- a/sound/oss/dmasound/dac3550a.c +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Driver for the i2c/i2s based DAC3550a sound chip used - * on some Apple iBooks. Also known as "DACA". - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive - * for more details. - */ - -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/delay.h> -#include <linux/proc_fs.h> -#include <linux/ioport.h> -#include <linux/sysctl.h> -#include <linux/types.h> -#include <linux/i2c.h> -#include <linux/init.h> -#include <asm/uaccess.h> -#include <asm/errno.h> -#include <asm/io.h> - -#include "dmasound.h" - -/* FYI: This code was derived from the tas3001c.c Texas/Tumbler mixer - * control code, as well as info derived from the AppleDACAAudio driver - * from Darwin CVS (main thing I derived being register numbers and - * values, as well as when to make the calls). */ - -#define I2C_DRIVERID_DACA (0xFDCB) - -#define DACA_VERSION "0.1" -#define DACA_DATE "20010930" - -static int cur_left_vol; -static int cur_right_vol; -static struct i2c_client *daca_client; - -static int daca_attach_adapter(struct i2c_adapter *adapter); -static int daca_detect_client(struct i2c_adapter *adapter, int address); -static int daca_detach_client(struct i2c_client *client); - -struct i2c_driver daca_driver = { - .driver = { - .name = "DAC3550A driver V " DACA_VERSION, - }, - .id = I2C_DRIVERID_DACA, - .attach_adapter = daca_attach_adapter, - .detach_client = daca_detach_client, -}; - -#define VOL_MAX ((1<<20) - 1) - -void daca_get_volume(uint * left_vol, uint *right_vol) -{ - *left_vol = cur_left_vol >> 5; - *right_vol = cur_right_vol >> 5; -} - -int daca_set_volume(uint left_vol, uint right_vol) -{ - unsigned short voldata; - - if (!daca_client) - return -1; - - /* Derived from experience, not from any specific values */ - left_vol <<= 5; - right_vol <<= 5; - - if (left_vol > VOL_MAX) - left_vol = VOL_MAX; - if (right_vol > VOL_MAX) - right_vol = VOL_MAX; - - voldata = ((left_vol >> 14) & 0x3f) << 8; - voldata |= (right_vol >> 14) & 0x3f; - - if (i2c_smbus_write_word_data(daca_client, 2, voldata) < 0) { - printk("daca: failed to set volume \n"); - return -1; - } - - cur_left_vol = left_vol; - cur_right_vol = right_vol; - - return 0; -} - -int daca_leave_sleep(void) -{ - if (!daca_client) - return -1; - - /* Do a short sleep, just to make sure I2C bus is awake and paying - * attention to us - */ - msleep(20); - /* Write the sample rate reg the value it needs */ - i2c_smbus_write_byte_data(daca_client, 1, 8); - daca_set_volume(cur_left_vol >> 5, cur_right_vol >> 5); - /* Another short delay, just to make sure the other I2C bus writes - * have taken... - */ - msleep(20); - /* Write the global config reg - invert right power amp, - * DAC on, use 5-volt mode */ - i2c_smbus_write_byte_data(daca_client, 3, 0x45); - - return 0; -} - -int daca_enter_sleep(void) -{ - if (!daca_client) - return -1; - - i2c_smbus_write_byte_data(daca_client, 1, 8); - daca_set_volume(cur_left_vol >> 5, cur_right_vol >> 5); - - /* Write the global config reg - invert right power amp, - * DAC on, enter low-power mode, use 5-volt mode - */ - i2c_smbus_write_byte_data(daca_client, 3, 0x65); - - return 0; -} - -static int daca_attach_adapter(struct i2c_adapter *adapter) -{ - if (!strncmp(adapter->name, "mac-io", 6)) - daca_detect_client(adapter, 0x4d); - return 0; -} - -static int daca_init_client(struct i2c_client * new_client) -{ - /* - * Probe is not working with the current i2c-keywest - * driver. We try to use addr 0x4d on each adapters - * instead, by setting the format register. - * - * FIXME: I'm sure that can be obtained from the - * device-tree. --BenH. - */ - - /* Write the global config reg - invert right power amp, - * DAC on, use 5-volt mode - */ - if (i2c_smbus_write_byte_data(new_client, 3, 0x45)) - return -1; - - i2c_smbus_write_byte_data(new_client, 1, 8); - daca_client = new_client; - daca_set_volume(15000, 15000); - - return 0; -} - -static int daca_detect_client(struct i2c_adapter *adapter, int address) -{ - const char *client_name = "DAC 3550A Digital Equalizer"; - struct i2c_client *new_client; - int rc = -ENODEV; - - new_client = kzalloc(sizeof(*new_client), GFP_KERNEL); - if (!new_client) - return -ENOMEM; - - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &daca_driver; - new_client->flags = 0; - strcpy(new_client->name, client_name); - - if (daca_init_client(new_client)) - goto bail; - - /* Tell the i2c layer a new client has arrived */ - if (i2c_attach_client(new_client)) - goto bail; - - return 0; - bail: - kfree(new_client); - return rc; -} - - -static int daca_detach_client(struct i2c_client *client) -{ - if (client == daca_client) - daca_client = NULL; - - i2c_detach_client(client); - kfree(client); - return 0; -} - -void daca_cleanup(void) -{ - i2c_del_driver(&daca_driver); -} - -int daca_init(void) -{ - printk("dac3550a driver version %s (%s)\n",DACA_VERSION,DACA_DATE); - return i2c_add_driver(&daca_driver); -} diff --git a/sound/oss/dmasound/dmasound.h b/sound/oss/dmasound/dmasound.h index 25dd5a318eb..d978b009656 100644 --- a/sound/oss/dmasound/dmasound.h +++ b/sound/oss/dmasound/dmasound.h @@ -59,7 +59,6 @@ static inline int ioctl_return(int __user *addr, int value) */ #undef HAS_8BIT_TABLES -#undef HAS_RECORD #if defined(CONFIG_DMASOUND_ATARI) || defined(CONFIG_DMASOUND_ATARI_MODULE) ||\ defined(CONFIG_DMASOUND_PAULA) || defined(CONFIG_DMASOUND_PAULA_MODULE) ||\ @@ -83,10 +82,6 @@ static inline int ioctl_return(int __user *addr, int value) #define DEFAULT_N_BUFFERS 4 #define DEFAULT_BUFF_SIZE (1<<15) -#if defined(CONFIG_DMASOUND_PMAC) || defined(CONFIG_DMASOUND_PMAC_MODULE) -#define HAS_RECORD -#endif - /* * Initialization */ @@ -168,9 +163,6 @@ struct sound_settings { SETTINGS soft; /* software settings */ SETTINGS dsp; /* /dev/dsp default settings */ TRANS *trans_write; /* supported translations */ -#ifdef HAS_RECORD - TRANS *trans_read; /* supported translations */ -#endif int volume_left; /* volume (range is machine dependent) */ int volume_right; int bass; /* tone (range is machine dependent) */ @@ -253,11 +245,6 @@ struct sound_queue { extern struct sound_queue dmasound_write_sq; #define write_sq dmasound_write_sq -#ifdef HAS_RECORD -extern struct sound_queue dmasound_read_sq; -#define read_sq dmasound_read_sq -#endif - extern int dmasound_catchRadius; #define catchRadius dmasound_catchRadius diff --git a/sound/oss/dmasound/dmasound_awacs.c b/sound/oss/dmasound/dmasound_awacs.c deleted file mode 100644 index 8f6388004f4..00000000000 --- a/sound/oss/dmasound/dmasound_awacs.c +++ /dev/null @@ -1,3215 +0,0 @@ -/* - * linux/sound/oss/dmasound/dmasound_awacs.c - * - * PowerMac `AWACS' and `Burgundy' DMA Sound Driver - * with some limited support for DACA & Tumbler - * - * See linux/sound/oss/dmasound/dmasound_core.c for copyright and - * history prior to 2001/01/26. - * - * 26/01/2001 ed 0.1 Iain Sandoe - * - added version info. - * - moved dbdma command buffer allocation to PMacXXXSqSetup() - * - fixed up beep dbdma cmd buffers - * - * 08/02/2001 [0.2] - * - make SNDCTL_DSP_GETFMTS return the correct info for the h/w - * - move soft format translations to a separate file - * - [0.3] make SNDCTL_DSP_GETCAPS return correct info. - * - [0.4] more informative machine name strings. - * - [0.5] - * - record changes. - * - made the default_hard/soft entries. - * 04/04/2001 [0.6] - * - minor correction to bit assignments in awacs_defs.h - * - incorporate mixer changes from 2.2.x back-port. - * - take out passthru as a rec input (it isn't). - * - make Input Gain slider work the 'right way up'. - * - try to make the mixer sliders more logical - so now the - * input selectors are just two-state (>50% == ON) and the - * Input Gain slider handles the rest of the gain issues. - * - try to pick slider representations that most closely match - * the actual use - e.g. IGain for input gain... - * - first stab at over/under-run detection. - * - minor cosmetic changes to IRQ identification. - * - fix bug where rates > max would be reported as supported. - * - first stab at over/under-run detection. - * - make use of i2c for mixer settings conditional on perch - * rather than cuda (some machines without perch have cuda). - * - fix bug where TX stops when dbdma status comes up "DEAD" - * so far only reported on PowerComputing clones ... but. - * - put in AWACS/Screamer register write timeouts. - * - part way to partitioning the init() stuff - * - first pass at 'tumbler' stuff (not support - just an attempt - * to allow the driver to load on new G4s). - * 01/02/2002 [0.7] - BenH - * - all sort of minor bits went in since the latest update, I - * bumped the version number for that reason - * - * 07/26/2002 [0.8] - BenH - * - More minor bits since last changelog (I should be more careful - * with those) - * - Support for snapper & better tumbler integration by Toby Sargeant - * - Headphone detect for scremer by Julien Blache - * - More tumbler fixed by Andreas Schwab - * 11/29/2003 [0.8.1] - Renzo Davoli (King Enzo) - * - Support for Snapper line in - * - snapper input resampling (for rates < 44100) - * - software line gain control - */ - -/* GENERAL FIXME/TODO: check that the assumptions about what is written to - mac-io is valid for DACA & Tumbler. - - This driver is in bad need of a rewrite. The dbdma code has to be split, - some proper device-tree parsing code has to be written, etc... -*/ - -#include <linux/types.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/soundcard.h> -#include <linux/adb.h> -#include <linux/nvram.h> -#include <linux/tty.h> -#include <linux/vt_kern.h> -#include <linux/spinlock.h> -#include <linux/kmod.h> -#include <linux/interrupt.h> -#include <linux/input.h> -#include <linux/mutex.h> -#ifdef CONFIG_ADB_CUDA -#include <linux/cuda.h> -#endif -#ifdef CONFIG_ADB_PMU -#include <linux/pmu.h> -#endif - -#include <asm/uaccess.h> -#include <asm/prom.h> -#include <asm/machdep.h> -#include <asm/io.h> -#include <asm/dbdma.h> -#include <asm/pmac_feature.h> -#include <asm/irq.h> -#include <asm/nvram.h> - -#include "awacs_defs.h" -#include "dmasound.h" -#include "tas3001c.h" -#include "tas3004.h" -#include "tas_common.h" - -#define DMASOUND_AWACS_REVISION 0 -#define DMASOUND_AWACS_EDITION 7 - -#define AWACS_SNAPPER 110 /* fake revision # for snapper */ -#define AWACS_BURGUNDY 100 /* fake revision # for burgundy */ -#define AWACS_TUMBLER 90 /* fake revision # for tumbler */ -#define AWACS_DACA 80 /* fake revision # for daca (ibook) */ -#define AWACS_AWACS 2 /* holding revision for AWACS */ -#define AWACS_SCREAMER 3 /* holding revision for Screamer */ -/* - * Interrupt numbers and addresses, & info obtained from the device tree. - */ -static int awacs_irq, awacs_tx_irq, awacs_rx_irq; -static volatile struct awacs_regs __iomem *awacs; -static volatile u32 __iomem *i2s; -static volatile struct dbdma_regs __iomem *awacs_txdma, *awacs_rxdma; -static int awacs_rate_index; -static int awacs_subframe; -static struct device_node* awacs_node; -static struct device_node* i2s_node; -static struct resource awacs_rsrc[3]; - -static char awacs_name[64]; -static int awacs_revision; -static int awacs_sleeping; -static DEFINE_MUTEX(dmasound_mutex); - -static int sound_device_id; /* exists after iMac revA */ -static int hw_can_byteswap = 1 ; /* most pmac sound h/w can */ - -/* model info */ -/* To be replaced with better interaction with pmac_feature.c */ -static int is_pbook_3X00; -static int is_pbook_g3; - -/* expansion info */ -static int has_perch; -static int has_ziva; - -/* for earlier powerbooks which need fiddling with mac-io to enable - * cd etc. -*/ -static unsigned char __iomem *latch_base; -static unsigned char __iomem *macio_base; - -/* - * Space for the DBDMA command blocks. - */ -static void *awacs_tx_cmd_space; -static volatile struct dbdma_cmd *awacs_tx_cmds; -static int number_of_tx_cmd_buffers; - -static void *awacs_rx_cmd_space; -static volatile struct dbdma_cmd *awacs_rx_cmds; -static int number_of_rx_cmd_buffers; - -/* - * Cached values of AWACS registers (we can't read them). - * Except on the burgundy (and screamer). XXX - */ - -int awacs_reg[8]; -int awacs_reg1_save; - -/* tracking values for the mixer contents -*/ - -static int spk_vol; -static int line_vol; -static int passthru_vol; - -static int ip_gain; /* mic preamp settings */ -static int rec_lev = 0x4545 ; /* default CD gain 69 % */ -static int mic_lev; -static int cd_lev = 0x6363 ; /* 99 % */ -static int line_lev; - -static int hdp_connected; - -/* - * Stuff for outputting a beep. The values range from -327 to +327 - * so we can multiply by an amplitude in the range 0..100 to get a - * signed short value to put in the output buffer. - */ -static short beep_wform[256] = { - 0, 40, 79, 117, 153, 187, 218, 245, - 269, 288, 304, 316, 323, 327, 327, 324, - 318, 310, 299, 288, 275, 262, 249, 236, - 224, 213, 204, 196, 190, 186, 183, 182, - 182, 183, 186, 189, 192, 196, 200, 203, - 206, 208, 209, 209, 209, 207, 204, 201, - 197, 193, 188, 183, 179, 174, 170, 166, - 163, 161, 160, 159, 159, 160, 161, 162, - 164, 166, 168, 169, 171, 171, 171, 170, - 169, 167, 163, 159, 155, 150, 144, 139, - 133, 128, 122, 117, 113, 110, 107, 105, - 103, 103, 103, 103, 104, 104, 105, 105, - 105, 103, 101, 97, 92, 86, 78, 68, - 58, 45, 32, 18, 3, -11, -26, -41, - -55, -68, -79, -88, -95, -100, -102, -102, - -99, -93, -85, -75, -62, -48, -33, -16, - 0, 16, 33, 48, 62, 75, 85, 93, - 99, 102, 102, 100, 95, 88, 79, 68, - 55, 41, 26, 11, -3, -18, -32, -45, - -58, -68, -78, -86, -92, -97, -101, -103, - -105, -105, -105, -104, -104, -103, -103, -103, - -103, -105, -107, -110, -113, -117, -122, -128, - -133, -139, -144, -150, -155, -159, -163, -167, - -169, -170, -171, -171, -171, -169, -168, -166, - -164, -162, -161, -160, -159, -159, -160, -161, - -163, -166, -170, -174, -179, -183, -188, -193, - -197, -201, -204, -207, -209, -209, -209, -208, - -206, -203, -200, -196, -192, -189, -186, -183, - -182, -182, -183, -186, -190, -196, -204, -213, - -224, -236, -249, -262, -275, -288, -299, -310, - -318, -324, -327, -327, -323, -316, -304, -288, - -269, -245, -218, -187, -153, -117, -79, -40, -}; - -/* beep support */ -#define BEEP_SRATE 22050 /* 22050 Hz sample rate */ -#define BEEP_BUFLEN 512 -#define BEEP_VOLUME 15 /* 0 - 100 */ - -static int beep_vol = BEEP_VOLUME; -static int beep_playing; -static int awacs_beep_state; -static short *beep_buf; -static void *beep_dbdma_cmd_space; -static volatile struct dbdma_cmd *beep_dbdma_cmd; - -/* Burgundy functions */ -static void awacs_burgundy_wcw(unsigned addr,unsigned newval); -static unsigned awacs_burgundy_rcw(unsigned addr); -static void awacs_burgundy_write_volume(unsigned address, int volume); -static int awacs_burgundy_read_volume(unsigned address); -static void awacs_burgundy_write_mvolume(unsigned address, int volume); -static int awacs_burgundy_read_mvolume(unsigned address); - -/* we will allocate a single 'emergency' dbdma cmd block to use if the - tx status comes up "DEAD". This happens on some PowerComputing Pmac - clones, either owing to a bug in dbdma or some interaction between - IDE and sound. However, this measure would deal with DEAD status if - if appeared elsewhere. - - for the sake of memory efficiency we'll allocate this cmd as part of - the beep cmd stuff. -*/ - -static volatile struct dbdma_cmd *emergency_dbdma_cmd; - -#ifdef CONFIG_PM -/* - * Stuff for restoring after a sleep. - */ -static void awacs_sleep_notify(struct pmu_sleep_notifier *self, int when); -struct pmu_sleep_notifier awacs_sleep_notifier = { - awacs_sleep_notify, SLEEP_LEVEL_SOUND, -}; -#endif /* CONFIG_PM */ - -/* for (soft) sample rate translations */ -int expand_bal; /* Balance factor for expanding (not volume!) */ -int expand_read_bal; /* Balance factor for expanding reads (not volume!) */ - -/*** Low level stuff *********************************************************/ - -static void *PMacAlloc(unsigned int size, gfp_t flags); -static void PMacFree(void *ptr, unsigned int size); -static int PMacIrqInit(void); -#ifdef MODULE -static void PMacIrqCleanup(void); -#endif -static void PMacSilence(void); -static void PMacInit(void); -static int PMacSetFormat(int format); -static int PMacSetVolume(int volume); -static void PMacPlay(void); -static void PMacRecord(void); -static irqreturn_t pmac_awacs_tx_intr(int irq, void *devid); -static irqreturn_t pmac_awacs_rx_intr(int irq, void *devid); -static irqreturn_t pmac_awacs_intr(int irq, void *devid); -static void awacs_write(int val); -static int awacs_get_volume(int reg, int lshift); -static int awacs_volume_setter(int volume, int n, int mute, int lshift); - - -/*** Mid level stuff **********************************************************/ - -static int PMacMixerIoctl(u_int cmd, u_long arg); -static int PMacWriteSqSetup(void); -static int PMacReadSqSetup(void); -static void PMacAbortRead(void); - -extern TRANS transAwacsNormal ; -extern TRANS transAwacsExpand ; -extern TRANS transAwacsNormalRead ; -extern TRANS transAwacsExpandRead ; - -extern int daca_init(void); -extern void daca_cleanup(void); -extern int daca_set_volume(uint left_vol, uint right_vol); -extern void daca_get_volume(uint * left_vol, uint *right_vol); -extern int daca_enter_sleep(void); -extern int daca_leave_sleep(void); - -#define TRY_LOCK() \ - if ((rc = mutex_lock_interruptible(&dmasound_mutex)) != 0) \ - return rc; -#define LOCK() mutex_lock(&dmasound_mutex); - -#define UNLOCK() mutex_unlock(&dmasound_mutex); - -/* We use different versions that the ones provided in dmasound.h - * - * FIXME: Use different names ;) - */ -#undef IOCTL_IN -#undef IOCTL_OUT - -#define IOCTL_IN(arg, ret) \ - rc = get_user(ret, (int __user *)(arg)); \ - if (rc) break; -#define IOCTL_OUT(arg, ret) \ - ioctl_return2((int __user *)(arg), ret) - -static inline int ioctl_return2(int __user *addr, int value) -{ - return value < 0 ? value : put_user(value, addr); -} - - -/*** AE - TUMBLER / SNAPPER START ************************************************/ - - -int gpio_audio_reset, gpio_audio_reset_pol; -int gpio_amp_mute, gpio_amp_mute_pol; -int gpio_headphone_mute, gpio_headphone_mute_pol; -int gpio_headphone_detect, gpio_headphone_detect_pol; -int gpio_headphone_irq; - -int -setup_audio_gpio(const char *name, const char* compatible, int *gpio_addr, int* gpio_pol) -{ - struct device_node *gpiop; - struct device_node *np; - const u32* pp; - int ret = -ENODEV; - - gpiop = of_find_node_by_name(NULL, "gpio"); - if (!gpiop) - goto done; - - np = of_get_next_child(gpiop, NULL); - while(np != 0) { - if (name) { - const char *property = - of_get_property(np,"audio-gpio",NULL); - if (property != 0 && strcmp(property,name) == 0) - break; - } else if (compatible && of_device_is_compatible(np, compatible)) - break; - np = of_get_next_child(gpiop, np); - } - if (!np) - goto done; - pp = of_get_property(np, "AAPL,address", NULL); - if (!pp) - goto done; - *gpio_addr = (*pp) & 0x0000ffff; - pp = of_get_property(np, "audio-gpio-active-state", NULL); - if (pp) - *gpio_pol = *pp; - else - *gpio_pol = 1; - ret = irq_of_parse_and_map(np, 0); -done: - of_node_put(np); - of_node_put(gpiop); - return ret; -} - -static inline void -write_audio_gpio(int gpio_addr, int data) -{ - if (!gpio_addr) - return; - pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, gpio_addr, data ? 0x05 : 0x04); -} - -static inline int -read_audio_gpio(int gpio_addr) -{ - if (!gpio_addr) - return 0; - return ((pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, gpio_addr, 0) & 0x02) !=0); -} - -/* - * Headphone interrupt via GPIO (Tumbler, Snapper, DACA) - */ -static irqreturn_t -headphone_intr(int irq, void *devid) -{ - unsigned long flags; - - spin_lock_irqsave(&dmasound.lock, flags); - if (read_audio_gpio(gpio_headphone_detect) == gpio_headphone_detect_pol) { - printk(KERN_INFO "Audio jack plugged, muting speakers.\n"); - write_audio_gpio(gpio_headphone_mute, !gpio_headphone_mute_pol); - write_audio_gpio(gpio_amp_mute, gpio_amp_mute_pol); - tas_output_device_change(sound_device_id,TAS_OUTPUT_HEADPHONES,0); - } else { - printk(KERN_INFO "Audio jack unplugged, enabling speakers.\n"); - write_audio_gpio(gpio_amp_mute, !gpio_amp_mute_pol); - write_audio_gpio(gpio_headphone_mute, gpio_headphone_mute_pol); - tas_output_device_change(sound_device_id,TAS_OUTPUT_INTERNAL_SPKR,0); - } - spin_unlock_irqrestore(&dmasound.lock, flags); - return IRQ_HANDLED; -} - - -/* Initialize tumbler */ - -static int -tas_dmasound_init(void) -{ - setup_audio_gpio( - "audio-hw-reset", - NULL, - &gpio_audio_reset, - &gpio_audio_reset_pol); - setup_audio_gpio( - "amp-mute", - NULL, - &gpio_amp_mute, - &gpio_amp_mute_pol); - setup_audio_gpio("headphone-mute", - NULL, - &gpio_headphone_mute, - &gpio_headphone_mute_pol); - gpio_headphone_irq = setup_audio_gpio( - "headphone-detect", - NULL, - &gpio_headphone_detect, - &gpio_headphone_detect_pol); - /* Fix some broken OF entries in desktop machines */ - if (!gpio_headphone_irq) - gpio_headphone_irq = setup_audio_gpio( - NULL, - "keywest-gpio15", - &gpio_headphone_detect, - &gpio_headphone_detect_pol); - - write_audio_gpio(gpio_audio_reset, gpio_audio_reset_pol); - msleep(100); - write_audio_gpio(gpio_audio_reset, !gpio_audio_reset_pol); - msleep(100); - if (gpio_headphone_irq) { - if (request_irq(gpio_headphone_irq,headphone_intr,0,"Headphone detect",NULL) < 0) { - printk(KERN_ERR "tumbler: Can't request headphone interrupt\n"); - gpio_headphone_irq = 0; - } else { - u8 val; - /* Activate headphone status interrupts */ - val = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, gpio_headphone_detect, 0); - pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, gpio_headphone_detect, val | 0x80); - /* Trigger it */ - headphone_intr(0, NULL); - } - } - if (!gpio_headphone_irq) { - /* Some machine enter this case ? */ - printk(KERN_WARNING "tumbler: Headphone detect IRQ not found, enabling all outputs !\n"); - write_audio_gpio(gpio_amp_mute, !gpio_amp_mute_pol); - write_audio_gpio(gpio_headphone_mute, !gpio_headphone_mute_pol); - } - return 0; -} - - -static int -tas_dmasound_cleanup(void) -{ - if (gpio_headphone_irq) - free_irq(gpio_headphone_irq, NULL); - return 0; -} - -/* We don't support 48k yet */ -static int tas_freqs[1] = { 44100 } ; -static int tas_freqs_ok[1] = { 1 } ; - -/* don't know what to do really - just have to leave it where - * OF left things -*/ - -static int -tas_set_frame_rate(void) -{ - if (i2s) { - out_le32(i2s + (I2S_REG_SERIAL_FORMAT >> 2), 0x41190000); - out_le32(i2s + (I2S_REG_DATAWORD_SIZES >> 2), 0x02000200); - } - dmasound.hard.speed = 44100 ; - awacs_rate_index = 0 ; - return 44100 ; -} - -static int -tas_mixer_ioctl(u_int cmd, u_long arg) -{ - int __user *argp = (int __user *)arg; - int data; - int rc; - - rc=tas_device_ioctl(cmd, arg); - if (rc != -EINVAL) { - return rc; - } - - if ((cmd & ~0xff) == MIXER_WRITE(0) && - tas_supported_mixers() & (1<<(cmd & 0xff))) { - rc = get_user(data, argp); - if (rc<0) return rc; - tas_set_mixer_level(cmd & 0xff, data); - tas_get_mixer_level(cmd & 0xff, &data); - return ioctl_return2(argp, data); - } - if ((cmd & ~0xff) == MIXER_READ(0) && - tas_supported_mixers() & (1<<(cmd & 0xff))) { - tas_get_mixer_level(cmd & 0xff, &data); - return ioctl_return2(argp, data); - } - - switch(cmd) { - case SOUND_MIXER_READ_DEVMASK: - data = tas_supported_mixers() | SOUND_MASK_SPEAKER; - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_READ_STEREODEVS: - data = tas_stereo_mixers(); - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_READ_CAPS: - rc = IOCTL_OUT(arg, 0); - break; - case SOUND_MIXER_READ_RECMASK: - // XXX FIXME: find a way to check what is really available */ - data = SOUND_MASK_LINE | SOUND_MASK_MIC; - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_READ_RECSRC: - if (awacs_reg[0] & MASK_MUX_AUDIN) - data |= SOUND_MASK_LINE; - if (awacs_reg[0] & MASK_MUX_MIC) - data |= SOUND_MASK_MIC; - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_WRITE_RECSRC: - IOCTL_IN(arg, data); - data =0; - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_WRITE_SPEAKER: /* really bell volume */ - IOCTL_IN(arg, data); - beep_vol = data & 0xff; - /* fall through */ - case SOUND_MIXER_READ_SPEAKER: - rc = IOCTL_OUT(arg, (beep_vol<<8) | beep_vol); - break; - case SOUND_MIXER_OUTMASK: - case SOUND_MIXER_OUTSRC: - default: - rc = -EINVAL; - } - - return rc; -} - -static void __init -tas_init_frame_rates(const unsigned int *prop, unsigned int l) -{ - int i ; - if (prop) { - for (i=0; i<1; i++) - tas_freqs_ok[i] = 0; - for (l /= sizeof(int); l > 0; --l) { - unsigned int r = *prop++; - /* Apple 'Fixed' format */ - if (r >= 0x10000) - r >>= 16; - for (i = 0; i < 1; ++i) { - if (r == tas_freqs[i]) { - tas_freqs_ok[i] = 1; - break; - } - } - } - } - /* else we assume that all the rates are available */ -} - - -/*** AE - TUMBLER / SNAPPER END ************************************************/ - - - -/*** Low level stuff *********************************************************/ - -/* - * PCI PowerMac, with AWACS, Screamer, Burgundy, DACA or Tumbler and DBDMA. - */ -static void *PMacAlloc(unsigned int size, gfp_t flags) -{ - return kmalloc(size, flags); -} - -static void PMacFree(void *ptr, unsigned int size) -{ - kfree(ptr); -} - -static int __init PMacIrqInit(void) -{ - if (awacs) - if (request_irq(awacs_irq, pmac_awacs_intr, 0, "Built-in Sound misc", NULL)) - return 0; - if (request_irq(awacs_tx_irq, pmac_awacs_tx_intr, 0, "Built-in Sound out", NULL) - || request_irq(awacs_rx_irq, pmac_awacs_rx_intr, 0, "Built-in Sound in", NULL)) - return 0; - return 1; -} - -#ifdef MODULE -static void PMacIrqCleanup(void) -{ - /* turn off input & output dma */ - DBDMA_DO_STOP(awacs_txdma); - DBDMA_DO_STOP(awacs_rxdma); - - if (awacs) - /* disable interrupts from awacs interface */ - out_le32(&awacs->control, in_le32(&awacs->control) & 0xfff); - - /* Switch off the sound clock */ - pmac_call_feature(PMAC_FTR_SOUND_CHIP_ENABLE, awacs_node, 0, 0); - /* Make sure proper bits are set on pismo & tipb */ - if ((machine_is_compatible("PowerBook3,1") || - machine_is_compatible("PowerBook3,2")) && awacs) { - awacs_reg[1] |= MASK_PAROUT0 | MASK_PAROUT1; - awacs_write(MASK_ADDR1 | awacs_reg[1]); - msleep(200); - } - if (awacs) - free_irq(awacs_irq, NULL); - free_irq(awacs_tx_irq, NULL); - free_irq(awacs_rx_irq, NULL); - - if (awacs) - iounmap(awacs); - if (i2s) - iounmap(i2s); - iounmap(awacs_txdma); - iounmap(awacs_rxdma); - - release_mem_region(awacs_rsrc[0].start, - awacs_rsrc[0].end - awacs_rsrc[0].start + 1); - release_mem_region(awacs_rsrc[1].start, - awacs_rsrc[1].end - awacs_rsrc[1].start + 1); - release_mem_region(awacs_rsrc[2].start, - awacs_rsrc[2].end - awacs_rsrc[2].start + 1); - - kfree(awacs_tx_cmd_space); - kfree(awacs_rx_cmd_space); - kfree(beep_dbdma_cmd_space); - kfree(beep_buf); -#ifdef CONFIG_PM - pmu_unregister_sleep_notifier(&awacs_sleep_notifier); -#endif -} -#endif /* MODULE */ - -static void PMacSilence(void) -{ - /* turn off output dma */ - DBDMA_DO_STOP(awacs_txdma); -} - -/* don't know what to do really - just have to leave it where - * OF left things -*/ - -static int daca_set_frame_rate(void) -{ - if (i2s) { - out_le32(i2s + (I2S_REG_SERIAL_FORMAT >> 2), 0x41190000); - out_le32(i2s + (I2S_REG_DATAWORD_SIZES >> 2), 0x02000200); - } - dmasound.hard.speed = 44100 ; - awacs_rate_index = 0 ; - return 44100 ; -} - -static int awacs_freqs[8] = { - 44100, 29400, 22050, 17640, 14700, 11025, 8820, 7350 -}; -static int awacs_freqs_ok[8] = { 1, 1, 1, 1, 1, 1, 1, 1 }; - -static int -awacs_set_frame_rate(int desired, int catch_r) -{ - int tolerance, i = 8 ; - /* - * If we have a sample rate which is within catchRadius percent - * of the requested value, we don't have to expand the samples. - * Otherwise choose the next higher rate. - * N.B.: burgundy awacs only works at 44100 Hz. - */ - do { - tolerance = catch_r * awacs_freqs[--i] / 100; - if (awacs_freqs_ok[i] - && dmasound.soft.speed <= awacs_freqs[i] + tolerance) - break; - } while (i > 0); - dmasound.hard.speed = awacs_freqs[i]; - awacs_rate_index = i; - - out_le32(&awacs->control, MASK_IEPC | (i << 8) | 0x11 ); - awacs_reg[1] = (awacs_reg[1] & ~MASK_SAMPLERATE) | (i << 3); - awacs_write(awacs_reg[1] | MASK_ADDR1); - return dmasound.hard.speed; -} - -static int -burgundy_set_frame_rate(void) -{ - awacs_rate_index = 0 ; - awacs_reg[1] = (awacs_reg[1] & ~MASK_SAMPLERATE) ; - /* XXX disable error interrupt on burgundy for now */ - out_le32(&awacs->control, MASK_IEPC | 0 | 0x11 | MASK_IEE); - return 44100 ; -} - -static int -set_frame_rate(int desired, int catch_r) -{ - switch (awacs_revision) { - case AWACS_BURGUNDY: - dmasound.hard.speed = burgundy_set_frame_rate(); - break ; - case AWACS_TUMBLER: - case AWACS_SNAPPER: - dmasound.hard.speed = tas_set_frame_rate(); - break ; - case AWACS_DACA: - dmasound.hard.speed = - daca_set_frame_rate(); - break ; - default: - dmasound.hard.speed = awacs_set_frame_rate(desired, - catch_r); - break ; - } - return dmasound.hard.speed ; -} - -static void -awacs_recalibrate(void) -{ - /* Sorry for the horrible delays... I hope to get that improved - * by making the whole PM process asynchronous in a future version - */ - msleep(750); - awacs_reg[1] |= MASK_CMUTE | MASK_AMUTE; - awacs_write(awacs_reg[1] | MASK_RECALIBRATE | MASK_ADDR1); - msleep(1000); - awacs_write(awacs_reg[1] | MASK_ADDR1); -} - -static void PMacInit(void) -{ - int tolerance; - - switch (dmasound.soft.format) { - case AFMT_S16_LE: - case AFMT_U16_LE: - if (hw_can_byteswap) - dmasound.hard.format = AFMT_S16_LE; - else - dmasound.hard.format = AFMT_S16_BE; - break; - default: - dmasound.hard.format = AFMT_S16_BE; - break; - } - dmasound.hard.stereo = 1; - dmasound.hard.size = 16; - - /* set dmasound.hard.speed - on the basis of what we want (soft) - * and the tolerance we'll allow. - */ - set_frame_rate(dmasound.soft.speed, catchRadius) ; - - tolerance = (catchRadius * dmasound.hard.speed) / 100; - if (dmasound.soft.speed >= dmasound.hard.speed - tolerance) { - dmasound.trans_write = &transAwacsNormal; - dmasound.trans_read = &transAwacsNormalRead; - } else { - dmasound.trans_write = &transAwacsExpand; - dmasound.trans_read = &transAwacsExpandRead; - } - - if (awacs) { - if (hw_can_byteswap && (dmasound.hard.format == AFMT_S16_LE)) - out_le32(&awacs->byteswap, BS_VAL); - else - out_le32(&awacs->byteswap, 0); - } - - expand_bal = -dmasound.soft.speed; - expand_read_bal = -dmasound.soft.speed; -} - -static int PMacSetFormat(int format) -{ - int size; - int req_format = format; - - switch (format) { - case AFMT_QUERY: - return dmasound.soft.format; - case AFMT_MU_LAW: - case AFMT_A_LAW: - case AFMT_U8: - case AFMT_S8: - size = 8; - break; - case AFMT_S16_LE: - if(!hw_can_byteswap) - format = AFMT_S16_BE; - case AFMT_S16_BE: - size = 16; - break; - case AFMT_U16_LE: - if(!hw_can_byteswap) - format = AFMT_U16_BE; - case AFMT_U16_BE: - size = 16; - break; - default: /* :-) */ - printk(KERN_ERR "dmasound: unknown format 0x%x, using AFMT_U8\n", - format); - size = 8; - format = AFMT_U8; - } - - if (req_format == format) { - dmasound.soft.format = format; - dmasound.soft.size = size; - if (dmasound.minDev == SND_DEV_DSP) { - dmasound.dsp.format = format; - dmasound.dsp.size = size; - } - } - - return format; -} - -#define AWACS_VOLUME_TO_MASK(x) (15 - ((((x) - 1) * 15) / 99)) -#define AWACS_MASK_TO_VOLUME(y) (100 - ((y) * 99 / 15)) - -static int awacs_get_volume(int reg, int lshift) -{ - int volume; - - volume = AWACS_MASK_TO_VOLUME((reg >> lshift) & 0xf); - volume |= AWACS_MASK_TO_VOLUME(reg & 0xf) << 8; - return volume; -} - -static int awacs_volume_setter(int volume, int n, int mute, int lshift) -{ - int r1, rn; - - if (mute && volume == 0) { - r1 = awacs_reg[1] | mute; - } else { - r1 = awacs_reg[1] & ~mute; - rn = awacs_reg[n] & ~(0xf | (0xf << lshift)); - rn |= ((AWACS_VOLUME_TO_MASK(volume & 0xff) & 0xf) << lshift); - rn |= AWACS_VOLUME_TO_MASK((volume >> 8) & 0xff) & 0xf; - awacs_reg[n] = rn; - awacs_write((n << 12) | rn); - volume = awacs_get_volume(rn, lshift); - } - if (r1 != awacs_reg[1]) { - awacs_reg[1] = r1; - awacs_write(r1 | MASK_ADDR1); - } - return volume; -} - -static int PMacSetVolume(int volume) -{ - printk(KERN_WARNING "Bogus call to PMacSetVolume !\n"); - return 0; -} - -static void awacs_setup_for_beep(int speed) -{ - out_le32(&awacs->control, - (in_le32(&awacs->control) & ~0x1f00) - | ((speed > 0 ? speed : awacs_rate_index) << 8)); - - if (hw_can_byteswap && (dmasound.hard.format == AFMT_S16_LE) && speed == -1) - out_le32(&awacs->byteswap, BS_VAL); - else - out_le32(&awacs->byteswap, 0); -} - -/* CHECK: how much of this *really* needs IRQs masked? */ -static void __PMacPlay(void) -{ - volatile struct dbdma_cmd *cp; - int next_frg, count; - - count = 300 ; /* > two cycles at the lowest sample rate */ - - /* what we want to send next */ - next_frg = (write_sq.front + write_sq.active) % write_sq.max_count; - - if (awacs_beep_state) { - /* sound takes precedence over beeps */ - /* stop the dma channel */ - out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16); - while ( (in_le32(&awacs_txdma->status) & RUN) && count--) - udelay(1); - if (awacs) - awacs_setup_for_beep(-1); - out_le32(&awacs_txdma->cmdptr, - virt_to_bus(&(awacs_tx_cmds[next_frg]))); - - beep_playing = 0; - awacs_beep_state = 0; - } - /* this won't allow more than two frags to be in the output queue at - once. (or one, if the max frags is 2 - because count can't exceed - 2 in that case) - */ - while (write_sq.active < 2 && write_sq.active < write_sq.count) { - count = (write_sq.count == write_sq.active + 1) ? - write_sq.rear_size:write_sq.block_size ; - if (count < write_sq.block_size) { - if (!write_sq.syncing) /* last block not yet filled,*/ - break; /* and we're not syncing or POST-ed */ - else { - /* pretend the block is full to force a new - block to be started on the next write */ - write_sq.rear_size = write_sq.block_size ; - write_sq.syncing &= ~2 ; /* clear POST */ - } - } - cp = &awacs_tx_cmds[next_frg]; - st_le16(&cp->req_count, count); - st_le16(&cp->xfer_status, 0); - st_le16(&cp->command, OUTPUT_MORE + INTR_ALWAYS); - /* put a STOP at the end of the queue - but only if we have - space for it. This means that, if we under-run and we only - have two fragments, we might re-play sound from an existing - queued frag. I guess the solution to that is not to set two - frags if you are likely to under-run... - */ - if (write_sq.count < write_sq.max_count) { - if (++next_frg >= write_sq.max_count) - next_frg = 0 ; /* wrap */ - /* if we get here then we've underrun so we will stop*/ - st_le16(&awacs_tx_cmds[next_frg].command, DBDMA_STOP); - } - /* set the dbdma controller going, if it is not already */ - if (write_sq.active == 0) - out_le32(&awacs_txdma->cmdptr, virt_to_bus(cp)); - (void)in_le32(&awacs_txdma->status); - out_le32(&awacs_txdma->control, ((RUN|WAKE) << 16) + (RUN|WAKE)); - ++write_sq.active; - } -} - -static void PMacPlay(void) -{ - LOCK(); - if (!awacs_sleeping) { - unsigned long flags; - - spin_lock_irqsave(&dmasound.lock, flags); - __PMacPlay(); - spin_unlock_irqrestore(&dmasound.lock, flags); - } - UNLOCK(); -} - -static void PMacRecord(void) -{ - unsigned long flags; - - if (read_sq.active) - return; - - spin_lock_irqsave(&dmasound.lock, flags); - - /* This is all we have to do......Just start it up. - */ - out_le32(&awacs_rxdma->control, ((RUN|WAKE) << 16) + (RUN|WAKE)); - read_sq.active = 1; - - spin_unlock_irqrestore(&dmasound.lock, flags); -} - -/* if the TX status comes up "DEAD" - reported on some Power Computing machines - we need to re-start the dbdma - but from a different physical start address - and with a different transfer length. It would get very messy to do this - with the normal dbdma_cmd blocks - we would have to re-write the buffer start - addresses each time. So, we will keep a single dbdma_cmd block which can be - fiddled with. - When DEAD status is first reported the content of the faulted dbdma block is - copied into the emergency buffer and we note that the buffer is in use. - we then bump the start physical address by the amount that was successfully - output before it died. - On any subsequent DEAD result we just do the bump-ups (we know that we are - already using the emergency dbdma_cmd). - CHECK: this just tries to "do it". It is possible that we should abandon - xfers when the number of residual bytes gets below a certain value - I can - see that this might cause a loop-forever if too small a transfer causes - DEAD status. However this is a TODO for now - we'll see what gets reported. - When we get a successful transfer result with the emergency buffer we just - pretend that it completed using the original dmdma_cmd and carry on. The - 'next_cmd' field will already point back to the original loop of blocks. -*/ - -static irqreturn_t -pmac_awacs_tx_intr(int irq, void *devid) -{ - int i = write_sq.front; - int stat; - int i_nowrap = write_sq.front; - volatile struct dbdma_cmd *cp; - /* != 0 when we are dealing with a DEAD xfer */ - static int emergency_in_use; - - spin_lock(&dmasound.lock); - while (write_sq.active > 0) { /* we expect to have done something*/ - if (emergency_in_use) /* we are dealing with DEAD xfer */ - cp = emergency_dbdma_cmd ; - else - cp = &awacs_tx_cmds[i]; - stat = ld_le16(&cp->xfer_status); - if (stat & DEAD) { - unsigned short req, res ; - unsigned int phy ; -#ifdef DEBUG_DMASOUND -printk("dmasound_pmac: tx-irq: xfer died - patching it up...\n") ; -#endif - /* to clear DEAD status we must first clear RUN - set it to quiescent to be on the safe side */ - (void)in_le32(&awacs_txdma->status); - out_le32(&awacs_txdma->control, - (RUN|PAUSE|FLUSH|WAKE) << 16); - write_sq.died++ ; - if (!emergency_in_use) { /* new problem */ - memcpy((void *)emergency_dbdma_cmd, (void *)cp, - sizeof(struct dbdma_cmd)); - emergency_in_use = 1; - cp = emergency_dbdma_cmd; - } - /* now bump the values to reflect the amount - we haven't yet shifted */ - req = ld_le16(&cp->req_count); - res = ld_le16(&cp->res_count); - phy = ld_le32(&cp->phy_addr); - phy += (req - res); - st_le16(&cp->req_count, res); - st_le16(&cp->res_count, 0); - st_le16(&cp->xfer_status, 0); - st_le32(&cp->phy_addr, phy); - st_le32(&cp->cmd_dep, virt_to_bus(&awacs_tx_cmds[(i+1)%write_sq.max_count])); - st_le16(&cp->command, OUTPUT_MORE | BR_ALWAYS | INTR_ALWAYS); - - /* point at our patched up command block */ - out_le32(&awacs_txdma->cmdptr, virt_to_bus(cp)); - /* we must re-start the controller */ - (void)in_le32(&awacs_txdma->status); - /* should complete clearing the DEAD status */ - out_le32(&awacs_txdma->control, - ((RUN|WAKE) << 16) + (RUN|WAKE)); - break; /* this block is still going */ - } - if ((stat & ACTIVE) == 0) - break; /* this frame is still going */ - if (emergency_in_use) - emergency_in_use = 0 ; /* done that */ - --write_sq.count; - --write_sq.active; - i_nowrap++; - if (++i >= write_sq.max_count) - i = 0; - } - - /* if we stopped and we were not sync-ing - then we under-ran */ - if( write_sq.syncing == 0 ){ - stat = in_le32(&awacs_txdma->status) ; - /* we hit the dbdma_stop */ - if( (stat & ACTIVE) == 0 ) write_sq.xruns++ ; - } - - /* if we used some data up then wake the writer to supply some more*/ - if (i_nowrap != write_sq.front) - WAKE_UP(write_sq.action_queue); - write_sq.front = i; - - /* but make sure we funnel what we've already got */\ - if (!awacs_sleeping) - __PMacPlay(); - - /* make the wake-on-empty conditional on syncing */ - if (!write_sq.active && (write_sq.syncing & 1)) - WAKE_UP(write_sq.sync_queue); /* any time we're empty */ - spin_unlock(&dmasound.lock); - return IRQ_HANDLED; -} - - -static irqreturn_t -pmac_awacs_rx_intr(int irq, void *devid) -{ - int stat ; - /* For some reason on my PowerBook G3, I get one interrupt - * when the interrupt vector is installed (like something is - * pending). This happens before the dbdma is initialized by - * us, so I just check the command pointer and if it is zero, - * just blow it off. - */ - if (in_le32(&awacs_rxdma->cmdptr) == 0) - return IRQ_HANDLED; - - /* We also want to blow 'em off when shutting down. - */ - if (read_sq.active == 0) - return IRQ_HANDLED; - - spin_lock(&dmasound.lock); - /* Check multiple buffers in case we were held off from - * interrupt processing for a long time. Geeze, I really hope - * this doesn't happen. - */ - while ((stat=awacs_rx_cmds[read_sq.rear].xfer_status)) { - - /* if we got a "DEAD" status then just log it for now. - and try to restart dma. - TODO: figure out how best to fix it up - */ - if (stat & DEAD){ -#ifdef DEBUG_DMASOUND -printk("dmasound_pmac: rx-irq: DIED - attempting resurection\n"); -#endif - /* to clear DEAD status we must first clear RUN - set it to quiescent to be on the safe side */ - (void)in_le32(&awacs_txdma->status); - out_le32(&awacs_txdma->control, - (RUN|PAUSE|FLUSH|WAKE) << 16); - awacs_rx_cmds[read_sq.rear].xfer_status = 0; - awacs_rx_cmds[read_sq.rear].res_count = 0; - read_sq.died++ ; - (void)in_le32(&awacs_txdma->status); - /* re-start the same block */ - out_le32(&awacs_rxdma->cmdptr, - virt_to_bus(&awacs_rx_cmds[read_sq.rear])); - /* we must re-start the controller */ - (void)in_le32(&awacs_rxdma->status); - /* should complete clearing the DEAD status */ - out_le32(&awacs_rxdma->control, - ((RUN|WAKE) << 16) + (RUN|WAKE)); - spin_unlock(&dmasound.lock); - return IRQ_HANDLED; /* try this block again */ - } - /* Clear status and move on to next buffer. - */ - awacs_rx_cmds[read_sq.rear].xfer_status = 0; - read_sq.rear++; - - /* Wrap the buffer ring. - */ - if (read_sq.rear >= read_sq.max_active) - read_sq.rear = 0; - - /* If we have caught up to the front buffer, bump it. - * This will cause weird (but not fatal) results if the - * read loop is currently using this buffer. The user is - * behind in this case anyway, so weird things are going - * to happen. - */ - if (read_sq.rear == read_sq.front) { - read_sq.front++; - read_sq.xruns++ ; /* we overan */ - if (read_sq.front >= read_sq.max_active) - read_sq.front = 0; - } - } - - WAKE_UP(read_sq.action_queue); - spin_unlock(&dmasound.lock); - return IRQ_HANDLED; -} - - -static irqreturn_t -pmac_awacs_intr(int irq, void *devid) -{ - int ctrl; - int status; - int r1; - - spin_lock(&dmasound.lock); - ctrl = in_le32(&awacs->control); - status = in_le32(&awacs->codec_stat); - - if (ctrl & MASK_PORTCHG) { - /* tested on Screamer, should work on others too */ - if (awacs_revision == AWACS_SCREAMER) { - if (((status & MASK_HDPCONN) >> 3) && (hdp_connected == 0)) { - hdp_connected = 1; - - r1 = awacs_reg[1] | MASK_SPKMUTE; - awacs_reg[1] = r1; - awacs_write(r1 | MASK_ADDR_MUTE); - } else if (((status & MASK_HDPCONN) >> 3 == 0) && (hdp_connected == 1)) { - hdp_connected = 0; - - r1 = awacs_reg[1] & ~MASK_SPKMUTE; - awacs_reg[1] = r1; - awacs_write(r1 | MASK_ADDR_MUTE); - } - } - } - if (ctrl & MASK_CNTLERR) { - int err = (in_le32(&awacs->codec_stat) & MASK_ERRCODE) >> 16; - /* CHECK: we just swallow burgundy errors at the moment..*/ - if (err != 0 && awacs_revision != AWACS_BURGUNDY) - printk(KERN_ERR "dmasound_pmac: error %x\n", err); - } - /* Writing 1s to the CNTLERR and PORTCHG bits clears them... */ - out_le32(&awacs->control, ctrl); - spin_unlock(&dmasound.lock); - return IRQ_HANDLED; -} - -static void -awacs_write(int val) -{ - int count = 300 ; - if (awacs_revision >= AWACS_DACA || !awacs) - return ; - - while ((in_le32(&awacs->codec_ctrl) & MASK_NEWECMD) && count--) - udelay(1) ; /* timeout is > 2 samples at lowest rate */ - out_le32(&awacs->codec_ctrl, val | (awacs_subframe << 22)); - (void)in_le32(&awacs->byteswap); -} - -/* this is called when the beep timer expires... it will be called even - if the beep has been overidden by other sound output. -*/ -static void awacs_nosound(unsigned long xx) -{ - unsigned long flags; - int count = 600 ; /* > four samples at lowest rate */ - - spin_lock_irqsave(&dmasound.lock, flags); - if (beep_playing) { - st_le16(&beep_dbdma_cmd->command, DBDMA_STOP); - out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16); - while ((in_le32(&awacs_txdma->status) & RUN) && count--) - udelay(1); - if (awacs) - awacs_setup_for_beep(-1); - beep_playing = 0; - } - spin_unlock_irqrestore(&dmasound.lock, flags); -} - -/* - * We generate the beep with a single dbdma command that loops a buffer - * forever - without generating interrupts. - * - * So, to stop it you have to stop dma output as per awacs_nosound. - */ -static int awacs_beep_event(struct input_dev *dev, unsigned int type, - unsigned int code, int hz) -{ - unsigned long flags; - int beep_speed = 0; - int srate; - int period, ncycles, nsamples; - int i, j, f; - short *p; - static int beep_hz_cache; - static int beep_nsamples_cache; - static int beep_volume_cache; - - if (type != EV_SND) - return -1; - switch (code) { - case SND_BELL: - if (hz) - hz = 1000; - break; - case SND_TONE: - break; - default: - return -1; - } - - if (beep_buf == NULL) - return -1; - - /* quick-hack fix for DACA, Burgundy & Tumbler */ - - if (awacs_revision >= AWACS_DACA){ - srate = 44100 ; - } else { - for (i = 0; i < 8 && awacs_freqs[i] >= BEEP_SRATE; ++i) - if (awacs_freqs_ok[i]) - beep_speed = i; - srate = awacs_freqs[beep_speed]; - } - - if (hz <= srate / BEEP_BUFLEN || hz > srate / 2) { - /* cancel beep currently playing */ - awacs_nosound(0); - return 0; - } - - spin_lock_irqsave(&dmasound.lock, flags); - if (beep_playing || write_sq.active || beep_buf == NULL) { - spin_unlock_irqrestore(&dmasound.lock, flags); - return -1; /* too hard, sorry :-( */ - } - beep_playing = 1; - st_le16(&beep_dbdma_cmd->command, OUTPUT_MORE + BR_ALWAYS); - spin_unlock_irqrestore(&dmasound.lock, flags); - - if (hz == beep_hz_cache && beep_vol == beep_volume_cache) { - nsamples = beep_nsamples_cache; - } else { - period = srate * 256 / hz; /* fixed point */ - ncycles = BEEP_BUFLEN * 256 / period; - nsamples = (period * ncycles) >> 8; - f = ncycles * 65536 / nsamples; - j = 0; - p = beep_buf; - for (i = 0; i < nsamples; ++i, p += 2) { - p[0] = p[1] = beep_wform[j >> 8] * beep_vol; - j = (j + f) & 0xffff; - } - beep_hz_cache = hz; - beep_volume_cache = beep_vol; - beep_nsamples_cache = nsamples; - } - - st_le16(&beep_dbdma_cmd->req_count, nsamples*4); - st_le16(&beep_dbdma_cmd->xfer_status, 0); - st_le32(&beep_dbdma_cmd->cmd_dep, virt_to_bus(beep_dbdma_cmd)); - st_le32(&beep_dbdma_cmd->phy_addr, virt_to_bus(beep_buf)); - awacs_beep_state = 1; - - spin_lock_irqsave(&dmasound.lock, flags); - if (beep_playing) { /* i.e. haven't been terminated already */ - int count = 300 ; - out_le32(&awacs_txdma->control, (RUN|WAKE|FLUSH|PAUSE) << 16); - while ((in_le32(&awacs_txdma->status) & RUN) && count--) - udelay(1); /* timeout > 2 samples at lowest rate*/ - if (awacs) - awacs_setup_for_beep(beep_speed); - out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd)); - (void)in_le32(&awacs_txdma->status); - out_le32(&awacs_txdma->control, RUN | (RUN << 16)); - } - spin_unlock_irqrestore(&dmasound.lock, flags); - - return 0; -} - -/* used in init and for wake-up */ - -static void -load_awacs(void) -{ - awacs_write(awacs_reg[0] + MASK_ADDR0); - awacs_write(awacs_reg[1] + MASK_ADDR1); - awacs_write(awacs_reg[2] + MASK_ADDR2); - awacs_write(awacs_reg[4] + MASK_ADDR4); - - if (awacs_revision == AWACS_SCREAMER) { - awacs_write(awacs_reg[5] + MASK_ADDR5); - msleep(100); - awacs_write(awacs_reg[6] + MASK_ADDR6); - msleep(2); - awacs_write(awacs_reg[1] + MASK_ADDR1); - awacs_write(awacs_reg[7] + MASK_ADDR7); - } - if (awacs) { - if (hw_can_byteswap && (dmasound.hard.format == AFMT_S16_LE)) - out_le32(&awacs->byteswap, BS_VAL); - else - out_le32(&awacs->byteswap, 0); - } -} - -#ifdef CONFIG_PM -/* - * Save state when going to sleep, restore it afterwards. - */ -/* FIXME: sort out disabling/re-enabling of read stuff as well */ -static void awacs_sleep_notify(struct pmu_sleep_notifier *self, int when) -{ - unsigned long flags; - - switch (when) { - case PBOOK_SLEEP_NOW: - LOCK(); - awacs_sleeping = 1; - /* Tell the rest of the driver we are now going to sleep */ - mb(); - if (awacs_revision == AWACS_SCREAMER || - awacs_revision == AWACS_AWACS) { - awacs_reg1_save = awacs_reg[1]; - awacs_reg[1] |= MASK_AMUTE | MASK_CMUTE; - awacs_write(MASK_ADDR1 | awacs_reg[1]); - } - - PMacSilence(); - /* stop rx - if going - a bit of a daft user... but */ - out_le32(&awacs_rxdma->control, (RUN|WAKE|FLUSH << 16)); - /* deny interrupts */ - if (awacs) - disable_irq(awacs_irq); - disable_irq(awacs_tx_irq); - disable_irq(awacs_rx_irq); - /* Chip specific sleep code */ - switch (awacs_revision) { - case AWACS_TUMBLER: - case AWACS_SNAPPER: - write_audio_gpio(gpio_headphone_mute, gpio_headphone_mute_pol); - write_audio_gpio(gpio_amp_mute, gpio_amp_mute_pol); - tas_enter_sleep(); - write_audio_gpio(gpio_audio_reset, gpio_audio_reset_pol); - break ; - case AWACS_DACA: - daca_enter_sleep(); - break ; - case AWACS_BURGUNDY: - break ; - case AWACS_SCREAMER: - case AWACS_AWACS: - default: - out_le32(&awacs->control, 0x11) ; - break ; - } - /* Disable sound clock */ - pmac_call_feature(PMAC_FTR_SOUND_CHIP_ENABLE, awacs_node, 0, 0); - /* According to Darwin, we do that after turning off the sound - * chip clock. All this will have to be cleaned up once we properly - * parse the OF sound-objects - */ - if ((machine_is_compatible("PowerBook3,1") || - machine_is_compatible("PowerBook3,2")) && awacs) { - awacs_reg[1] |= MASK_PAROUT0 | MASK_PAROUT1; - awacs_write(MASK_ADDR1 | awacs_reg[1]); - msleep(200); - } - break; - case PBOOK_WAKE: - /* Enable sound clock */ - pmac_call_feature(PMAC_FTR_SOUND_CHIP_ENABLE, awacs_node, 0, 1); - if ((machine_is_compatible("PowerBook3,1") || - machine_is_compatible("PowerBook3,2")) && awacs) { - msleep(100); - awacs_reg[1] &= ~(MASK_PAROUT0 | MASK_PAROUT1); - awacs_write(MASK_ADDR1 | awacs_reg[1]); - msleep(300); - } else - msleep(1000); - /* restore settings */ - switch (awacs_revision) { - case AWACS_TUMBLER: - case AWACS_SNAPPER: - write_audio_gpio(gpio_headphone_mute, gpio_headphone_mute_pol); - write_audio_gpio(gpio_amp_mute, gpio_amp_mute_pol); - write_audio_gpio(gpio_audio_reset, gpio_audio_reset_pol); - msleep(100); - write_audio_gpio(gpio_audio_reset, !gpio_audio_reset_pol); - msleep(150); - tas_leave_sleep(); /* Stub for now */ - headphone_intr(0, NULL); - break; - case AWACS_DACA: - msleep(10); /* Check this !!! */ - daca_leave_sleep(); - break ; /* dont know how yet */ - case AWACS_BURGUNDY: - break ; - case AWACS_SCREAMER: - case AWACS_AWACS: - default: - load_awacs() ; - break ; - } - /* Recalibrate chip */ - if (awacs_revision == AWACS_SCREAMER && awacs) - awacs_recalibrate(); - /* Make sure dma is stopped */ - PMacSilence(); - if (awacs) - enable_irq(awacs_irq); - enable_irq(awacs_tx_irq); - enable_irq(awacs_rx_irq); - if (awacs) { - /* OK, allow ints back again */ - out_le32(&awacs->control, MASK_IEPC - | (awacs_rate_index << 8) | 0x11 - | (awacs_revision < AWACS_DACA ? MASK_IEE: 0)); - } - if (macio_base && is_pbook_g3) { - /* FIXME: should restore the setup we had...*/ - out_8(macio_base + 0x37, 3); - } else if (is_pbook_3X00) { - in_8(latch_base + 0x190); - } - /* Remove mute */ - if (awacs_revision == AWACS_SCREAMER || - awacs_revision == AWACS_AWACS) { - awacs_reg[1] = awacs_reg1_save; - awacs_write(MASK_ADDR1 | awacs_reg[1]); - } - awacs_sleeping = 0; - /* Resume pending sounds. */ - /* we don't try to restart input... */ - spin_lock_irqsave(&dmasound.lock, flags); - __PMacPlay(); - spin_unlock_irqrestore(&dmasound.lock, flags); - UNLOCK(); - } -} -#endif /* CONFIG_PM */ - - -/* All the burgundy functions: */ - -/* Waits for busy flag to clear */ -static inline void -awacs_burgundy_busy_wait(void) -{ - int count = 50; /* > 2 samples at 44k1 */ - while ((in_le32(&awacs->codec_ctrl) & MASK_NEWECMD) && count--) - udelay(1) ; -} - -static inline void -awacs_burgundy_extend_wait(void) -{ - int count = 50 ; /* > 2 samples at 44k1 */ - while ((!(in_le32(&awacs->codec_stat) & MASK_EXTEND)) && count--) - udelay(1) ; - count = 50; - while ((in_le32(&awacs->codec_stat) & MASK_EXTEND) && count--) - udelay(1); -} - -static void -awacs_burgundy_wcw(unsigned addr, unsigned val) -{ - out_le32(&awacs->codec_ctrl, addr + 0x200c00 + (val & 0xff)); - awacs_burgundy_busy_wait(); - out_le32(&awacs->codec_ctrl, addr + 0x200d00 +((val>>8) & 0xff)); - awacs_burgundy_busy_wait(); - out_le32(&awacs->codec_ctrl, addr + 0x200e00 +((val>>16) & 0xff)); - awacs_burgundy_busy_wait(); - out_le32(&awacs->codec_ctrl, addr + 0x200f00 +((val>>24) & 0xff)); - awacs_burgundy_busy_wait(); -} - -static unsigned -awacs_burgundy_rcw(unsigned addr) -{ - unsigned val = 0; - unsigned long flags; - - /* should have timeouts here */ - spin_lock_irqsave(&dmasound.lock, flags); - - out_le32(&awacs->codec_ctrl, addr + 0x100000); - awacs_burgundy_busy_wait(); - awacs_burgundy_extend_wait(); - val += (in_le32(&awacs->codec_stat) >> 4) & 0xff; - - out_le32(&awacs->codec_ctrl, addr + 0x100100); - awacs_burgundy_busy_wait(); - awacs_burgundy_extend_wait(); - val += ((in_le32(&awacs->codec_stat)>>4) & 0xff) <<8; - - out_le32(&awacs->codec_ctrl, addr + 0x100200); - awacs_burgundy_busy_wait(); - awacs_burgundy_extend_wait(); - val += ((in_le32(&awacs->codec_stat)>>4) & 0xff) <<16; - - out_le32(&awacs->codec_ctrl, addr + 0x100300); - awacs_burgundy_busy_wait(); - awacs_burgundy_extend_wait(); - val += ((in_le32(&awacs->codec_stat)>>4) & 0xff) <<24; - - spin_unlock_irqrestore(&dmasound.lock, flags); - - return val; -} - - -static void -awacs_burgundy_wcb(unsigned addr, unsigned val) -{ - out_le32(&awacs->codec_ctrl, addr + 0x300000 + (val & 0xff)); - awacs_burgundy_busy_wait(); -} - -static unsigned -awacs_burgundy_rcb(unsigned addr) -{ - unsigned val = 0; - unsigned long flags; - - /* should have timeouts here */ - spin_lock_irqsave(&dmasound.lock, flags); - - out_le32(&awacs->codec_ctrl, addr + 0x100000); - awacs_burgundy_busy_wait(); - awacs_burgundy_extend_wait(); - val += (in_le32(&awacs->codec_stat) >> 4) & 0xff; - - spin_unlock_irqrestore(&dmasound.lock, flags); - - return val; -} - -static int -awacs_burgundy_check(void) -{ - /* Checks to see the chip is alive and kicking */ - int error = in_le32(&awacs->codec_ctrl) & MASK_ERRCODE; - - return error == 0xf0000; -} - -static int -awacs_burgundy_init(void) -{ - if (awacs_burgundy_check()) { - printk(KERN_WARNING "dmasound_pmac: burgundy not working :-(\n"); - return 1; - } - - awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_OUTPUTENABLES, - DEF_BURGUNDY_OUTPUTENABLES); - awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, - DEF_BURGUNDY_MORE_OUTPUTENABLES); - awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_OUTPUTSELECTS, - DEF_BURGUNDY_OUTPUTSELECTS); - - awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_INPSEL21, - DEF_BURGUNDY_INPSEL21); - awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_INPSEL3, - DEF_BURGUNDY_INPSEL3); - awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_GAINCD, - DEF_BURGUNDY_GAINCD); - awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_GAINLINE, - DEF_BURGUNDY_GAINLINE); - awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_GAINMIC, - DEF_BURGUNDY_GAINMIC); - awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_GAINMODEM, - DEF_BURGUNDY_GAINMODEM); - - awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_ATTENSPEAKER, - DEF_BURGUNDY_ATTENSPEAKER); - awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_ATTENLINEOUT, - DEF_BURGUNDY_ATTENLINEOUT); - awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_ATTENHP, - DEF_BURGUNDY_ATTENHP); - - awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_MASTER_VOLUME, - DEF_BURGUNDY_MASTER_VOLUME); - awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_VOLCD, - DEF_BURGUNDY_VOLCD); - awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_VOLLINE, - DEF_BURGUNDY_VOLLINE); - awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_VOLMIC, - DEF_BURGUNDY_VOLMIC); - return 0; -} - -static void -awacs_burgundy_write_volume(unsigned address, int volume) -{ - int hardvolume,lvolume,rvolume; - - lvolume = (volume & 0xff) ? (volume & 0xff) + 155 : 0; - rvolume = ((volume >>8)&0xff) ? ((volume >> 8)&0xff ) + 155 : 0; - - hardvolume = lvolume + (rvolume << 16); - - awacs_burgundy_wcw(address, hardvolume); -} - -static int -awacs_burgundy_read_volume(unsigned address) -{ - int softvolume,wvolume; - - wvolume = awacs_burgundy_rcw(address); - - softvolume = (wvolume & 0xff) - 155; - softvolume += (((wvolume >> 16) & 0xff) - 155)<<8; - - return softvolume > 0 ? softvolume : 0; -} - -static int -awacs_burgundy_read_mvolume(unsigned address) -{ - int lvolume,rvolume,wvolume; - - wvolume = awacs_burgundy_rcw(address); - - wvolume &= 0xffff; - - rvolume = (wvolume & 0xff) - 155; - lvolume = ((wvolume & 0xff00)>>8) - 155; - - return lvolume + (rvolume << 8); -} - -static void -awacs_burgundy_write_mvolume(unsigned address, int volume) -{ - int lvolume,rvolume,hardvolume; - - lvolume = (volume &0xff) ? (volume & 0xff) + 155 :0; - rvolume = ((volume >>8) & 0xff) ? (volume >> 8) + 155 :0; - - hardvolume = lvolume + (rvolume << 8); - hardvolume += (hardvolume << 16); - - awacs_burgundy_wcw(address, hardvolume); -} - -/* End burgundy functions */ - -/* Set up output volumes on machines with the 'perch/whisper' extension card. - * this has an SGS i2c chip (7433) which is accessed using the cuda. - * - * TODO: split this out and make use of the other parts of the SGS chip to - * do Bass, Treble etc. - */ - -static void -awacs_enable_amp(int spkr_vol) -{ -#ifdef CONFIG_ADB_CUDA - struct adb_request req; - - if (sys_ctrler != SYS_CTRLER_CUDA) - return; - - /* turn on headphones */ - cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC, - 0x8a, 4, 0); - while (!req.complete) cuda_poll(); - cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC, - 0x8a, 6, 0); - while (!req.complete) cuda_poll(); - - /* turn on speaker */ - cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC, - 0x8a, 3, (100 - (spkr_vol & 0xff)) * 32 / 100); - while (!req.complete) cuda_poll(); - cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC, - 0x8a, 5, (100 - ((spkr_vol >> 8) & 0xff)) * 32 / 100); - while (!req.complete) cuda_poll(); - - cuda_request(&req, NULL, 5, CUDA_PACKET, - CUDA_GET_SET_IIC, 0x8a, 1, 0x29); - while (!req.complete) cuda_poll(); -#endif /* CONFIG_ADB_CUDA */ -} - - -/*** Mid level stuff *********************************************************/ - - -/* - * /dev/mixer abstraction - */ - -static void do_line_lev(int data) -{ - line_lev = data ; - awacs_reg[0] &= ~MASK_MUX_AUDIN; - if ((data & 0xff) >= 50) - awacs_reg[0] |= MASK_MUX_AUDIN; - awacs_write(MASK_ADDR0 | awacs_reg[0]); -} - -static void do_ip_gain(int data) -{ - ip_gain = data ; - data &= 0xff; - awacs_reg[0] &= ~MASK_GAINLINE; - if (awacs_revision == AWACS_SCREAMER) { - awacs_reg[6] &= ~MASK_MIC_BOOST ; - if (data >= 33) { - awacs_reg[0] |= MASK_GAINLINE; - if( data >= 66) - awacs_reg[6] |= MASK_MIC_BOOST ; - } - awacs_write(MASK_ADDR6 | awacs_reg[6]) ; - } else { - if (data >= 50) - awacs_reg[0] |= MASK_GAINLINE; - } - awacs_write(MASK_ADDR0 | awacs_reg[0]); -} - -static void do_mic_lev(int data) -{ - mic_lev = data ; - data &= 0xff; - awacs_reg[0] &= ~MASK_MUX_MIC; - if (data >= 50) - awacs_reg[0] |= MASK_MUX_MIC; - awacs_write(MASK_ADDR0 | awacs_reg[0]); -} - -static void do_cd_lev(int data) -{ - cd_lev = data ; - awacs_reg[0] &= ~MASK_MUX_CD; - if ((data & 0xff) >= 50) - awacs_reg[0] |= MASK_MUX_CD; - awacs_write(MASK_ADDR0 | awacs_reg[0]); -} - -static void do_rec_lev(int data) -{ - int left, right ; - rec_lev = data ; - /* need to fudge this to use the volume setter routine */ - left = 100 - (data & 0xff) ; if( left < 0 ) left = 0 ; - right = 100 - ((data >> 8) & 0xff) ; if( right < 0 ) right = 0 ; - left |= (right << 8 ); - left = awacs_volume_setter(left, 0, 0, 4); -} - -static void do_passthru_vol(int data) -{ - passthru_vol = data ; - awacs_reg[1] &= ~MASK_LOOPTHRU; - if (awacs_revision == AWACS_SCREAMER) { - if( data ) { /* switch it on for non-zero */ - awacs_reg[1] |= MASK_LOOPTHRU; - awacs_write(MASK_ADDR1 | awacs_reg[1]); - } - data = awacs_volume_setter(data, 5, 0, 6) ; - } else { - if ((data & 0xff) >= 50) - awacs_reg[1] |= MASK_LOOPTHRU; - awacs_write(MASK_ADDR1 | awacs_reg[1]); - data = (awacs_reg[1] & MASK_LOOPTHRU)? 100: 0; - } -} - -static int awacs_mixer_ioctl(u_int cmd, u_long arg) -{ - int data; - int rc; - - switch (cmd) { - case SOUND_MIXER_READ_CAPS: - /* say we will allow multiple inputs? prob. wrong - so I'm switching it to single */ - return IOCTL_OUT(arg, 1); - case SOUND_MIXER_READ_DEVMASK: - data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER - | SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD - | SOUND_MASK_IGAIN | SOUND_MASK_RECLEV - | SOUND_MASK_ALTPCM - | SOUND_MASK_MONITOR; - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_READ_RECMASK: - data = SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD; - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_READ_RECSRC: - data = 0; - if (awacs_reg[0] & MASK_MUX_AUDIN) - data |= SOUND_MASK_LINE; - if (awacs_reg[0] & MASK_MUX_MIC) - data |= SOUND_MASK_MIC; - if (awacs_reg[0] & MASK_MUX_CD) - data |= SOUND_MASK_CD; - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_WRITE_RECSRC: - IOCTL_IN(arg, data); - data &= (SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD); - awacs_reg[0] &= ~(MASK_MUX_CD | MASK_MUX_MIC - | MASK_MUX_AUDIN); - if (data & SOUND_MASK_LINE) - awacs_reg[0] |= MASK_MUX_AUDIN; - if (data & SOUND_MASK_MIC) - awacs_reg[0] |= MASK_MUX_MIC; - if (data & SOUND_MASK_CD) - awacs_reg[0] |= MASK_MUX_CD; - awacs_write(awacs_reg[0] | MASK_ADDR0); - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_READ_STEREODEVS: - data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER| SOUND_MASK_RECLEV ; - if (awacs_revision == AWACS_SCREAMER) - data |= SOUND_MASK_MONITOR ; - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_WRITE_VOLUME: - IOCTL_IN(arg, data); - line_vol = data ; - awacs_volume_setter(data, 2, 0, 6); - /* fall through */ - case SOUND_MIXER_READ_VOLUME: - rc = IOCTL_OUT(arg, line_vol); - break; - case SOUND_MIXER_WRITE_SPEAKER: - IOCTL_IN(arg, data); - spk_vol = data ; - if (has_perch) - awacs_enable_amp(data); - else - (void)awacs_volume_setter(data, 4, MASK_CMUTE, 6); - /* fall though */ - case SOUND_MIXER_READ_SPEAKER: - rc = IOCTL_OUT(arg, spk_vol); - break; - case SOUND_MIXER_WRITE_ALTPCM: /* really bell volume */ - IOCTL_IN(arg, data); - beep_vol = data & 0xff; - /* fall through */ - case SOUND_MIXER_READ_ALTPCM: - rc = IOCTL_OUT(arg, beep_vol); - break; - case SOUND_MIXER_WRITE_LINE: - IOCTL_IN(arg, data); - do_line_lev(data) ; - /* fall through */ - case SOUND_MIXER_READ_LINE: - rc = IOCTL_OUT(arg, line_lev); - break; - case SOUND_MIXER_WRITE_IGAIN: - IOCTL_IN(arg, data); - do_ip_gain(data) ; - /* fall through */ - case SOUND_MIXER_READ_IGAIN: - rc = IOCTL_OUT(arg, ip_gain); - break; - case SOUND_MIXER_WRITE_MIC: - IOCTL_IN(arg, data); - do_mic_lev(data); - /* fall through */ - case SOUND_MIXER_READ_MIC: - rc = IOCTL_OUT(arg, mic_lev); - break; - case SOUND_MIXER_WRITE_CD: - IOCTL_IN(arg, data); - do_cd_lev(data); - /* fall through */ - case SOUND_MIXER_READ_CD: - rc = IOCTL_OUT(arg, cd_lev); - break; - case SOUND_MIXER_WRITE_RECLEV: - IOCTL_IN(arg, data); - do_rec_lev(data) ; - /* fall through */ - case SOUND_MIXER_READ_RECLEV: - rc = IOCTL_OUT(arg, rec_lev); - break; - case MIXER_WRITE(SOUND_MIXER_MONITOR): - IOCTL_IN(arg, data); - do_passthru_vol(data) ; - /* fall through */ - case MIXER_READ(SOUND_MIXER_MONITOR): - rc = IOCTL_OUT(arg, passthru_vol); - break; - default: - rc = -EINVAL; - } - - return rc; -} - -static void awacs_mixer_init(void) -{ - awacs_volume_setter(line_vol, 2, 0, 6); - if (has_perch) - awacs_enable_amp(spk_vol); - else - (void)awacs_volume_setter(spk_vol, 4, MASK_CMUTE, 6); - do_line_lev(line_lev) ; - do_ip_gain(ip_gain) ; - do_mic_lev(mic_lev) ; - do_cd_lev(cd_lev) ; - do_rec_lev(rec_lev) ; - do_passthru_vol(passthru_vol) ; -} - -static int burgundy_mixer_ioctl(u_int cmd, u_long arg) -{ - int data; - int rc; - - /* We are, we are, we are... Burgundy or better */ - switch(cmd) { - case SOUND_MIXER_READ_DEVMASK: - data = SOUND_MASK_VOLUME | SOUND_MASK_CD | - SOUND_MASK_LINE | SOUND_MASK_MIC | - SOUND_MASK_SPEAKER | SOUND_MASK_ALTPCM; - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_READ_RECMASK: - data = SOUND_MASK_LINE | SOUND_MASK_MIC - | SOUND_MASK_CD; - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_READ_RECSRC: - data = 0; - if (awacs_reg[0] & MASK_MUX_AUDIN) - data |= SOUND_MASK_LINE; - if (awacs_reg[0] & MASK_MUX_MIC) - data |= SOUND_MASK_MIC; - if (awacs_reg[0] & MASK_MUX_CD) - data |= SOUND_MASK_CD; - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_WRITE_RECSRC: - IOCTL_IN(arg, data); - data &= (SOUND_MASK_LINE - | SOUND_MASK_MIC | SOUND_MASK_CD); - awacs_reg[0] &= ~(MASK_MUX_CD | MASK_MUX_MIC - | MASK_MUX_AUDIN); - if (data & SOUND_MASK_LINE) - awacs_reg[0] |= MASK_MUX_AUDIN; - if (data & SOUND_MASK_MIC) - awacs_reg[0] |= MASK_MUX_MIC; - if (data & SOUND_MASK_CD) - awacs_reg[0] |= MASK_MUX_CD; - awacs_write(awacs_reg[0] | MASK_ADDR0); - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_READ_STEREODEVS: - data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER - | SOUND_MASK_RECLEV | SOUND_MASK_CD - | SOUND_MASK_LINE; - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_READ_CAPS: - rc = IOCTL_OUT(arg, 0); - break; - case SOUND_MIXER_WRITE_VOLUME: - IOCTL_IN(arg, data); - awacs_burgundy_write_mvolume(MASK_ADDR_BURGUNDY_MASTER_VOLUME, data); - /* Fall through */ - case SOUND_MIXER_READ_VOLUME: - rc = IOCTL_OUT(arg, awacs_burgundy_read_mvolume(MASK_ADDR_BURGUNDY_MASTER_VOLUME)); - break; - case SOUND_MIXER_WRITE_SPEAKER: - IOCTL_IN(arg, data); - if (!(data & 0xff)) { - /* Mute the left speaker */ - awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, - awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) & ~0x2); - } else { - /* Unmute the left speaker */ - awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, - awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) | 0x2); - } - if (!(data & 0xff00)) { - /* Mute the right speaker */ - awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, - awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) & ~0x4); - } else { - /* Unmute the right speaker */ - awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, - awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) | 0x4); - } - - data = (((data&0xff)*16)/100 > 0xf ? 0xf : - (((data&0xff)*16)/100)) + - ((((data>>8)*16)/100 > 0xf ? 0xf : - ((((data>>8)*16)/100)))<<4); - - awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_ATTENSPEAKER, ~data); - /* Fall through */ - case SOUND_MIXER_READ_SPEAKER: - data = awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_ATTENSPEAKER); - data = (((data & 0xf)*100)/16) + ((((data>>4)*100)/16)<<8); - rc = IOCTL_OUT(arg, (~data) & 0x0000ffff); - break; - case SOUND_MIXER_WRITE_ALTPCM: /* really bell volume */ - IOCTL_IN(arg, data); - beep_vol = data & 0xff; - /* fall through */ - case SOUND_MIXER_READ_ALTPCM: - rc = IOCTL_OUT(arg, beep_vol); - break; - case SOUND_MIXER_WRITE_LINE: - IOCTL_IN(arg, data); - awacs_burgundy_write_volume(MASK_ADDR_BURGUNDY_VOLLINE, data); - - /* fall through */ - case SOUND_MIXER_READ_LINE: - data = awacs_burgundy_read_volume(MASK_ADDR_BURGUNDY_VOLLINE); - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_WRITE_MIC: - IOCTL_IN(arg, data); - /* Mic is mono device */ - data = (data << 8) + (data << 24); - awacs_burgundy_write_volume(MASK_ADDR_BURGUNDY_VOLMIC, data); - /* fall through */ - case SOUND_MIXER_READ_MIC: - data = awacs_burgundy_read_volume(MASK_ADDR_BURGUNDY_VOLMIC); - data <<= 24; - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_WRITE_CD: - IOCTL_IN(arg, data); - awacs_burgundy_write_volume(MASK_ADDR_BURGUNDY_VOLCD, data); - /* fall through */ - case SOUND_MIXER_READ_CD: - data = awacs_burgundy_read_volume(MASK_ADDR_BURGUNDY_VOLCD); - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_WRITE_RECLEV: - IOCTL_IN(arg, data); - data = awacs_volume_setter(data, 0, 0, 4); - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_READ_RECLEV: - data = awacs_get_volume(awacs_reg[0], 4); - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_OUTMASK: - case SOUND_MIXER_OUTSRC: - default: - rc = -EINVAL; - } - - return rc; -} - -static int daca_mixer_ioctl(u_int cmd, u_long arg) -{ - int data; - int rc; - - /* And the DACA's no genius either! */ - - switch(cmd) { - case SOUND_MIXER_READ_DEVMASK: - data = SOUND_MASK_VOLUME; - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_READ_RECMASK: - data = 0; - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_READ_RECSRC: - data = 0; - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_WRITE_RECSRC: - IOCTL_IN(arg, data); - data =0; - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_READ_STEREODEVS: - data = SOUND_MASK_VOLUME; - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_READ_CAPS: - rc = IOCTL_OUT(arg, 0); - break; - case SOUND_MIXER_WRITE_VOLUME: - IOCTL_IN(arg, data); - daca_set_volume(data, data); - /* Fall through */ - case SOUND_MIXER_READ_VOLUME: - daca_get_volume(& data, &data); - rc = IOCTL_OUT(arg, data); - break; - case SOUND_MIXER_OUTMASK: - case SOUND_MIXER_OUTSRC: - default: - rc = -EINVAL; - } - return rc; -} - -static int PMacMixerIoctl(u_int cmd, u_long arg) -{ - int rc; - - /* Different IOCTLS for burgundy and, eventually, DACA & Tumbler */ - - TRY_LOCK(); - - switch (awacs_revision){ - case AWACS_BURGUNDY: - rc = burgundy_mixer_ioctl(cmd, arg); - break ; - case AWACS_DACA: - rc = daca_mixer_ioctl(cmd, arg); - break; - case AWACS_TUMBLER: - case AWACS_SNAPPER: - rc = tas_mixer_ioctl(cmd, arg); - break ; - default: /* ;-)) */ - rc = awacs_mixer_ioctl(cmd, arg); - } - - UNLOCK(); - - return rc; -} - -static void PMacMixerInit(void) -{ - switch (awacs_revision) { - case AWACS_TUMBLER: - printk("AE-Init tumbler mixer\n"); - break ; - case AWACS_SNAPPER: - printk("AE-Init snapper mixer\n"); - break ; - case AWACS_DACA: - case AWACS_BURGUNDY: - break ; /* don't know yet */ - case AWACS_AWACS: - case AWACS_SCREAMER: - default: - awacs_mixer_init() ; - break ; - } -} - -/* Write/Read sq setup functions: - Check to see if we have enough (or any) dbdma cmd buffers for the - user's fragment settings. If not, allocate some. If this fails we will - point at the beep buffer - as an emergency provision - to stop dma tromping - on some random bit of memory (if someone lets it go anyway). - The command buffers are then set up to point to the fragment buffers - (allocated elsewhere). We need n+1 commands the last of which holds - a NOP + loop to start. -*/ - -static int PMacWriteSqSetup(void) -{ - int i, count = 600 ; - volatile struct dbdma_cmd *cp; - - LOCK(); - - /* stop the controller from doing any output - if it isn't already. - it _should_ be before this is called anyway */ - - out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16); - while ((in_le32(&awacs_txdma->status) & RUN) && count--) - udelay(1); -#ifdef DEBUG_DMASOUND -if (count <= 0) - printk("dmasound_pmac: write sq setup: timeout waiting for dma to stop\n"); -#endif - - if ((write_sq.max_count + 1) > number_of_tx_cmd_buffers) { - kfree(awacs_tx_cmd_space); - number_of_tx_cmd_buffers = 0; - - /* we need nbufs + 1 (for the loop) and we should request + 1 - again because the DBDMA_ALIGN might pull the start up by up - to sizeof(struct dbdma_cmd) - 4. - */ - - awacs_tx_cmd_space = kmalloc - ((write_sq.max_count + 1 + 1) * sizeof(struct dbdma_cmd), - GFP_KERNEL); - if (awacs_tx_cmd_space == NULL) { - /* don't leave it dangling - nasty but better than a - random address */ - out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd)); - printk(KERN_ERR - "dmasound_pmac: can't allocate dbdma cmd buffers" - ", driver disabled\n"); - UNLOCK(); - return -ENOMEM; - } - awacs_tx_cmds = (volatile struct dbdma_cmd *) - DBDMA_ALIGN(awacs_tx_cmd_space); - number_of_tx_cmd_buffers = write_sq.max_count + 1; - } - - cp = awacs_tx_cmds; - memset((void *)cp, 0, (write_sq.max_count+1) * sizeof(struct dbdma_cmd)); - for (i = 0; i < write_sq.max_count; ++i, ++cp) { - st_le32(&cp->phy_addr, virt_to_bus(write_sq.buffers[i])); - } - st_le16(&cp->command, DBDMA_NOP + BR_ALWAYS); - st_le32(&cp->cmd_dep, virt_to_bus(awacs_tx_cmds)); - /* point the controller at the command stack - ready to go */ - out_le32(&awacs_txdma->cmdptr, virt_to_bus(awacs_tx_cmds)); - UNLOCK(); - return 0; -} - -static int PMacReadSqSetup(void) -{ - int i, count = 600; - volatile struct dbdma_cmd *cp; - - LOCK(); - - /* stop the controller from doing any input - if it isn't already. - it _should_ be before this is called anyway */ - - out_le32(&awacs_rxdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16); - while ((in_le32(&awacs_rxdma->status) & RUN) && count--) - udelay(1); -#ifdef DEBUG_DMASOUND -if (count <= 0) - printk("dmasound_pmac: read sq setup: timeout waiting for dma to stop\n"); -#endif - - if ((read_sq.max_count+1) > number_of_rx_cmd_buffers ) { - kfree(awacs_rx_cmd_space); - number_of_rx_cmd_buffers = 0; - - /* we need nbufs + 1 (for the loop) and we should request + 1 again - because the DBDMA_ALIGN might pull the start up by up to - sizeof(struct dbdma_cmd) - 4 (assuming kmalloc aligns 32 bits). - */ - - awacs_rx_cmd_space = kmalloc - ((read_sq.max_count + 1 + 1) * sizeof(struct dbdma_cmd), - GFP_KERNEL); - if (awacs_rx_cmd_space == NULL) { - /* don't leave it dangling - nasty but better than a - random address */ - out_le32(&awacs_rxdma->cmdptr, virt_to_bus(beep_dbdma_cmd)); - printk(KERN_ERR - "dmasound_pmac: can't allocate dbdma cmd buffers" - ", driver disabled\n"); - UNLOCK(); - return -ENOMEM; - } - awacs_rx_cmds = (volatile struct dbdma_cmd *) - DBDMA_ALIGN(awacs_rx_cmd_space); - number_of_rx_cmd_buffers = read_sq.max_count + 1 ; - } - cp = awacs_rx_cmds; - memset((void *)cp, 0, (read_sq.max_count+1) * sizeof(struct dbdma_cmd)); - - /* Set dma buffers up in a loop */ - for (i = 0; i < read_sq.max_count; i++,cp++) { - st_le32(&cp->phy_addr, virt_to_bus(read_sq.buffers[i])); - st_le16(&cp->command, INPUT_MORE + INTR_ALWAYS); - st_le16(&cp->req_count, read_sq.block_size); - st_le16(&cp->xfer_status, 0); - } - - /* The next two lines make the thing loop around. - */ - st_le16(&cp->command, DBDMA_NOP + BR_ALWAYS); - st_le32(&cp->cmd_dep, virt_to_bus(awacs_rx_cmds)); - /* point the controller at the command stack - ready to go */ - out_le32(&awacs_rxdma->cmdptr, virt_to_bus(awacs_rx_cmds)); - - UNLOCK(); - return 0; -} - -/* TODO: this needs work to guarantee that when it returns DMA has stopped - but in a more elegant way than is done here.... -*/ - -static void PMacAbortRead(void) -{ - int i; - volatile struct dbdma_cmd *cp; - - LOCK(); - /* give it a chance to update the output and provide the IRQ - that is expected. - */ - - out_le32(&awacs_rxdma->control, ((FLUSH) << 16) + FLUSH ); - - cp = awacs_rx_cmds; - for (i = 0; i < read_sq.max_count; i++,cp++) - st_le16(&cp->command, DBDMA_STOP); - /* - * We should probably wait for the thing to stop before we - * release the memory. - */ - - msleep(100) ; /* give it a (small) chance to act */ - - /* apply the sledgehammer approach - just stop it now */ - - out_le32(&awacs_rxdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16); - UNLOCK(); -} - -extern char *get_afmt_string(int); -static int PMacStateInfo(char *b, size_t sp) -{ - int i, len = 0; - len = sprintf(b,"HW rates: "); - switch (awacs_revision){ - case AWACS_DACA: - case AWACS_BURGUNDY: - len += sprintf(b,"44100 ") ; - break ; - case AWACS_TUMBLER: - case AWACS_SNAPPER: - for (i=0; i<1; i++){ - if (tas_freqs_ok[i]) - len += sprintf(b+len,"%d ", tas_freqs[i]) ; - } - break ; - case AWACS_AWACS: - case AWACS_SCREAMER: - default: - for (i=0; i<8; i++){ - if (awacs_freqs_ok[i]) - len += sprintf(b+len,"%d ", awacs_freqs[i]) ; - } - break ; - } - len += sprintf(b+len,"s/sec\n") ; - if (len < sp) { - len += sprintf(b+len,"HW AFMTS: "); - i = AFMT_U16_BE ; - while (i) { - if (i & dmasound.mach.hardware_afmts) - len += sprintf(b+len,"%s ", - get_afmt_string(i & dmasound.mach.hardware_afmts)); - i >>= 1 ; - } - len += sprintf(b+len,"\n") ; - } - return len ; -} - -/*** Machine definitions *****************************************************/ - -static SETTINGS def_hard = { - .format = AFMT_S16_BE, - .stereo = 1, - .size = 16, - .speed = 44100 -} ; - -static SETTINGS def_soft = { - .format = AFMT_S16_BE, - .stereo = 1, - .size = 16, - .speed = 44100 -} ; - -static MACHINE machPMac = { - .name = awacs_name, - .name2 = "PowerMac Built-in Sound", - .owner = THIS_MODULE, - .dma_alloc = PMacAlloc, - .dma_free = PMacFree, - .irqinit = PMacIrqInit, -#ifdef MODULE - .irqcleanup = PMacIrqCleanup, -#endif /* MODULE */ - .init = PMacInit, - .silence = PMacSilence, - .setFormat = PMacSetFormat, - .setVolume = PMacSetVolume, - .play = PMacPlay, - .record = NULL, /* default to no record */ - .mixer_init = PMacMixerInit, - .mixer_ioctl = PMacMixerIoctl, - .write_sq_setup = PMacWriteSqSetup, - .read_sq_setup = PMacReadSqSetup, - .state_info = PMacStateInfo, - .abort_read = PMacAbortRead, - .min_dsp_speed = 7350, - .max_dsp_speed = 44100, - .version = ((DMASOUND_AWACS_REVISION<<8) + DMASOUND_AWACS_EDITION) -}; - - -/*** Config & Setup **********************************************************/ - -/* Check for pmac models that we care about in terms of special actions. -*/ - -void __init -set_model(void) -{ - /* portables/lap-tops */ - - if (machine_is_compatible("AAPL,3400/2400") || - machine_is_compatible("AAPL,3500")) { - is_pbook_3X00 = 1 ; - } - if (machine_is_compatible("PowerBook1,1") || /* lombard */ - machine_is_compatible("AAPL,PowerBook1998")){ /* wallstreet */ - is_pbook_g3 = 1 ; - return ; - } -} - -/* Get the OF node that tells us about the registers, interrupts etc. to use - for sound IO. - - On most machines the sound IO OF node is the 'davbus' node. On newer pmacs - with DACA (& Tumbler) the node to use is i2s-a. On much older machines i.e. - before 9500 there is no davbus node and we have to use the 'awacs' property. - - In the latter case we signal this by setting the codec value - so that the - code that looks for chip properties knows how to go about it. -*/ - -static struct device_node* __init -get_snd_io_node(void) -{ - struct device_node *np; - - /* set up awacs_node for early OF which doesn't have a full set of - * properties on davbus - */ - awacs_node = of_find_node_by_name(NULL, "awacs"); - if (awacs_node) - awacs_revision = AWACS_AWACS; - - /* powermac models after 9500 (other than those which use DACA or - * Tumbler) have a node called "davbus". - */ - np = of_find_node_by_name(NULL, "davbus"); - /* - * if we didn't find a davbus device, try 'i2s-a' since - * this seems to be what iBooks (& Tumbler) have. - */ - if (np == NULL) { - i2s_node = of_find_node_by_name(NULL, "i2s-a"); - np = of_node_get(i2s_node); - } - - /* if we didn't find this - perhaps we are on an early model - * which _only_ has an 'awacs' node - */ - if (np == NULL && awacs_node) - np = of_node_get(awacs_node); - - /* if we failed all these return null - this will cause the - * driver to give up... - */ - return np ; -} - -/* Get the OF node that contains the info about the sound chip, inputs s-rates - etc. - This node does not exist (or contains much reduced info) on earlier machines - we have to deduce the info other ways for these. -*/ - -static struct device_node* __init -get_snd_info_node(struct device_node *io) -{ - struct device_node *info; - - for_each_node_by_name(info, "sound") - if (info->parent == io) - break; - return info; -} - -/* Find out what type of codec we have. -*/ - -static int __init -get_codec_type(struct device_node *info) -{ - /* already set if pre-davbus model and info will be NULL */ - int codec = awacs_revision ; - - if (info) { - /* must do awacs first to allow screamer to overide it */ - if (of_device_is_compatible(info, "awacs")) - codec = AWACS_AWACS ; - if (of_device_is_compatible(info, "screamer")) - codec = AWACS_SCREAMER; - if (of_device_is_compatible(info, "burgundy")) - codec = AWACS_BURGUNDY ; - if (of_device_is_compatible(info, "daca")) - codec = AWACS_DACA; - if (of_device_is_compatible(info, "tumbler")) - codec = AWACS_TUMBLER; - if (of_device_is_compatible(info, "snapper")) - codec = AWACS_SNAPPER; - } - return codec ; -} - -/* find out what type, if any, of expansion card we have -*/ -static void __init -get_expansion_type(void) -{ - struct device_node *dn; - - dn = of_find_node_by_name(NULL, "perch"); - if (dn != NULL) - has_perch = 1; - of_node_put(dn); - - dn = of_find_node_by_name(NULL, "pb-ziva-pc"); - if (dn != NULL) - has_ziva = 1; - of_node_put(dn); - /* need to work out how we deal with iMac SRS module */ -} - -/* set up frame rates. - * I suspect that these routines don't quite go about it the right way: - * - where there is more than one rate - I think that the first property - * value is the number of rates. - * TODO: check some more device trees and modify accordingly - * Set dmasound.mach.max_dsp_rate on the basis of these routines. -*/ - -static void __init -awacs_init_frame_rates(const unsigned int *prop, unsigned int l) -{ - int i ; - if (prop) { - for (i=0; i<8; i++) - awacs_freqs_ok[i] = 0 ; - for (l /= sizeof(int); l > 0; --l) { - unsigned int r = *prop++; - /* Apple 'Fixed' format */ - if (r >= 0x10000) - r >>= 16; - for (i = 0; i < 8; ++i) { - if (r == awacs_freqs[i]) { - awacs_freqs_ok[i] = 1; - break; - } - } - } - } - /* else we assume that all the rates are available */ -} - -static void __init -burgundy_init_frame_rates(const unsigned int *prop, unsigned int l) -{ - int temp[9] ; - int i = 0 ; - if (prop) { - for (l /= sizeof(int); l > 0; --l) { - unsigned int r = *prop++; - /* Apple 'Fixed' format */ - if (r >= 0x10000) - r >>= 16; - temp[i] = r ; - i++ ; if(i>=9) i=8; - } - } -#ifdef DEBUG_DMASOUND -if (i > 1){ - int j; - printk("dmasound_pmac: burgundy with multiple frame rates\n"); - for(j=0; j<i; j++) - printk("%d ", temp[j]) ; - printk("\n") ; -} -#endif -} - -static void __init -daca_init_frame_rates(const unsigned int *prop, unsigned int l) -{ - int temp[9] ; - int i = 0 ; - if (prop) { - for (l /= sizeof(int); l > 0; --l) { - unsigned int r = *prop++; - /* Apple 'Fixed' format */ - if (r >= 0x10000) - r >>= 16; - temp[i] = r ; - i++ ; if(i>=9) i=8; - - } - } -#ifdef DEBUG_DMASOUND -if (i > 1){ - int j; - printk("dmasound_pmac: DACA with multiple frame rates\n"); - for(j=0; j<i; j++) - printk("%d ", temp[j]) ; - printk("\n") ; -} -#endif -} - -static void __init -init_frame_rates(const unsigned int *prop, unsigned int l) -{ - switch (awacs_revision) { - case AWACS_TUMBLER: - case AWACS_SNAPPER: - tas_init_frame_rates(prop, l); - break ; - case AWACS_DACA: - daca_init_frame_rates(prop, l); - break ; - case AWACS_BURGUNDY: - burgundy_init_frame_rates(prop, l); - break ; - default: - awacs_init_frame_rates(prop, l); - break ; - } -} - -/* find things/machines that can't do mac-io byteswap -*/ - -static void __init -set_hw_byteswap(struct device_node *io) -{ - struct device_node *mio ; - unsigned int kl = 0 ; - - /* if seems that Keylargo can't byte-swap */ - - for (mio = io->parent; mio ; mio = mio->parent) { - if (strcmp(mio->name, "mac-io") == 0) { - if (of_device_is_compatible(mio, "Keylargo")) - kl = 1; - break; - } - } - hw_can_byteswap = !kl; -} - -/* Allocate the resources necessary for beep generation. This cannot be (quite) - done statically (yet) because we cannot do virt_to_bus() on static vars when - the code is loaded as a module. - - for the sake of saving the possibility that two allocations will incur the - overhead of two pull-ups in DBDMA_ALIGN() we allocate the 'emergency' dmdma - command here as well... even tho' it is not part of the beep process. -*/ - -int32_t -__init setup_beep(void) -{ - /* Initialize beep stuff */ - /* want one cmd buffer for beeps, and a second one for emergencies - - i.e. dbdma error conditions. - ask for three to allow for pull up in DBDMA_ALIGN(). - */ - beep_dbdma_cmd_space = - kmalloc((2 + 1) * sizeof(struct dbdma_cmd), GFP_KERNEL); - if(beep_dbdma_cmd_space == NULL) { - printk(KERN_ERR "dmasound_pmac: no beep dbdma cmd space\n") ; - return -ENOMEM ; - } - beep_dbdma_cmd = (volatile struct dbdma_cmd *) - DBDMA_ALIGN(beep_dbdma_cmd_space); - /* set up emergency dbdma cmd */ - emergency_dbdma_cmd = beep_dbdma_cmd+1 ; - beep_buf = kmalloc(BEEP_BUFLEN * 4, GFP_KERNEL); - if (beep_buf == NULL) { - printk(KERN_ERR "dmasound_pmac: no memory for beep buffer\n"); - kfree(beep_dbdma_cmd_space) ; - return -ENOMEM ; - } - return 0 ; -} - -static struct input_dev *awacs_beep_dev; - -int __init dmasound_awacs_init(void) -{ - struct device_node *io = NULL, *info = NULL; - int vol, res; - - if (!machine_is(powermac)) - return -ENODEV; - - awacs_subframe = 0; - awacs_revision = 0; - hw_can_byteswap = 1 ; /* most can */ - - /* look for models we need to handle specially */ - set_model() ; - - /* find the OF node that tells us about the dbdma stuff - */ - io = get_snd_io_node(); - if (io == NULL) { -#ifdef DEBUG_DMASOUND -printk("dmasound_pmac: couldn't find sound io OF node\n"); -#endif - goto no_device; - } - - /* find the OF node that tells us about the sound sub-system - * this doesn't exist on pre-davbus machines (earlier than 9500) - */ - if (awacs_revision != AWACS_AWACS) { /* set for pre-davbus */ - info = get_snd_info_node(io) ; - if (info == NULL){ -#ifdef DEBUG_DMASOUND -printk("dmasound_pmac: couldn't find 'sound' OF node\n"); -#endif - goto no_device; - } - } - - awacs_revision = get_codec_type(info) ; - if (awacs_revision == 0) { -#ifdef DEBUG_DMASOUND -printk("dmasound_pmac: couldn't find a Codec we can handle\n"); -#endif - goto no_device; /* we don't know this type of h/w */ - } - - /* set up perch, ziva, SRS or whatever else we have as sound - * expansion. - */ - get_expansion_type(); - - /* we've now got enough information to make up the audio topology. - * we will map the sound part of mac-io now so that we can probe for - * other info if necessary (early AWACS we want to read chip ids) - */ - - if (of_get_address(io, 2, NULL, NULL) == NULL) { - /* OK - maybe we need to use the 'awacs' node (on earlier - * machines). - */ - if (awacs_node) { - of_node_put(io); - io = of_node_get(awacs_node); - if (of_get_address(io, 2, NULL, NULL) == NULL) { - printk("dmasound_pmac: can't use %s\n", - io->full_name); - goto no_device; - } - } else - printk("dmasound_pmac: can't use %s\n", io->full_name); - } - - if (of_address_to_resource(io, 0, &awacs_rsrc[0]) || - request_mem_region(awacs_rsrc[0].start, - awacs_rsrc[0].end - awacs_rsrc[0].start + 1, - " (IO)") == NULL) { - printk(KERN_ERR "dmasound: can't request IO resource !\n"); - goto no_device; - } - if (of_address_to_resource(io, 1, &awacs_rsrc[1]) || - request_mem_region(awacs_rsrc[1].start, - awacs_rsrc[1].end - awacs_rsrc[1].start + 1, - " (tx dma)") == NULL) { - release_mem_region(awacs_rsrc[0].start, - awacs_rsrc[0].end - awacs_rsrc[0].start + 1); - printk(KERN_ERR "dmasound: can't request Tx DMA resource !\n"); - goto no_device; - } - if (of_address_to_resource(io, 2, &awacs_rsrc[2]) || - request_mem_region(awacs_rsrc[2].start, - awacs_rsrc[2].end - awacs_rsrc[2].start + 1, - " (rx dma)") == NULL) { - release_mem_region(awacs_rsrc[0].start, - awacs_rsrc[0].end - awacs_rsrc[0].start + 1); - release_mem_region(awacs_rsrc[1].start, - awacs_rsrc[1].end - awacs_rsrc[1].start + 1); - printk(KERN_ERR "dmasound: can't request Rx DMA resource !\n"); - goto no_device; - } - - awacs_beep_dev = input_allocate_device(); - if (!awacs_beep_dev) { - release_mem_region(awacs_rsrc[0].start, - awacs_rsrc[0].end - awacs_rsrc[0].start + 1); - release_mem_region(awacs_rsrc[1].start, - awacs_rsrc[1].end - awacs_rsrc[1].start + 1); - release_mem_region(awacs_rsrc[2].start, - awacs_rsrc[2].end - awacs_rsrc[2].start + 1); - printk(KERN_ERR "dmasound: can't allocate input device !\n"); - goto no_device; - } - - awacs_beep_dev->name = "dmasound beeper"; - awacs_beep_dev->phys = "macio/input0"; - awacs_beep_dev->id.bustype = BUS_HOST; - awacs_beep_dev->event = awacs_beep_event; - awacs_beep_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE); - awacs_beep_dev->evbit[0] = BIT(EV_SND); - - /* all OF versions I've seen use this value */ - if (i2s_node) - i2s = ioremap(awacs_rsrc[0].start, 0x1000); - else - awacs = ioremap(awacs_rsrc[0].start, 0x1000); - awacs_txdma = ioremap(awacs_rsrc[1].start, 0x100); - awacs_rxdma = ioremap(awacs_rsrc[2].start, 0x100); - - /* first of all make sure that the chip is powered up....*/ - pmac_call_feature(PMAC_FTR_SOUND_CHIP_ENABLE, io, 0, 1); - if (awacs_revision == AWACS_SCREAMER && awacs) - awacs_recalibrate(); - - awacs_irq = irq_of_parse_and_map(io, 0); - awacs_tx_irq = irq_of_parse_and_map(io, 1); - awacs_rx_irq = irq_of_parse_and_map(io, 2); - - /* Hack for legacy crap that will be killed someday */ - of_node_put(awacs_node); - awacs_node = of_node_get(io); - - /* if we have an awacs or screamer - probe the chip to make - * sure we have the right revision. - */ - - if (awacs_revision <= AWACS_SCREAMER){ - uint32_t temp, rev, mfg ; - /* find out the awacs revision from the chip */ - temp = in_le32(&awacs->codec_stat); - rev = (temp >> 12) & 0xf; - mfg = (temp >> 8) & 0xf; -#ifdef DEBUG_DMASOUND -printk("dmasound_pmac: Awacs/Screamer Codec Mfct: %d Rev %d\n", mfg, rev); -#endif - if (rev >= AWACS_SCREAMER) - awacs_revision = AWACS_SCREAMER ; - else - awacs_revision = rev ; - } - - dmasound.mach = machPMac; - - /* find out other bits & pieces from OF, these may be present - only on some models ... so be careful. - */ - - /* in the absence of a frame rates property we will use the defaults - */ - - if (info) { - const unsigned int *prop; - unsigned int l; - - sound_device_id = 0; - /* device ID appears post g3 b&w */ - prop = of_get_property(info, "device-id", NULL); - if (prop != 0) - sound_device_id = *prop; - - /* look for a property saying what sample rates - are available */ - - prop = of_get_property(info, "sample-rates", &l); - if (prop == 0) - prop = of_get_property(info, "output-frame-rates", &l); - - /* if it's there use it to set up frame rates */ - init_frame_rates(prop, l) ; - of_node_put(info); - info = NULL; - } - - if (awacs) - out_le32(&awacs->control, 0x11); /* set everything quiesent */ - - set_hw_byteswap(io) ; /* figure out if the h/w can do it */ - -#ifdef CONFIG_NVRAM - /* get default volume from nvram */ - vol = ((pmac_xpram_read( 8 ) & 7 ) << 1 ); -#else - vol = 0; -#endif - - /* set up tracking values */ - spk_vol = vol * 100 ; - spk_vol /= 7 ; /* get set value to a percentage */ - spk_vol |= (spk_vol << 8) ; /* equal left & right */ - line_vol = passthru_vol = spk_vol ; - - /* fill regs that are shared between AWACS & Burgundy */ - - awacs_reg[2] = vol + (vol << 6); - awacs_reg[4] = vol + (vol << 6); - awacs_reg[5] = vol + (vol << 6); /* screamer has loopthru vol control */ - awacs_reg[6] = 0; /* maybe should be vol << 3 for PCMCIA speaker */ - awacs_reg[7] = 0; - - awacs_reg[0] = MASK_MUX_CD; - awacs_reg[1] = MASK_LOOPTHRU; - - /* FIXME: Only machines with external SRS module need MASK_PAROUT */ - if (has_perch || sound_device_id == 0x5 - || /*sound_device_id == 0x8 ||*/ sound_device_id == 0xb) - awacs_reg[1] |= MASK_PAROUT0 | MASK_PAROUT1; - - switch (awacs_revision) { - case AWACS_TUMBLER: - tas_register_driver(&tas3001c_hooks); - tas_init(I2C_DRIVERID_TAS3001C, I2C_DRIVERNAME_TAS3001C); - tas_dmasound_init(); - tas_post_init(); - break ; - case AWACS_SNAPPER: - tas_register_driver(&tas3004_hooks); - tas_init(I2C_DRIVERID_TAS3004,I2C_DRIVERNAME_TAS3004); - tas_dmasound_init(); - tas_post_init(); - break; - case AWACS_DACA: - daca_init(); - break; - case AWACS_BURGUNDY: - awacs_burgundy_init(); - break ; - case AWACS_SCREAMER: - case AWACS_AWACS: - default: - load_awacs(); - break ; - } - - /* enable/set-up external modules - when we know how */ - - if (has_perch) - awacs_enable_amp(100 * 0x101); - - /* Reset dbdma channels */ - out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE|DEAD) << 16); - while (in_le32(&awacs_txdma->status) & RUN) - udelay(1); - out_le32(&awacs_rxdma->control, (RUN|PAUSE|FLUSH|WAKE|DEAD) << 16); - while (in_le32(&awacs_rxdma->status) & RUN) - udelay(1); - - /* Initialize beep stuff */ - if ((res=setup_beep())) - return res ; - -#ifdef CONFIG_PM - pmu_register_sleep_notifier(&awacs_sleep_notifier); -#endif /* CONFIG_PM */ - - /* Powerbooks have odd ways of enabling inputs such as - an expansion-bay CD or sound from an internal modem - or a PC-card modem. */ - if (is_pbook_3X00) { - /* - * Enable CD and PC-card sound inputs. - * This is done by reading from address - * f301a000, + 0x10 to enable the expansion-bay - * CD sound input, + 0x80 to enable the PC-card - * sound input. The 0x100 enables the SCSI bus - * terminator power. - */ - latch_base = ioremap (0xf301a000, 0x1000); - in_8(latch_base + 0x190); - - } else if (is_pbook_g3) { - struct device_node* mio; - macio_base = NULL; - for (mio = io->parent; mio; mio = mio->parent) { - if (strcmp(mio->name, "mac-io") == 0) { - struct resource r; - if (of_address_to_resource(mio, 0, &r) == 0) - macio_base = ioremap(r.start, 0x40); - break; - } - } - /* - * Enable CD sound input. - * The relevant bits for writing to this byte are 0x8f. - * I haven't found out what the 0x80 bit does. - * For the 0xf bits, writing 3 or 7 enables the CD - * input, any other value disables it. Values - * 1, 3, 5, 7 enable the microphone. Values 0, 2, - * 4, 6, 8 - f enable the input from the modem. - * -- paulus. - */ - if (macio_base) - out_8(macio_base + 0x37, 3); - } - - if (hw_can_byteswap) - dmasound.mach.hardware_afmts = (AFMT_S16_BE | AFMT_S16_LE) ; - else - dmasound.mach.hardware_afmts = AFMT_S16_BE ; - - /* shut out chips that do output only. - * may need to extend this to machines which have no inputs - even tho' - * they use screamer - IIRC one of the powerbooks is like this. - */ - - if (awacs_revision != AWACS_DACA) { - dmasound.mach.capabilities = DSP_CAP_DUPLEX ; - dmasound.mach.record = PMacRecord ; - } - - dmasound.mach.default_hard = def_hard ; - dmasound.mach.default_soft = def_soft ; - - switch (awacs_revision) { - case AWACS_BURGUNDY: - sprintf(awacs_name, "PowerMac Burgundy ") ; - break ; - case AWACS_DACA: - sprintf(awacs_name, "PowerMac DACA ") ; - break ; - case AWACS_TUMBLER: - sprintf(awacs_name, "PowerMac Tumbler ") ; - break ; - case AWACS_SNAPPER: - sprintf(awacs_name, "PowerMac Snapper ") ; - break ; - case AWACS_SCREAMER: - sprintf(awacs_name, "PowerMac Screamer ") ; - break ; - case AWACS_AWACS: - default: - sprintf(awacs_name, "PowerMac AWACS rev %d ", awacs_revision) ; - break ; - } - - /* - * XXX: we should handle errors here, but that would mean - * rewriting the whole init code. later.. - */ - input_register_device(awacs_beep_dev); - - of_node_put(io); - - return dmasound_init(); - -no_device: - of_node_put(info); - of_node_put(awacs_node); - of_node_put(i2s_node); - of_node_put(io); - return -ENODEV ; -} - -static void __exit dmasound_awacs_cleanup(void) -{ - input_unregister_device(awacs_beep_dev); - - switch (awacs_revision) { - case AWACS_TUMBLER: - case AWACS_SNAPPER: - tas_dmasound_cleanup(); - tas_cleanup(); - break ; - case AWACS_DACA: - daca_cleanup(); - break; - } - dmasound_deinit(); - - of_node_put(awacs_node); - of_node_put(i2s_node); -} - -MODULE_DESCRIPTION("PowerMac built-in audio driver."); -MODULE_LICENSE("GPL"); - -module_init(dmasound_awacs_init); -module_exit(dmasound_awacs_cleanup); diff --git a/sound/oss/dmasound/dmasound_core.c b/sound/oss/dmasound/dmasound_core.c index f4056a9c371..a003c0ea930 100644 --- a/sound/oss/dmasound/dmasound_core.c +++ b/sound/oss/dmasound/dmasound_core.c @@ -202,13 +202,6 @@ module_param(numWriteBufs, int, 0); static unsigned int writeBufSize = DEFAULT_BUFF_SIZE ; /* in bytes */ module_param(writeBufSize, int, 0); -#ifdef HAS_RECORD -static unsigned int numReadBufs = DEFAULT_N_BUFFERS; -module_param(numReadBufs, int, 0); -static unsigned int readBufSize = DEFAULT_BUFF_SIZE; /* in bytes */ -module_param(readBufSize, int, 0); -#endif - MODULE_LICENSE("GPL"); #ifdef MODULE @@ -403,10 +396,6 @@ static void mixer_init(void) struct sound_queue dmasound_write_sq; static void sq_reset_output(void) ; -#ifdef HAS_RECORD -struct sound_queue dmasound_read_sq; -static void sq_reset_input(void) ; -#endif static int sq_allocate_buffers(struct sound_queue *sq, int num, int size) { @@ -530,12 +519,6 @@ printk("dmasound_core: invalid frag count (user set %d)\n", sq->user_frags) ; sq->rear = -1; setup_func = dmasound.mach.write_sq_setup; } -#ifdef HAS_RECORD - else { - sq->rear = 0; - setup_func = dmasound.mach.read_sq_setup; - } -#endif if (setup_func) return setup_func(); return 0 ; @@ -672,13 +655,6 @@ static unsigned int sq_poll(struct file *file, struct poll_table_struct *wait) } if (file->f_mode & FMODE_WRITE ) poll_wait(file, &write_sq.action_queue, wait); -#ifdef HAS_RECORD - if (file->f_mode & FMODE_READ) - poll_wait(file, &read_sq.action_queue, wait); - if (file->f_mode & FMODE_READ) - if (read_sq.block_size - read_sq.rear_size > 0) - mask |= POLLIN | POLLRDNORM; -#endif if (file->f_mode & FMODE_WRITE) if (write_sq.count < write_sq.max_active || write_sq.block_size - write_sq.rear_size > 0) mask |= POLLOUT | POLLWRNORM; @@ -686,101 +662,6 @@ static unsigned int sq_poll(struct file *file, struct poll_table_struct *wait) } -#ifdef HAS_RECORD - /* - * Here is how the values are used for reading. - * The value 'active' simply indicates the DMA is running. This is done - * so the driver semantics are DMA starts when the first read is posted. - * The value 'front' indicates the buffer we should next send to the user. - * The value 'rear' indicates the buffer the DMA is currently filling. - * When 'front' == 'rear' the buffer "ring" is empty (we always have an - * empty available). The 'rear_size' is used to track partial offsets - * into the buffer we are currently returning to the user. - - * This level (> [1.5]) doesn't care what strategy the LL driver uses with - * DMA on over-run. It can leave it running (and keep active == 1) or it - * can kill it and set active == 0 in which case this routine will spot - * it and restart the DMA. - */ - -static ssize_t sq_read(struct file *file, char __user *dst, size_t uLeft, - loff_t *ppos) -{ - - ssize_t uRead, bLeft, bUsed, uUsed; - - if (uLeft == 0) - return 0; - - /* cater for the compatibility mode - record compiled in but no LL */ - if (dmasound.mach.record == NULL) - return -EINVAL ; - - /* see comment in sq_write() - */ - - if( shared_resources_initialised == 0) { - dmasound.mach.init() ; - shared_resources_initialised = 1 ; - } - - /* set up the sq if it is not already done. see comments in sq_write(). - */ - - if (read_sq.locked == 0) { - if ((uRead = sq_setup(&read_sq)) < 0) - return uRead ; - } - - uRead = 0; - - /* Move what the user requests, depending upon other options. - */ - while (uLeft > 0) { - - /* we happened to get behind and the LL driver killed DMA - then we should set it going again. This also sets it - going the first time through. - */ - if ( !read_sq.active ) - dmasound.mach.record(); - - /* When front == rear, the DMA is not done yet. - */ - while (read_sq.front == read_sq.rear) { - if (read_sq.open_mode & O_NONBLOCK) { - return uRead > 0 ? uRead : -EAGAIN; - } - SLEEP(read_sq.action_queue); - if (signal_pending(current)) - return uRead > 0 ? uRead : -EINTR; - } - - /* The amount we move is either what is left in the - * current buffer or what the user wants. - */ - bLeft = read_sq.block_size - read_sq.rear_size; - bUsed = read_sq.rear_size; - uUsed = sound_copy_translate(dmasound.trans_read, dst, uLeft, - read_sq.buffers[read_sq.front], - &bUsed, bLeft); - if (uUsed <= 0) - return uUsed; - dst += uUsed; - uRead += uUsed; - uLeft -= uUsed; - read_sq.rear_size += bUsed; - if (read_sq.rear_size >= read_sq.block_size) { - read_sq.rear_size = 0; - read_sq.front++; - if (read_sq.front >= read_sq.max_active) - read_sq.front = 0; - } - } - return uRead; -} -#endif /* HAS_RECORD */ - static inline void sq_init_waitqueue(struct sound_queue *sq) { init_waitqueue_head(&sq->action_queue); @@ -854,23 +735,6 @@ static int sq_open2(struct sound_queue *sq, struct file *file, mode_t mode, #define write_sq_open(file) \ sq_open2(&write_sq, file, FMODE_WRITE, numWriteBufs, writeBufSize ) -#ifdef HAS_RECORD -#define read_sq_init_waitqueue() sq_init_waitqueue(&read_sq) -#if 0 /* blocking open() */ -#define read_sq_wake_up(file) sq_wake_up(&read_sq, file, FMODE_READ) -#endif -#define read_sq_release_buffers() sq_release_buffers(&read_sq) -#define read_sq_open(file) \ - sq_open2(&read_sq, file, FMODE_READ, numReadBufs, readBufSize ) -#else -#define read_sq_init_waitqueue() do {} while (0) -#if 0 /* blocking open() */ -#define read_sq_wake_up(file) do {} while (0) -#endif -#define read_sq_release_buffers() do {} while (0) -#define sq_reset_input() do {} while (0) -#endif - static int sq_open(struct inode *inode, struct file *file) { int rc; @@ -881,25 +745,11 @@ static int sq_open(struct inode *inode, struct file *file) rc = write_sq_open(file); /* checks the f_mode */ if (rc) goto out; -#ifdef HAS_RECORD - if (dmasound.mach.record) { - rc = read_sq_open(file); /* checks the f_mode */ - if (rc) - goto out; - } else { /* no record function installed; in compat mode */ - if (file->f_mode & FMODE_READ) { - /* TODO: if O_RDWR, release any resources grabbed by write part */ - rc = -ENXIO; - goto out; - } - } -#else /* !HAS_RECORD */ if (file->f_mode & FMODE_READ) { /* TODO: if O_RDWR, release any resources grabbed by write part */ rc = -ENXIO ; /* I think this is what is required by open(2) */ goto out; } -#endif /* HAS_RECORD */ if (dmasound.mach.sq_open) dmasound.mach.sq_open(file->f_mode); @@ -956,43 +806,9 @@ static void sq_reset_output(void) write_sq.user_frag_size = 0 ; } -#ifdef HAS_RECORD - -static void sq_reset_input(void) -{ - if (dmasound.mach.record && read_sq.active) { - if (dmasound.mach.abort_read) { /* this routine must really be present */ - read_sq.syncing = 1 ; - /* this can use the read_sq.sync_queue to sleep if - necessary - it should not return until DMA - is really stopped - because we might deallocate - the buffers as the next action... - */ - dmasound.mach.abort_read() ; - } else { - printk(KERN_ERR - "dmasound_core: %s has no abort_read()!! all bets are off\n", - dmasound.mach.name) ; - } - } - read_sq.syncing = - read_sq.active = - read_sq.front = - read_sq.count = - read_sq.rear = 0 ; - - /* OK - we can unlock the parameters and fragment settings */ - read_sq.locked = 0 ; - read_sq.user_frags = 0 ; - read_sq.user_frag_size = 0 ; -} - -#endif - static void sq_reset(void) { sq_reset_output() ; - sq_reset_input() ; /* we could consider resetting the shared_resources_owner here... but I think it is probably still rather non-obvious to application writer */ @@ -1038,17 +854,6 @@ static int sq_release(struct inode *inode, struct file *file) lock_kernel(); -#ifdef HAS_RECORD - /* probably best to do the read side first - so that time taken to do it - overlaps with playing any remaining output samples. - */ - if (file->f_mode & FMODE_READ) { - sq_reset_input() ; /* make sure dma is stopped and all is quiet */ - read_sq_release_buffers(); - read_sq.busy = 0; - } -#endif - if (file->f_mode & FMODE_WRITE) { if (write_sq.busy) rc = sq_fsync(file, file->f_path.dentry); @@ -1105,11 +910,6 @@ static int shared_resources_are_mine(mode_t md) static int queues_are_quiescent(void) { -#ifdef HAS_RECORD - if (dmasound.mach.record) - if (read_sq.locked) - return 0 ; -#endif if (write_sq.locked) return 0 ; return 1 ; @@ -1185,13 +985,6 @@ static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd, the read_sq ones. */ size = 0 ; -#ifdef HAS_RECORD - if (dmasound.mach.record && (file->f_mode & FMODE_READ)) { - if ( !read_sq.locked ) - sq_setup(&read_sq) ; /* set params */ - size = read_sq.user_frag_size ; - } -#endif if (file->f_mode & FMODE_WRITE) { if ( !write_sq.locked ) sq_setup(&write_sq) ; @@ -1214,8 +1007,6 @@ static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd, everything - read, however, is killed imediately. */ result = 0 ; - if ((file->f_mode & FMODE_READ) && dmasound.mach.record) - sq_reset_input() ; if (file->f_mode & FMODE_WRITE) { result = sq_fsync(file, file->f_path.dentry); sq_reset_output() ; @@ -1294,13 +1085,6 @@ static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd, result = 0 ; nbufs = (data >> 16) & 0x7fff ; /* 0x7fff is 'use maximum' */ size = data & 0xffff; -#ifdef HAS_RECORD - if ((file->f_mode & FMODE_READ) && dmasound.mach.record) { - result = set_queue_frags(&read_sq, nbufs, size) ; - if (result) - return result ; - } -#endif if (file->f_mode & FMODE_WRITE) { result = set_queue_frags(&write_sq, nbufs, size) ; if (result) @@ -1348,20 +1132,6 @@ static const struct file_operations sq_fops = .release = sq_release, }; -#ifdef HAS_RECORD -static const struct file_operations sq_fops_record = -{ - .owner = THIS_MODULE, - .llseek = no_llseek, - .write = sq_write, - .poll = sq_poll, - .ioctl = sq_ioctl, - .open = sq_open, - .release = sq_release, - .read = sq_read, -}; -#endif - static int sq_init(void) { const struct file_operations *fops = &sq_fops; @@ -1369,10 +1139,6 @@ static int sq_init(void) int sq_unit; #endif -#ifdef HAS_RECORD - if (dmasound.mach.record) - fops = &sq_fops_record; -#endif sq_unit = register_sound_dsp(fops, -1); if (sq_unit < 0) { printk(KERN_ERR "dmasound_core: couldn't register fops\n") ; @@ -1380,7 +1146,6 @@ static int sq_init(void) } write_sq_init_waitqueue(); - read_sq_init_waitqueue(); /* These parameters will be restored for every clean open() * in the case of multiple open()s (e.g. dsp0 & dsp1) they @@ -1406,11 +1171,7 @@ static int sq_init(void) driver. */ -#ifdef HAS_RECORD -#define STAT_BUFF_LEN 1024 -#else #define STAT_BUFF_LEN 768 -#endif /* this is how much space we will allow the low-level driver to use in the stat buffer. Currently, 2 * (80 character line + <NL>). @@ -1518,11 +1279,6 @@ static int state_open(struct inode *inode, struct file *file) len += sprintf(buffer+len,"Allocated:%8s%6s\n","Buffers","Size") ; len += sprintf(buffer+len,"%9s:%8d%6d\n", "write", write_sq.numBufs, write_sq.bufSize) ; -#ifdef HAS_RECORD - if (dmasound.mach.record) - len += sprintf(buffer+len,"%9s:%8d%6d\n", - "read", read_sq.numBufs, read_sq.bufSize) ; -#endif len += sprintf(buffer+len, "Current : MaxFrg FragSiz MaxAct Frnt Rear " "Cnt RrSize A B S L xruns\n") ; @@ -1531,14 +1287,6 @@ static int state_open(struct inode *inode, struct file *file) write_sq.max_active, write_sq.front, write_sq.rear, write_sq.count, write_sq.rear_size, write_sq.active, write_sq.busy, write_sq.syncing, write_sq.locked, write_sq.xruns) ; -#ifdef HAS_RECORD - if (dmasound.mach.record) - len += sprintf(buffer+len,"%9s:%7d%8d%7d%5d%5d%4d%7d%2d%2d%2d%2d%7d\n", - "read", read_sq.max_count, read_sq.block_size, - read_sq.max_active, read_sq.front, read_sq.rear, - read_sq.count, read_sq.rear_size, read_sq.active, - read_sq.busy, read_sq.syncing, read_sq.locked, read_sq.xruns) ; -#endif #ifdef DEBUG_DMASOUND printk("dmasound: stat buffer used %d bytes\n", len) ; #endif @@ -1638,13 +1386,6 @@ int dmasound_init(void) (dmasound.mach.version >> 8), (dmasound.mach.version & 0xff)) ; printk(KERN_INFO "Write will use %4d fragments of %7d bytes as default\n", numWriteBufs, writeBufSize) ; -#ifdef HAS_RECORD - if (dmasound.mach.record) - printk(KERN_INFO - "Read will use %4d fragments of %7d bytes as default\n", - numReadBufs, readBufSize) ; -#endif - return 0; } @@ -1659,7 +1400,6 @@ void dmasound_deinit(void) } write_sq_release_buffers(); - read_sq_release_buffers(); if (mixer_unit >= 0) unregister_sound_mixer(mixer_unit); @@ -1684,36 +1424,12 @@ static int dmasound_setup(char *str) */ switch (ints[0]) { -#ifdef HAS_RECORD - case 5: - if ((ints[5] < 0) || (ints[5] > MAX_CATCH_RADIUS)) - printk("dmasound_setup: invalid catch radius, using default = %d\n", catchRadius); - else - catchRadius = ints[5]; - /* fall through */ - case 4: - if (ints[4] < MIN_BUFFERS) - printk("dmasound_setup: invalid number of read buffers, using default = %d\n", - numReadBufs); - else - numReadBufs = ints[4]; - /* fall through */ - case 3: - if ((size = ints[3]) < 256) /* check for small buffer specs */ - size <<= 10 ; - if (size < MIN_BUFSIZE || size > MAX_BUFSIZE) - printk("dmasound_setup: invalid read buffer size, using default = %d\n", readBufSize); - else - readBufSize = size; - /* fall through */ -#else case 3: if ((ints[3] < 0) || (ints[3] > MAX_CATCH_RADIUS)) printk("dmasound_setup: invalid catch radius, using default = %d\n", catchRadius); else catchRadius = ints[3]; /* fall through */ -#endif case 2: if (ints[1] < MIN_BUFFERS) printk("dmasound_setup: invalid number of buffers, using default = %d\n", numWriteBufs); @@ -1830,9 +1546,6 @@ EXPORT_SYMBOL(dmasound_init); EXPORT_SYMBOL(dmasound_deinit); #endif EXPORT_SYMBOL(dmasound_write_sq); -#ifdef HAS_RECORD -EXPORT_SYMBOL(dmasound_read_sq); -#endif EXPORT_SYMBOL(dmasound_catchRadius); #ifdef HAS_8BIT_TABLES EXPORT_SYMBOL(dmasound_ulaw2dma8); diff --git a/sound/oss/dmasound/tas3001c.c b/sound/oss/dmasound/tas3001c.c deleted file mode 100644 index 4b7dbdd2a43..00000000000 --- a/sound/oss/dmasound/tas3001c.c +++ /dev/null @@ -1,849 +0,0 @@ -/* - * Driver for the i2c/i2s based TA3004 sound chip used - * on some Apple hardware. Also known as "snapper". - * - * Tobias Sargeant <tobias.sargeant@bigpond.com> - * Based upon, tas3001c.c by Christopher C. Chimelis <chris@debian.org>: - * - * TODO: - * ----- - * * Enable control over input line 2 (is this connected?) - * * Implement sleep support (at least mute everything and - * * set gains to minimum during sleep) - * * Look into some of Darwin's tweaks regarding the mute - * * lines (delays & different behaviour on some HW) - * - */ - -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/proc_fs.h> -#include <linux/ioport.h> -#include <linux/sysctl.h> -#include <linux/types.h> -#include <linux/i2c.h> -#include <linux/init.h> -#include <linux/soundcard.h> -#include <linux/workqueue.h> -#include <asm/uaccess.h> -#include <asm/errno.h> -#include <asm/io.h> -#include <asm/prom.h> - -#include "dmasound.h" -#include "tas_common.h" -#include "tas3001c.h" - -#include "tas_ioctl.h" - -#define TAS3001C_BIQUAD_FILTER_COUNT 6 -#define TAS3001C_BIQUAD_CHANNEL_COUNT 2 - -#define VOL_DEFAULT (100 * 4 / 5) -#define INPUT_DEFAULT (100 * 4 / 5) -#define BASS_DEFAULT (100 / 2) -#define TREBLE_DEFAULT (100 / 2) - -struct tas3001c_data_t { - struct tas_data_t super; - int device_id; - int output_id; - int speaker_id; - struct tas_drce_t drce_state; - struct work_struct change; -}; - - -static const union tas_biquad_t -tas3001c_eq_unity={ - .buf = { 0x100000, 0x000000, 0x000000, 0x000000, 0x000000 } -}; - - -static inline unsigned char db_to_regval(short db) { - int r=0; - - r=(db+0x59a0) / 0x60; - - if (r < 0x91) return 0x91; - if (r > 0xef) return 0xef; - return r; -} - -static inline short quantize_db(short db) { - return db_to_regval(db) * 0x60 - 0x59a0; -} - - -static inline int -register_width(enum tas3001c_reg_t r) -{ - switch(r) { - case TAS3001C_REG_MCR: - case TAS3001C_REG_TREBLE: - case TAS3001C_REG_BASS: - return 1; - - case TAS3001C_REG_DRC: - return 2; - - case TAS3001C_REG_MIXER1: - case TAS3001C_REG_MIXER2: - return 3; - - case TAS3001C_REG_VOLUME: - return 6; - - case TAS3001C_REG_LEFT_BIQUAD0: - case TAS3001C_REG_LEFT_BIQUAD1: - case TAS3001C_REG_LEFT_BIQUAD2: - case TAS3001C_REG_LEFT_BIQUAD3: - case TAS3001C_REG_LEFT_BIQUAD4: - case TAS3001C_REG_LEFT_BIQUAD5: - case TAS3001C_REG_LEFT_BIQUAD6: - - case TAS3001C_REG_RIGHT_BIQUAD0: - case TAS3001C_REG_RIGHT_BIQUAD1: - case TAS3001C_REG_RIGHT_BIQUAD2: - case TAS3001C_REG_RIGHT_BIQUAD3: - case TAS3001C_REG_RIGHT_BIQUAD4: - case TAS3001C_REG_RIGHT_BIQUAD5: - case TAS3001C_REG_RIGHT_BIQUAD6: - return 15; - - default: - return 0; - } -} - -static int -tas3001c_write_register( struct tas3001c_data_t *self, - enum tas3001c_reg_t reg_num, - char *data, - uint write_mode) -{ - if (reg_num==TAS3001C_REG_MCR || - reg_num==TAS3001C_REG_BASS || - reg_num==TAS3001C_REG_TREBLE) { - return tas_write_byte_register(&self->super, - (uint)reg_num, - *data, - write_mode); - } else { - return tas_write_register(&self->super, - (uint)reg_num, - register_width(reg_num), - data, - write_mode); - } -} - -static int -tas3001c_sync_register( struct tas3001c_data_t *self, - enum tas3001c_reg_t reg_num) -{ - if (reg_num==TAS3001C_REG_MCR || - reg_num==TAS3001C_REG_BASS || - reg_num==TAS3001C_REG_TREBLE) { - return tas_sync_byte_register(&self->super, - (uint)reg_num, - register_width(reg_num)); - } else { - return tas_sync_register(&self->super, - (uint)reg_num, - register_width(reg_num)); - } -} - -static int -tas3001c_read_register( struct tas3001c_data_t *self, - enum tas3001c_reg_t reg_num, - char *data, - uint write_mode) -{ - return tas_read_register(&self->super, - (uint)reg_num, - register_width(reg_num), - data); -} - -static inline int -tas3001c_fast_load(struct tas3001c_data_t *self, int fast) -{ - if (fast) - self->super.shadow[TAS3001C_REG_MCR][0] |= 0x80; - else - self->super.shadow[TAS3001C_REG_MCR][0] &= 0x7f; - return tas3001c_sync_register(self,TAS3001C_REG_MCR); -} - -static uint -tas3001c_supported_mixers(struct tas3001c_data_t *self) -{ - return SOUND_MASK_VOLUME | - SOUND_MASK_PCM | - SOUND_MASK_ALTPCM | - SOUND_MASK_TREBLE | - SOUND_MASK_BASS; -} - -static int -tas3001c_mixer_is_stereo(struct tas3001c_data_t *self,int mixer) -{ - switch(mixer) { - case SOUND_MIXER_VOLUME: - return 1; - default: - return 0; - } -} - -static uint -tas3001c_stereo_mixers(struct tas3001c_data_t *self) -{ - uint r=tas3001c_supported_mixers(self); - uint i; - - for (i=1; i<SOUND_MIXER_NRDEVICES; i++) - if (r&(1<<i) && !tas3001c_mixer_is_stereo(self,i)) - r &= ~(1<<i); - return r; -} - -static int -tas3001c_get_mixer_level(struct tas3001c_data_t *self,int mixer,uint *level) -{ - if (!self) - return -1; - - *level=self->super.mixer[mixer]; - - return 0; -} - -static int -tas3001c_set_mixer_level(struct tas3001c_data_t *self,int mixer,uint level) -{ - int rc; - tas_shadow_t *shadow; - - uint temp; - uint offset=0; - - if (!self) - return -1; - - shadow=self->super.shadow; - - if (!tas3001c_mixer_is_stereo(self,mixer)) - level = tas_mono_to_stereo(level); - - switch(mixer) { - case SOUND_MIXER_VOLUME: - temp = tas3001c_gain.master[level&0xff]; - shadow[TAS3001C_REG_VOLUME][0] = (temp >> 16) & 0xff; - shadow[TAS3001C_REG_VOLUME][1] = (temp >> 8) & 0xff; - shadow[TAS3001C_REG_VOLUME][2] = (temp >> 0) & 0xff; - temp = tas3001c_gain.master[(level>>8)&0xff]; - shadow[TAS3001C_REG_VOLUME][3] = (temp >> 16) & 0xff; - shadow[TAS3001C_REG_VOLUME][4] = (temp >> 8) & 0xff; - shadow[TAS3001C_REG_VOLUME][5] = (temp >> 0) & 0xff; - rc = tas3001c_sync_register(self,TAS3001C_REG_VOLUME); - break; - case SOUND_MIXER_ALTPCM: - /* tas3001c_fast_load(self, 1); */ - level = tas_mono_to_stereo(level); - temp = tas3001c_gain.mixer[level&0xff]; - shadow[TAS3001C_REG_MIXER2][offset+0] = (temp >> 16) & 0xff; - shadow[TAS3001C_REG_MIXER2][offset+1] = (temp >> 8) & 0xff; - shadow[TAS3001C_REG_MIXER2][offset+2] = (temp >> 0) & 0xff; - rc = tas3001c_sync_register(self,TAS3001C_REG_MIXER2); - /* tas3001c_fast_load(self, 0); */ - break; - case SOUND_MIXER_PCM: - /* tas3001c_fast_load(self, 1); */ - level = tas_mono_to_stereo(level); - temp = tas3001c_gain.mixer[level&0xff]; - shadow[TAS3001C_REG_MIXER1][offset+0] = (temp >> 16) & 0xff; - shadow[TAS3001C_REG_MIXER1][offset+1] = (temp >> 8) & 0xff; - shadow[TAS3001C_REG_MIXER1][offset+2] = (temp >> 0) & 0xff; - rc = tas3001c_sync_register(self,TAS3001C_REG_MIXER1); - /* tas3001c_fast_load(self, 0); */ - break; - case SOUND_MIXER_TREBLE: - temp = tas3001c_gain.treble[level&0xff]; - shadow[TAS3001C_REG_TREBLE][0]=temp&0xff; - rc = tas3001c_sync_register(self,TAS3001C_REG_TREBLE); - break; - case SOUND_MIXER_BASS: - temp = tas3001c_gain.bass[level&0xff]; - shadow[TAS3001C_REG_BASS][0]=temp&0xff; - rc = tas3001c_sync_register(self,TAS3001C_REG_BASS); - break; - default: - rc = -1; - break; - } - if (rc < 0) - return rc; - self->super.mixer[mixer]=level; - return 0; -} - -static int -tas3001c_leave_sleep(struct tas3001c_data_t *self) -{ - unsigned char mcr = (1<<6)+(2<<4)+(2<<2); - - if (!self) - return -1; - - /* Make sure something answers on the i2c bus */ - if (tas3001c_write_register(self, TAS3001C_REG_MCR, &mcr, - WRITE_NORMAL|FORCE_WRITE) < 0) - return -1; - - tas3001c_fast_load(self, 1); - - (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD0); - (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD1); - (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD2); - (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD3); - (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD4); - (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD5); - - (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD0); - (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD1); - (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD2); - (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD3); - (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD4); - (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD5); - - tas3001c_fast_load(self, 0); - - (void)tas3001c_sync_register(self,TAS3001C_REG_BASS); - (void)tas3001c_sync_register(self,TAS3001C_REG_TREBLE); - (void)tas3001c_sync_register(self,TAS3001C_REG_MIXER1); - (void)tas3001c_sync_register(self,TAS3001C_REG_MIXER2); - (void)tas3001c_sync_register(self,TAS3001C_REG_VOLUME); - - return 0; -} - -static int -tas3001c_enter_sleep(struct tas3001c_data_t *self) -{ - /* Stub for now, but I have the details on low-power mode */ - if (!self) - return -1; - return 0; -} - -static int -tas3001c_sync_biquad( struct tas3001c_data_t *self, - u_int channel, - u_int filter) -{ - enum tas3001c_reg_t reg; - - if (channel >= TAS3001C_BIQUAD_CHANNEL_COUNT || - filter >= TAS3001C_BIQUAD_FILTER_COUNT) return -EINVAL; - - reg=( channel ? TAS3001C_REG_RIGHT_BIQUAD0 : TAS3001C_REG_LEFT_BIQUAD0 ) + filter; - - return tas3001c_sync_register(self,reg); -} - -static int -tas3001c_write_biquad_shadow( struct tas3001c_data_t *self, - u_int channel, - u_int filter, - const union tas_biquad_t *biquad) -{ - tas_shadow_t *shadow=self->super.shadow; - enum tas3001c_reg_t reg; - - if (channel >= TAS3001C_BIQUAD_CHANNEL_COUNT || - filter >= TAS3001C_BIQUAD_FILTER_COUNT) return -EINVAL; - - reg=( channel ? TAS3001C_REG_RIGHT_BIQUAD0 : TAS3001C_REG_LEFT_BIQUAD0 ) + filter; - - SET_4_20(shadow[reg], 0,biquad->coeff.b0); - SET_4_20(shadow[reg], 3,biquad->coeff.b1); - SET_4_20(shadow[reg], 6,biquad->coeff.b2); - SET_4_20(shadow[reg], 9,biquad->coeff.a1); - SET_4_20(shadow[reg],12,biquad->coeff.a2); - - return 0; -} - -static int -tas3001c_write_biquad( struct tas3001c_data_t *self, - u_int channel, - u_int filter, - const union tas_biquad_t *biquad) -{ - int rc; - - rc=tas3001c_write_biquad_shadow(self, channel, filter, biquad); - if (rc < 0) return rc; - - return tas3001c_sync_biquad(self, channel, filter); -} - -static int -tas3001c_write_biquad_list( struct tas3001c_data_t *self, - u_int filter_count, - u_int flags, - struct tas_biquad_ctrl_t *biquads) -{ - int i; - int rc; - - if (flags & TAS_BIQUAD_FAST_LOAD) tas3001c_fast_load(self,1); - - for (i=0; i<filter_count; i++) { - rc=tas3001c_write_biquad(self, - biquads[i].channel, - biquads[i].filter, - &biquads[i].data); - if (rc < 0) break; - } - - if (flags & TAS_BIQUAD_FAST_LOAD) { - tas3001c_fast_load(self,0); - - (void)tas3001c_sync_register(self,TAS3001C_REG_BASS); - (void)tas3001c_sync_register(self,TAS3001C_REG_TREBLE); - (void)tas3001c_sync_register(self,TAS3001C_REG_MIXER1); - (void)tas3001c_sync_register(self,TAS3001C_REG_MIXER2); - (void)tas3001c_sync_register(self,TAS3001C_REG_VOLUME); - } - - return rc; -} - -static int -tas3001c_read_biquad( struct tas3001c_data_t *self, - u_int channel, - u_int filter, - union tas_biquad_t *biquad) -{ - tas_shadow_t *shadow=self->super.shadow; - enum tas3001c_reg_t reg; - - if (channel >= TAS3001C_BIQUAD_CHANNEL_COUNT || - filter >= TAS3001C_BIQUAD_FILTER_COUNT) return -EINVAL; - - reg=( channel ? TAS3001C_REG_RIGHT_BIQUAD0 : TAS3001C_REG_LEFT_BIQUAD0 ) + filter; - - biquad->coeff.b0=GET_4_20(shadow[reg], 0); - biquad->coeff.b1=GET_4_20(shadow[reg], 3); - biquad->coeff.b2=GET_4_20(shadow[reg], 6); - biquad->coeff.a1=GET_4_20(shadow[reg], 9); - biquad->coeff.a2=GET_4_20(shadow[reg],12); - - return 0; -} - -static int -tas3001c_eq_rw( struct tas3001c_data_t *self, - u_int cmd, - u_long arg) -{ - int rc; - struct tas_biquad_ctrl_t biquad; - void __user *argp = (void __user *)arg; - - if (copy_from_user(&biquad, argp, sizeof(struct tas_biquad_ctrl_t))) { - return -EFAULT; - } - - if (cmd & SIOC_IN) { - rc=tas3001c_write_biquad(self, biquad.channel, biquad.filter, &biquad.data); - if (rc != 0) return rc; - } - - if (cmd & SIOC_OUT) { - rc=tas3001c_read_biquad(self, biquad.channel, biquad.filter, &biquad.data); - if (rc != 0) return rc; - - if (copy_to_user(argp, &biquad, sizeof(struct tas_biquad_ctrl_t))) { - return -EFAULT; - } - - } - return 0; -} - -static int -tas3001c_eq_list_rw( struct tas3001c_data_t *self, - u_int cmd, - u_long arg) -{ - int rc; - int filter_count; - int flags; - int i,j; - char sync_required[2][6]; - struct tas_biquad_ctrl_t biquad; - struct tas_biquad_ctrl_list_t __user *argp = (void __user *)arg; - - memset(sync_required,0,sizeof(sync_required)); - - if (copy_from_user(&filter_count, &argp->filter_count, sizeof(int))) - return -EFAULT; - - if (copy_from_user(&flags, &argp->flags, sizeof(int))) - return -EFAULT; - - if (cmd & SIOC_IN) { - } - - for (i=0; i < filter_count; i++) { - if (copy_from_user(&biquad, &argp->biquads[i], - sizeof(struct tas_biquad_ctrl_t))) { - return -EFAULT; - } - - if (cmd & SIOC_IN) { - sync_required[biquad.channel][biquad.filter]=1; - rc=tas3001c_write_biquad_shadow(self, biquad.channel, biquad.filter, &biquad.data); - if (rc != 0) return rc; - } - - if (cmd & SIOC_OUT) { - rc=tas3001c_read_biquad(self, biquad.channel, biquad.filter, &biquad.data); - if (rc != 0) return rc; - - if (copy_to_user(&argp->biquads[i], &biquad, - sizeof(struct tas_biquad_ctrl_t))) { - return -EFAULT; - } - } - } - - if (cmd & SIOC_IN) { - if (flags & TAS_BIQUAD_FAST_LOAD) tas3001c_fast_load(self,1); - for (i=0; i<2; i++) { - for (j=0; j<6; j++) { - if (sync_required[i][j]) { - rc=tas3001c_sync_biquad(self, i, j); - if (rc < 0) return rc; - } - } - } - if (flags & TAS_BIQUAD_FAST_LOAD) { - tas3001c_fast_load(self,0); - /* now we need to set up the mixers again, - because leaving fast mode resets them. */ - (void)tas3001c_sync_register(self,TAS3001C_REG_BASS); - (void)tas3001c_sync_register(self,TAS3001C_REG_TREBLE); - (void)tas3001c_sync_register(self,TAS3001C_REG_MIXER1); - (void)tas3001c_sync_register(self,TAS3001C_REG_MIXER2); - (void)tas3001c_sync_register(self,TAS3001C_REG_VOLUME); - } - } - - return 0; -} - -static int -tas3001c_update_drce( struct tas3001c_data_t *self, - int flags, - struct tas_drce_t *drce) -{ - tas_shadow_t *shadow; - shadow=self->super.shadow; - - shadow[TAS3001C_REG_DRC][1] = 0xc1; - - if (flags & TAS_DRCE_THRESHOLD) { - self->drce_state.threshold=quantize_db(drce->threshold); - shadow[TAS3001C_REG_DRC][2] = db_to_regval(self->drce_state.threshold); - } - - if (flags & TAS_DRCE_ENABLE) { - self->drce_state.enable = drce->enable; - } - - if (!self->drce_state.enable) { - shadow[TAS3001C_REG_DRC][0] = 0xf0; - } - -#ifdef DEBUG_DRCE - printk("DRCE IOCTL: set [ ENABLE:%x THRESH:%x\n", - self->drce_state.enable, - self->drce_state.threshold); - - printk("DRCE IOCTL: reg [ %02x %02x ]\n", - (unsigned char)shadow[TAS3001C_REG_DRC][0], - (unsigned char)shadow[TAS3001C_REG_DRC][1]); -#endif - - return tas3001c_sync_register(self, TAS3001C_REG_DRC); -} - -static int -tas3001c_drce_rw( struct tas3001c_data_t *self, - u_int cmd, - u_long arg) -{ - int rc; - struct tas_drce_ctrl_t drce_ctrl; - void __user *argp = (void __user *)arg; - - if (copy_from_user(&drce_ctrl, argp, sizeof(struct tas_drce_ctrl_t))) - return -EFAULT; - -#ifdef DEBUG_DRCE - printk("DRCE IOCTL: input [ FLAGS:%x ENABLE:%x THRESH:%x\n", - drce_ctrl.flags, - drce_ctrl.data.enable, - drce_ctrl.data.threshold); -#endif - - if (cmd & SIOC_IN) { - rc = tas3001c_update_drce(self, drce_ctrl.flags, &drce_ctrl.data); - if (rc < 0) - return rc; - } - - if (cmd & SIOC_OUT) { - if (drce_ctrl.flags & TAS_DRCE_ENABLE) - drce_ctrl.data.enable = self->drce_state.enable; - - if (drce_ctrl.flags & TAS_DRCE_THRESHOLD) - drce_ctrl.data.threshold = self->drce_state.threshold; - - if (copy_to_user(argp, &drce_ctrl, - sizeof(struct tas_drce_ctrl_t))) { - return -EFAULT; - } - } - - return 0; -} - -static void -tas3001c_update_device_parameters(struct tas3001c_data_t *self) -{ - int i,j; - - if (!self) return; - - if (self->output_id == TAS_OUTPUT_HEADPHONES) { - tas3001c_fast_load(self, 1); - - for (i=0; i<TAS3001C_BIQUAD_CHANNEL_COUNT; i++) { - for (j=0; j<TAS3001C_BIQUAD_FILTER_COUNT; j++) { - tas3001c_write_biquad(self, i, j, &tas3001c_eq_unity); - } - } - - tas3001c_fast_load(self, 0); - - (void)tas3001c_sync_register(self,TAS3001C_REG_BASS); - (void)tas3001c_sync_register(self,TAS3001C_REG_TREBLE); - (void)tas3001c_sync_register(self,TAS3001C_REG_MIXER1); - (void)tas3001c_sync_register(self,TAS3001C_REG_MIXER2); - (void)tas3001c_sync_register(self,TAS3001C_REG_VOLUME); - - return; - } - - for (i=0; tas3001c_eq_prefs[i]; i++) { - struct tas_eq_pref_t *eq = tas3001c_eq_prefs[i]; - - if (eq->device_id == self->device_id && - (eq->output_id == 0 || eq->output_id == self->output_id) && - (eq->speaker_id == 0 || eq->speaker_id == self->speaker_id)) { - - tas3001c_update_drce(self, TAS_DRCE_ALL, eq->drce); - tas3001c_write_biquad_list(self, eq->filter_count, TAS_BIQUAD_FAST_LOAD, eq->biquads); - - break; - } - } -} - -static void -tas3001c_device_change_handler(struct work_struct *work) -{ - struct tas3001c_data_t *self; - self = container_of(work, struct tas3001c_data_t, change); - tas3001c_update_device_parameters(self); -} - -static int -tas3001c_output_device_change( struct tas3001c_data_t *self, - int device_id, - int output_id, - int speaker_id) -{ - self->device_id=device_id; - self->output_id=output_id; - self->speaker_id=speaker_id; - - schedule_work(&self->change); - return 0; -} - -static int -tas3001c_device_ioctl( struct tas3001c_data_t *self, - u_int cmd, - u_long arg) -{ - uint __user *argp = (void __user *)arg; - switch (cmd) { - case TAS_READ_EQ: - case TAS_WRITE_EQ: - return tas3001c_eq_rw(self, cmd, arg); - - case TAS_READ_EQ_LIST: - case TAS_WRITE_EQ_LIST: - return tas3001c_eq_list_rw(self, cmd, arg); - - case TAS_READ_EQ_FILTER_COUNT: - put_user(TAS3001C_BIQUAD_FILTER_COUNT, argp); - return 0; - - case TAS_READ_EQ_CHANNEL_COUNT: - put_user(TAS3001C_BIQUAD_CHANNEL_COUNT, argp); - return 0; - - case TAS_READ_DRCE: - case TAS_WRITE_DRCE: - return tas3001c_drce_rw(self, cmd, arg); - - case TAS_READ_DRCE_CAPS: - put_user(TAS_DRCE_ENABLE | TAS_DRCE_THRESHOLD, argp); - return 0; - - case TAS_READ_DRCE_MIN: - case TAS_READ_DRCE_MAX: { - struct tas_drce_ctrl_t drce_ctrl; - - if (copy_from_user(&drce_ctrl, argp, - sizeof(struct tas_drce_ctrl_t))) { - return -EFAULT; - } - - if (drce_ctrl.flags & TAS_DRCE_THRESHOLD) { - if (cmd == TAS_READ_DRCE_MIN) { - drce_ctrl.data.threshold=-36<<8; - } else { - drce_ctrl.data.threshold=-6<<8; - } - } - - if (copy_to_user(argp, &drce_ctrl, - sizeof(struct tas_drce_ctrl_t))) { - return -EFAULT; - } - } - } - - return -EINVAL; -} - -static int -tas3001c_init_mixer(struct tas3001c_data_t *self) -{ - unsigned char mcr = (1<<6)+(2<<4)+(2<<2); - - /* Make sure something answers on the i2c bus */ - if (tas3001c_write_register(self, TAS3001C_REG_MCR, &mcr, - WRITE_NORMAL|FORCE_WRITE) < 0) - return -1; - - tas3001c_fast_load(self, 1); - - (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD0); - (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD1); - (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD2); - (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD3); - (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD4); - (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD5); - (void)tas3001c_sync_register(self,TAS3001C_REG_RIGHT_BIQUAD6); - - (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD0); - (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD1); - (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD2); - (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD3); - (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD4); - (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD5); - (void)tas3001c_sync_register(self,TAS3001C_REG_LEFT_BIQUAD6); - - tas3001c_fast_load(self, 0); - - tas3001c_set_mixer_level(self, SOUND_MIXER_VOLUME, VOL_DEFAULT<<8 | VOL_DEFAULT); - tas3001c_set_mixer_level(self, SOUND_MIXER_PCM, INPUT_DEFAULT<<8 | INPUT_DEFAULT); - tas3001c_set_mixer_level(self, SOUND_MIXER_ALTPCM, 0); - - tas3001c_set_mixer_level(self, SOUND_MIXER_BASS, BASS_DEFAULT); - tas3001c_set_mixer_level(self, SOUND_MIXER_TREBLE, TREBLE_DEFAULT); - - return 0; -} - -static int -tas3001c_uninit_mixer(struct tas3001c_data_t *self) -{ - tas3001c_set_mixer_level(self, SOUND_MIXER_VOLUME, 0); - tas3001c_set_mixer_level(self, SOUND_MIXER_PCM, 0); - tas3001c_set_mixer_level(self, SOUND_MIXER_ALTPCM, 0); - - tas3001c_set_mixer_level(self, SOUND_MIXER_BASS, 0); - tas3001c_set_mixer_level(self, SOUND_MIXER_TREBLE, 0); - - return 0; -} - -static int -tas3001c_init(struct i2c_client *client) -{ - struct tas3001c_data_t *self; - size_t sz = sizeof(*self) + (TAS3001C_REG_MAX*sizeof(tas_shadow_t)); - int i, j; - - self = kzalloc(sz, GFP_KERNEL); - if (!self) - return -ENOMEM; - - self->super.client = client; - self->super.shadow = (tas_shadow_t *)(self+1); - self->output_id = TAS_OUTPUT_HEADPHONES; - - dev_set_drvdata(&client->dev, self); - - for (i = 0; i < TAS3001C_BIQUAD_CHANNEL_COUNT; i++) - for (j = 0; j < TAS3001C_BIQUAD_FILTER_COUNT; j++) - tas3001c_write_biquad_shadow(self, i, j, - &tas3001c_eq_unity); - - INIT_WORK(&self->change, tas3001c_device_change_handler); - return 0; -} - -static void -tas3001c_uninit(struct tas3001c_data_t *self) -{ - tas3001c_uninit_mixer(self); - kfree(self); -} - -struct tas_driver_hooks_t tas3001c_hooks = { - .init = (tas_hook_init_t)tas3001c_init, - .post_init = (tas_hook_post_init_t)tas3001c_init_mixer, - .uninit = (tas_hook_uninit_t)tas3001c_uninit, - .get_mixer_level = (tas_hook_get_mixer_level_t)tas3001c_get_mixer_level, - .set_mixer_level = (tas_hook_set_mixer_level_t)tas3001c_set_mixer_level, - .enter_sleep = (tas_hook_enter_sleep_t)tas3001c_enter_sleep, - .leave_sleep = (tas_hook_leave_sleep_t)tas3001c_leave_sleep, - .supported_mixers = (tas_hook_supported_mixers_t)tas3001c_supported_mixers, - .mixer_is_stereo = (tas_hook_mixer_is_stereo_t)tas3001c_mixer_is_stereo, - .stereo_mixers = (tas_hook_stereo_mixers_t)tas3001c_stereo_mixers, - .output_device_change = (tas_hook_output_device_change_t)tas3001c_output_device_change, - .device_ioctl = (tas_hook_device_ioctl_t)tas3001c_device_ioctl -}; diff --git a/sound/oss/dmasound/tas3001c.h b/sound/oss/dmasound/tas3001c.h deleted file mode 100644 index 3660da33a2d..00000000000 --- a/sound/oss/dmasound/tas3001c.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Header file for the i2c/i2s based TA3001c sound chip used - * on some Apple hardware. Also known as "tumbler". - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive - * for more details. - * - * Written by Christopher C. Chimelis <chris@debian.org> - */ - -#ifndef _TAS3001C_H_ -#define _TAS3001C_H_ - -#include <linux/types.h> - -#include "tas_common.h" -#include "tas_eq_prefs.h" - -/* - * Macros that correspond to the registers that we write to - * when setting the various values. - */ - -#define TAS3001C_VERSION "0.3" -#define TAS3001C_DATE "20011214" - -#define I2C_DRIVERNAME_TAS3001C "TAS3001c driver V " TAS3001C_VERSION -#define I2C_DRIVERID_TAS3001C (I2C_DRIVERID_TAS_BASE+0) - -extern struct tas_driver_hooks_t tas3001c_hooks; -extern struct tas_gain_t tas3001c_gain; -extern struct tas_eq_pref_t *tas3001c_eq_prefs[]; - -enum tas3001c_reg_t { - TAS3001C_REG_MCR = 0x01, - TAS3001C_REG_DRC = 0x02, - - TAS3001C_REG_VOLUME = 0x04, - TAS3001C_REG_TREBLE = 0x05, - TAS3001C_REG_BASS = 0x06, - TAS3001C_REG_MIXER1 = 0x07, - TAS3001C_REG_MIXER2 = 0x08, - - TAS3001C_REG_LEFT_BIQUAD0 = 0x0a, - TAS3001C_REG_LEFT_BIQUAD1 = 0x0b, - TAS3001C_REG_LEFT_BIQUAD2 = 0x0c, - TAS3001C_REG_LEFT_BIQUAD3 = 0x0d, - TAS3001C_REG_LEFT_BIQUAD4 = 0x0e, - TAS3001C_REG_LEFT_BIQUAD5 = 0x0f, - TAS3001C_REG_LEFT_BIQUAD6 = 0x10, - - TAS3001C_REG_RIGHT_BIQUAD0 = 0x13, - TAS3001C_REG_RIGHT_BIQUAD1 = 0x14, - TAS3001C_REG_RIGHT_BIQUAD2 = 0x15, - TAS3001C_REG_RIGHT_BIQUAD3 = 0x16, - TAS3001C_REG_RIGHT_BIQUAD4 = 0x17, - TAS3001C_REG_RIGHT_BIQUAD5 = 0x18, - TAS3001C_REG_RIGHT_BIQUAD6 = 0x19, - - TAS3001C_REG_MAX = 0x20 -}; - -#endif /* _TAS3001C_H_ */ diff --git a/sound/oss/dmasound/tas3001c_tables.c b/sound/oss/dmasound/tas3001c_tables.c deleted file mode 100644 index 1768fa95f25..00000000000 --- a/sound/oss/dmasound/tas3001c_tables.c +++ /dev/null @@ -1,375 +0,0 @@ -#include "tas_common.h" -#include "tas_eq_prefs.h" - -static struct tas_drce_t eqp_0e_2_1_drce = { - .enable = 1, - .above = { .val = 3.0 * (1<<8), .expand = 0 }, - .below = { .val = 1.0 * (1<<8), .expand = 0 }, - .threshold = -15.33 * (1<<8), - .energy = 2.4 * (1<<12), - .attack = 0.013 * (1<<12), - .decay = 0.212 * (1<<12), -}; - -static struct tas_biquad_ctrl_t eqp_0e_2_1_biquads[]={ - { .channel = 0, .filter = 0, .data = { .coeff = { 0x0FCAD3, 0xE06A58, 0x0FCAD3, 0xE06B09, 0x0F9657 } } }, - { .channel = 0, .filter = 1, .data = { .coeff = { 0x041731, 0x082E63, 0x041731, 0xFD8D08, 0x02CFBD } } }, - { .channel = 0, .filter = 2, .data = { .coeff = { 0x0FFDC7, 0xE0524C, 0x0FBFAA, 0xE0524C, 0x0FBD72 } } }, - { .channel = 0, .filter = 3, .data = { .coeff = { 0x0F3D35, 0xE228CA, 0x0EC7B2, 0xE228CA, 0x0E04E8 } } }, - { .channel = 0, .filter = 4, .data = { .coeff = { 0x0FCEBF, 0xE181C2, 0x0F2656, 0xE181C2, 0x0EF516 } } }, - { .channel = 0, .filter = 5, .data = { .coeff = { 0x0EC417, 0x073E22, 0x0B0633, 0x073E22, 0x09CA4A } } }, - - { .channel = 1, .filter = 0, .data = { .coeff = { 0x0FCAD3, 0xE06A58, 0x0FCAD3, 0xE06B09, 0x0F9657 } } }, - { .channel = 1, .filter = 1, .data = { .coeff = { 0x041731, 0x082E63, 0x041731, 0xFD8D08, 0x02CFBD } } }, - { .channel = 1, .filter = 2, .data = { .coeff = { 0x0FFDC7, 0xE0524C, 0x0FBFAA, 0xE0524C, 0x0FBD72 } } }, - { .channel = 1, .filter = 3, .data = { .coeff = { 0x0F3D35, 0xE228CA, 0x0EC7B2, 0xE228CA, 0x0E04E8 } } }, - { .channel = 1, .filter = 4, .data = { .coeff = { 0x0FCEBF, 0xE181C2, 0x0F2656, 0xE181C2, 0x0EF516 } } }, - { .channel = 1, .filter = 5, .data = { .coeff = { 0x0EC417, 0x073E22, 0x0B0633, 0x073E22, 0x09CA4A } } }, -}; - -static struct tas_eq_pref_t eqp_0e_2_1 = { - .sample_rate = 44100, - .device_id = 0x0e, - .output_id = TAS_OUTPUT_EXTERNAL_SPKR, - .speaker_id = 0x01, - - .drce = &eqp_0e_2_1_drce, - - .filter_count = 12, - .biquads = eqp_0e_2_1_biquads -}; - -/* ======================================================================== */ - -static struct tas_drce_t eqp_10_1_0_drce={ - .enable = 1, - .above = { .val = 3.0 * (1<<8), .expand = 0 }, - .below = { .val = 1.0 * (1<<8), .expand = 0 }, - .threshold = -12.46 * (1<<8), - .energy = 2.4 * (1<<12), - .attack = 0.013 * (1<<12), - .decay = 0.212 * (1<<12), -}; - -static struct tas_biquad_ctrl_t eqp_10_1_0_biquads[]={ - { .channel = 0, .filter = 0, .data = { .coeff = { 0x0F4A12, 0xE16BDA, 0x0F4A12, 0xE173F0, 0x0E9C3A } } }, - { .channel = 0, .filter = 1, .data = { .coeff = { 0x02DD54, 0x05BAA8, 0x02DD54, 0xF8001D, 0x037532 } } }, - { .channel = 0, .filter = 2, .data = { .coeff = { 0x0E2FC7, 0xE4D5DC, 0x0D7477, 0xE4D5DC, 0x0BA43F } } }, - { .channel = 0, .filter = 3, .data = { .coeff = { 0x0E7899, 0xE67CCA, 0x0D0E93, 0xE67CCA, 0x0B872D } } }, - { .channel = 0, .filter = 4, .data = { .coeff = { 0x100000, 0x000000, 0x000000, 0x000000, 0x000000 } } }, - { .channel = 0, .filter = 5, .data = { .coeff = { 0x100000, 0x000000, 0x000000, 0x000000, 0x000000 } } }, - - { .channel = 1, .filter = 0, .data = { .coeff = { 0x0F4A12, 0xE16BDA, 0x0F4A12, 0xE173F0, 0x0E9C3A } } }, - { .channel = 1, .filter = 1, .data = { .coeff = { 0x02DD54, 0x05BAA8, 0x02DD54, 0xF8001D, 0x037532 } } }, - { .channel = 1, .filter = 2, .data = { .coeff = { 0x0E2FC7, 0xE4D5DC, 0x0D7477, 0xE4D5DC, 0x0BA43F } } }, - { .channel = 1, .filter = 3, .data = { .coeff = { 0x0E7899, 0xE67CCA, 0x0D0E93, 0xE67CCA, 0x0B872D } } }, - { .channel = 1, .filter = 4, .data = { .coeff = { 0x100000, 0x000000, 0x000000, 0x000000, 0x000000 } } }, - { .channel = 1, .filter = 5, .data = { .coeff = { 0x100000, 0x000000, 0x000000, 0x000000, 0x000000 } } }, -}; - -static struct tas_eq_pref_t eqp_10_1_0 = { - .sample_rate = 44100, - .device_id = 0x10, - .output_id = TAS_OUTPUT_INTERNAL_SPKR, - .speaker_id = 0x00, - - .drce = &eqp_10_1_0_drce, - - .filter_count = 12, - .biquads = eqp_10_1_0_biquads -}; - -/* ======================================================================== */ - -static struct tas_drce_t eqp_15_2_1_drce={ - .enable = 1, - .above = { .val = 3.0 * (1<<8), .expand = 0 }, - .below = { .val = 1.0 * (1<<8), .expand = 0 }, - .threshold = -15.33 * (1<<8), - .energy = 2.4 * (1<<12), - .attack = 0.013 * (1<<12), - .decay = 0.212 * (1<<12), -}; - -static struct tas_biquad_ctrl_t eqp_15_2_1_biquads[]={ - { .channel = 0, .filter = 0, .data = { .coeff = { 0x0FE143, 0xE05204, 0x0FCCC5, 0xE05266, 0x0FAE6B } } }, - { .channel = 0, .filter = 1, .data = { .coeff = { 0x102383, 0xE03A03, 0x0FA325, 0xE03A03, 0x0FC6A8 } } }, - { .channel = 0, .filter = 2, .data = { .coeff = { 0x0FF2AB, 0xE06285, 0x0FB20A, 0xE06285, 0x0FA4B5 } } }, - { .channel = 0, .filter = 3, .data = { .coeff = { 0x0F544D, 0xE35971, 0x0D8F3A, 0xE35971, 0x0CE388 } } }, - { .channel = 0, .filter = 4, .data = { .coeff = { 0x13E1D3, 0xF3ECB5, 0x042227, 0xF3ECB5, 0x0803FA } } }, - { .channel = 0, .filter = 5, .data = { .coeff = { 0x0AC119, 0x034181, 0x078AB1, 0x034181, 0x024BCA } } }, - - { .channel = 1, .filter = 0, .data = { .coeff = { 0x0FE143, 0xE05204, 0x0FCCC5, 0xE05266, 0x0FAE6B } } }, - { .channel = 1, .filter = 1, .data = { .coeff = { 0x102383, 0xE03A03, 0x0FA325, 0xE03A03, 0x0FC6A8 } } }, - { .channel = 1, .filter = 2, .data = { .coeff = { 0x0FF2AB, 0xE06285, 0x0FB20A, 0xE06285, 0x0FA4B5 } } }, - { .channel = 1, .filter = 3, .data = { .coeff = { 0x0F544D, 0xE35971, 0x0D8F3A, 0xE35971, 0x0CE388 } } }, - { .channel = 1, .filter = 4, .data = { .coeff = { 0x13E1D3, 0xF3ECB5, 0x042227, 0xF3ECB5, 0x0803FA } } }, - { .channel = 1, .filter = 5, .data = { .coeff = { 0x0AC119, 0x034181, 0x078AB1, 0x034181, 0x024BCA } } }, -}; - -static struct tas_eq_pref_t eqp_15_2_1 = { - .sample_rate = 44100, - .device_id = 0x15, - .output_id = TAS_OUTPUT_EXTERNAL_SPKR, - .speaker_id = 0x01, - - .drce = &eqp_15_2_1_drce, - - .filter_count = 12, - .biquads = eqp_15_2_1_biquads -}; - -/* ======================================================================== */ - -static struct tas_drce_t eqp_15_1_0_drce={ - .enable = 1, - .above = { .val = 3.0 * (1<<8), .expand = 0 }, - .below = { .val = 1.0 * (1<<8), .expand = 0 }, - .threshold = 0.0 * (1<<8), - .energy = 2.4 * (1<<12), - .attack = 0.013 * (1<<12), - .decay = 0.212 * (1<<12), -}; - -static struct tas_biquad_ctrl_t eqp_15_1_0_biquads[]={ - { .channel = 0, .filter = 0, .data = { .coeff = { 0x0FAD08, 0xE0A5EF, 0x0FAD08, 0xE0A79D, 0x0F5BBE } } }, - { .channel = 0, .filter = 1, .data = { .coeff = { 0x04B38D, 0x09671B, 0x04B38D, 0x000F71, 0x02BEC5 } } }, - { .channel = 0, .filter = 2, .data = { .coeff = { 0x0FDD32, 0xE0A56F, 0x0F8A69, 0xE0A56F, 0x0F679C } } }, - { .channel = 0, .filter = 3, .data = { .coeff = { 0x0FD284, 0xE135FB, 0x0F2161, 0xE135FB, 0x0EF3E5 } } }, - { .channel = 0, .filter = 4, .data = { .coeff = { 0x0E81B1, 0xE6283F, 0x0CE49D, 0xE6283F, 0x0B664F } } }, - { .channel = 0, .filter = 5, .data = { .coeff = { 0x0F2D62, 0xE98797, 0x0D1E19, 0xE98797, 0x0C4B7B } } }, - - { .channel = 1, .filter = 0, .data = { .coeff = { 0x0FAD08, 0xE0A5EF, 0x0FAD08, 0xE0A79D, 0x0F5BBE } } }, - { .channel = 1, .filter = 1, .data = { .coeff = { 0x04B38D, 0x09671B, 0x04B38D, 0x000F71, 0x02BEC5 } } }, - { .channel = 1, .filter = 2, .data = { .coeff = { 0x0FDD32, 0xE0A56F, 0x0F8A69, 0xE0A56F, 0x0F679C } } }, - { .channel = 1, .filter = 3, .data = { .coeff = { 0x0FD284, 0xE135FB, 0x0F2161, 0xE135FB, 0x0EF3E5 } } }, - { .channel = 1, .filter = 4, .data = { .coeff = { 0x0E81B1, 0xE6283F, 0x0CE49D, 0xE6283F, 0x0B664F } } }, - { .channel = 1, .filter = 5, .data = { .coeff = { 0x0F2D62, 0xE98797, 0x0D1E19, 0xE98797, 0x0C4B7B } } }, -}; - -static struct tas_eq_pref_t eqp_15_1_0 = { - .sample_rate = 44100, - .device_id = 0x15, - .output_id = TAS_OUTPUT_INTERNAL_SPKR, - .speaker_id = 0x00, - - .drce = &eqp_15_1_0_drce, - - .filter_count = 12, - .biquads = eqp_15_1_0_biquads -}; - -/* ======================================================================== */ - -static struct tas_drce_t eqp_0f_2_1_drce={ - .enable = 1, - .above = { .val = 3.0 * (1<<8), .expand = 0 }, - .below = { .val = 1.0 * (1<<8), .expand = 0 }, - .threshold = -15.33 * (1<<8), - .energy = 2.4 * (1<<12), - .attack = 0.013 * (1<<12), - .decay = 0.212 * (1<<12), -}; - -static struct tas_biquad_ctrl_t eqp_0f_2_1_biquads[]={ - { .channel = 0, .filter = 0, .data = { .coeff = { 0x0FE143, 0xE05204, 0x0FCCC5, 0xE05266, 0x0FAE6B } } }, - { .channel = 0, .filter = 1, .data = { .coeff = { 0x102383, 0xE03A03, 0x0FA325, 0xE03A03, 0x0FC6A8 } } }, - { .channel = 0, .filter = 2, .data = { .coeff = { 0x0FF2AB, 0xE06285, 0x0FB20A, 0xE06285, 0x0FA4B5 } } }, - { .channel = 0, .filter = 3, .data = { .coeff = { 0x0F544D, 0xE35971, 0x0D8F3A, 0xE35971, 0x0CE388 } } }, - { .channel = 0, .filter = 4, .data = { .coeff = { 0x13E1D3, 0xF3ECB5, 0x042227, 0xF3ECB5, 0x0803FA } } }, - { .channel = 0, .filter = 5, .data = { .coeff = { 0x0AC119, 0x034181, 0x078AB1, 0x034181, 0x024BCA } } }, - - { .channel = 1, .filter = 0, .data = { .coeff = { 0x0FE143, 0xE05204, 0x0FCCC5, 0xE05266, 0x0FAE6B } } }, - { .channel = 1, .filter = 1, .data = { .coeff = { 0x102383, 0xE03A03, 0x0FA325, 0xE03A03, 0x0FC6A8 } } }, - { .channel = 1, .filter = 2, .data = { .coeff = { 0x0FF2AB, 0xE06285, 0x0FB20A, 0xE06285, 0x0FA4B5 } } }, - { .channel = 1, .filter = 3, .data = { .coeff = { 0x0F544D, 0xE35971, 0x0D8F3A, 0xE35971, 0x0CE388 } } }, - { .channel = 1, .filter = 4, .data = { .coeff = { 0x13E1D3, 0xF3ECB5, 0x042227, 0xF3ECB5, 0x0803FA } } }, - { .channel = 1, .filter = 5, .data = { .coeff = { 0x0AC119, 0x034181, 0x078AB1, 0x034181, 0x024BCA } } }, -}; - -static struct tas_eq_pref_t eqp_0f_2_1 = { - .sample_rate = 44100, - .device_id = 0x0f, - .output_id = TAS_OUTPUT_EXTERNAL_SPKR, - .speaker_id = 0x01, - - .drce = &eqp_0f_2_1_drce, - - .filter_count = 12, - .biquads = eqp_0f_2_1_biquads -}; - -/* ======================================================================== */ - -static struct tas_drce_t eqp_0f_1_0_drce={ - .enable = 1, - .above = { .val = 3.0 * (1<<8), .expand = 0 }, - .below = { .val = 1.0 * (1<<8), .expand = 0 }, - .threshold = -15.33 * (1<<8), - .energy = 2.4 * (1<<12), - .attack = 0.013 * (1<<12), - .decay = 0.212 * (1<<12), -}; - -static struct tas_biquad_ctrl_t eqp_0f_1_0_biquads[]={ - { .channel = 0, .filter = 0, .data = { .coeff = { 0x0FCAD3, 0xE06A58, 0x0FCAD3, 0xE06B09, 0x0F9657 } } }, - { .channel = 0, .filter = 1, .data = { .coeff = { 0x041731, 0x082E63, 0x041731, 0xFD8D08, 0x02CFBD } } }, - { .channel = 0, .filter = 2, .data = { .coeff = { 0x0FFDC7, 0xE0524C, 0x0FBFAA, 0xE0524C, 0x0FBD72 } } }, - { .channel = 0, .filter = 3, .data = { .coeff = { 0x0F3D35, 0xE228CA, 0x0EC7B2, 0xE228CA, 0x0E04E8 } } }, - { .channel = 0, .filter = 4, .data = { .coeff = { 0x0FCEBF, 0xE181C2, 0x0F2656, 0xE181C2, 0x0EF516 } } }, - { .channel = 0, .filter = 5, .data = { .coeff = { 0x0EC417, 0x073E22, 0x0B0633, 0x073E22, 0x09CA4A } } }, - - { .channel = 1, .filter = 0, .data = { .coeff = { 0x0FCAD3, 0xE06A58, 0x0FCAD3, 0xE06B09, 0x0F9657 } } }, - { .channel = 1, .filter = 1, .data = { .coeff = { 0x041731, 0x082E63, 0x041731, 0xFD8D08, 0x02CFBD } } }, - { .channel = 1, .filter = 2, .data = { .coeff = { 0x0FFDC7, 0xE0524C, 0x0FBFAA, 0xE0524C, 0x0FBD72 } } }, - { .channel = 1, .filter = 3, .data = { .coeff = { 0x0F3D35, 0xE228CA, 0x0EC7B2, 0xE228CA, 0x0E04E8 } } }, - { .channel = 1, .filter = 4, .data = { .coeff = { 0x0FCEBF, 0xE181C2, 0x0F2656, 0xE181C2, 0x0EF516 } } }, - { .channel = 1, .filter = 5, .data = { .coeff = { 0x0EC417, 0x073E22, 0x0B0633, 0x073E22, 0x09CA4A } } }, -}; - -static struct tas_eq_pref_t eqp_0f_1_0 = { - .sample_rate = 44100, - .device_id = 0x0f, - .output_id = TAS_OUTPUT_INTERNAL_SPKR, - .speaker_id = 0x00, - - .drce = &eqp_0f_1_0_drce, - - .filter_count = 12, - .biquads = eqp_0f_1_0_biquads -}; - -/* ======================================================================== */ - -static uint tas3001c_master_tab[]={ - 0x0, 0x75, 0x9c, 0xbb, - 0xdb, 0xfb, 0x11e, 0x143, - 0x16b, 0x196, 0x1c3, 0x1f5, - 0x229, 0x263, 0x29f, 0x2e1, - 0x328, 0x373, 0x3c5, 0x41b, - 0x478, 0x4dc, 0x547, 0x5b8, - 0x633, 0x6b5, 0x740, 0x7d5, - 0x873, 0x91c, 0x9d2, 0xa92, - 0xb5e, 0xc39, 0xd22, 0xe19, - 0xf20, 0x1037, 0x1161, 0x129e, - 0x13ed, 0x1551, 0x16ca, 0x185d, - 0x1a08, 0x1bcc, 0x1dac, 0x1fa7, - 0x21c1, 0x23fa, 0x2655, 0x28d6, - 0x2b7c, 0x2e4a, 0x3141, 0x3464, - 0x37b4, 0x3b35, 0x3ee9, 0x42d3, - 0x46f6, 0x4b53, 0x4ff0, 0x54ce, - 0x59f2, 0x5f5f, 0x6519, 0x6b24, - 0x7183, 0x783c, 0x7f53, 0x86cc, - 0x8ead, 0x96fa, 0x9fba, 0xa8f2, - 0xb2a7, 0xbce1, 0xc7a5, 0xd2fa, - 0xdee8, 0xeb75, 0xf8aa, 0x1068e, - 0x1152a, 0x12487, 0x134ad, 0x145a5, - 0x1577b, 0x16a37, 0x17df5, 0x192bd, - 0x1a890, 0x1bf7b, 0x1d78d, 0x1f0d1, - 0x20b55, 0x22727, 0x24456, 0x262f2, - 0x2830b -}; - -static uint tas3001c_mixer_tab[]={ - 0x0, 0x748, 0x9be, 0xbaf, - 0xda4, 0xfb1, 0x11de, 0x1431, - 0x16ad, 0x1959, 0x1c37, 0x1f4b, - 0x2298, 0x2628, 0x29fb, 0x2e12, - 0x327d, 0x3734, 0x3c47, 0x41b4, - 0x4787, 0x4dbe, 0x546d, 0x5b86, - 0x632e, 0x6b52, 0x7400, 0x7d54, - 0x873b, 0x91c6, 0x9d1a, 0xa920, - 0xb5e5, 0xc38c, 0xd21b, 0xe18f, - 0xf1f5, 0x1036a, 0x1160f, 0x129d6, - 0x13ed0, 0x1550c, 0x16ca0, 0x185c9, - 0x1a07b, 0x1bcc3, 0x1dab9, 0x1fa75, - 0x21c0f, 0x23fa3, 0x26552, 0x28d64, - 0x2b7c9, 0x2e4a2, 0x31411, 0x3463b, - 0x37b44, 0x3b353, 0x3ee94, 0x42d30, - 0x46f55, 0x4b533, 0x4fefc, 0x54ce5, - 0x59f25, 0x5f5f6, 0x65193, 0x6b23c, - 0x71835, 0x783c3, 0x7f52c, 0x86cc0, - 0x8eacc, 0x96fa5, 0x9fba0, 0xa8f1a, - 0xb2a71, 0xbce0a, 0xc7a4a, 0xd2fa0, - 0xdee7b, 0xeb752, 0xf8a9f, 0x1068e4, - 0x1152a3, 0x12486a, 0x134ac8, 0x145a55, - 0x1577ac, 0x16a370, 0x17df51, 0x192bc2, - 0x1a88f8, 0x1bf7b7, 0x1d78c9, 0x1f0d04, - 0x20b542, 0x227268, 0x244564, 0x262f26, - 0x2830af -}; - -static uint tas3001c_treble_tab[]={ - 0x96, 0x95, 0x95, 0x94, - 0x93, 0x92, 0x92, 0x91, - 0x90, 0x90, 0x8f, 0x8e, - 0x8d, 0x8d, 0x8c, 0x8b, - 0x8a, 0x8a, 0x89, 0x88, - 0x88, 0x87, 0x86, 0x85, - 0x85, 0x84, 0x83, 0x83, - 0x82, 0x81, 0x80, 0x80, - 0x7f, 0x7e, 0x7e, 0x7d, - 0x7c, 0x7b, 0x7b, 0x7a, - 0x79, 0x78, 0x78, 0x77, - 0x76, 0x76, 0x75, 0x74, - 0x73, 0x73, 0x72, 0x71, - 0x71, 0x70, 0x6e, 0x6d, - 0x6d, 0x6c, 0x6b, 0x6a, - 0x69, 0x68, 0x67, 0x66, - 0x65, 0x63, 0x62, 0x62, - 0x60, 0x5f, 0x5d, 0x5c, - 0x5a, 0x58, 0x56, 0x55, - 0x53, 0x51, 0x4f, 0x4c, - 0x4a, 0x48, 0x45, 0x43, - 0x40, 0x3d, 0x3a, 0x37, - 0x35, 0x32, 0x2e, 0x2a, - 0x27, 0x22, 0x1e, 0x1a, - 0x15, 0x11, 0xc, 0x7, - 0x1 -}; - -static uint tas3001c_bass_tab[]={ - 0x86, 0x83, 0x81, 0x7f, - 0x7d, 0x7b, 0x79, 0x78, - 0x76, 0x75, 0x74, 0x72, - 0x71, 0x6f, 0x6e, 0x6d, - 0x6c, 0x6b, 0x69, 0x67, - 0x65, 0x64, 0x61, 0x60, - 0x5e, 0x5d, 0x5c, 0x5b, - 0x5a, 0x59, 0x58, 0x57, - 0x56, 0x55, 0x55, 0x54, - 0x53, 0x52, 0x50, 0x4f, - 0x4d, 0x4c, 0x4b, 0x49, - 0x47, 0x45, 0x44, 0x42, - 0x41, 0x3f, 0x3e, 0x3d, - 0x3c, 0x3b, 0x39, 0x38, - 0x37, 0x36, 0x35, 0x34, - 0x33, 0x31, 0x30, 0x2f, - 0x2e, 0x2c, 0x2b, 0x2b, - 0x29, 0x28, 0x27, 0x26, - 0x25, 0x24, 0x22, 0x21, - 0x20, 0x1e, 0x1c, 0x19, - 0x18, 0x18, 0x17, 0x16, - 0x15, 0x14, 0x13, 0x12, - 0x11, 0x10, 0xf, 0xe, - 0xd, 0xb, 0xa, 0x9, - 0x8, 0x6, 0x4, 0x2, - 0x1 -}; - -struct tas_gain_t tas3001c_gain = { - .master = tas3001c_master_tab, - .treble = tas3001c_treble_tab, - .bass = tas3001c_bass_tab, - .mixer = tas3001c_mixer_tab -}; - -struct tas_eq_pref_t *tas3001c_eq_prefs[]={ - &eqp_0e_2_1, - &eqp_10_1_0, - &eqp_15_2_1, - &eqp_15_1_0, - &eqp_0f_2_1, - &eqp_0f_1_0, - NULL -}; diff --git a/sound/oss/dmasound/tas3004.c b/sound/oss/dmasound/tas3004.c deleted file mode 100644 index 678bf0ff6da..00000000000 --- a/sound/oss/dmasound/tas3004.c +++ /dev/null @@ -1,1138 +0,0 @@ -/* - * Driver for the i2c/i2s based TA3004 sound chip used - * on some Apple hardware. Also known as "snapper". - * - * Tobias Sargeant <tobias.sargeant@bigpond.com> - * Based upon tas3001c.c by Christopher C. Chimelis <chris@debian.org>: - * - * Input support by Renzo Davoli <renzo@cs.unibo.it> - * - */ - -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/proc_fs.h> -#include <linux/ioport.h> -#include <linux/sysctl.h> -#include <linux/types.h> -#include <linux/i2c.h> -#include <linux/init.h> -#include <linux/soundcard.h> -#include <linux/interrupt.h> -#include <linux/workqueue.h> - -#include <asm/uaccess.h> -#include <asm/errno.h> -#include <asm/io.h> -#include <asm/prom.h> - -#include "dmasound.h" -#include "tas_common.h" -#include "tas3004.h" - -#include "tas_ioctl.h" - -/* #define DEBUG_DRCE */ - -#define TAS3004_BIQUAD_FILTER_COUNT 7 -#define TAS3004_BIQUAD_CHANNEL_COUNT 2 - -#define VOL_DEFAULT (100 * 4 / 5) -#define INPUT_DEFAULT (100 * 4 / 5) -#define BASS_DEFAULT (100 / 2) -#define TREBLE_DEFAULT (100 / 2) - -struct tas3004_data_t { - struct tas_data_t super; - int device_id; - int output_id; - int speaker_id; - struct tas_drce_t drce_state; - struct work_struct change; -}; - -#define MAKE_TIME(sec,usec) (((sec)<<12) + (50000+(usec/10)*(1<<12))/100000) - -#define MAKE_RATIO(i,f) (((i)<<8) + ((500+(f)*(1<<8))/1000)) - - -static const union tas_biquad_t tas3004_eq_unity = { - .buf = { 0x100000, 0x000000, 0x000000, 0x000000, 0x000000 }, -}; - - -static const struct tas_drce_t tas3004_drce_min = { - .enable = 1, - .above = { .val = MAKE_RATIO(16,0), .expand = 0 }, - .below = { .val = MAKE_RATIO(2,0), .expand = 0 }, - .threshold = -0x59a0, - .energy = MAKE_TIME(0, 1700), - .attack = MAKE_TIME(0, 1700), - .decay = MAKE_TIME(0, 1700), -}; - - -static const struct tas_drce_t tas3004_drce_max = { - .enable = 1, - .above = { .val = MAKE_RATIO(1,500), .expand = 1 }, - .below = { .val = MAKE_RATIO(2,0), .expand = 1 }, - .threshold = -0x0, - .energy = MAKE_TIME(2,400000), - .attack = MAKE_TIME(2,400000), - .decay = MAKE_TIME(2,400000), -}; - - -static const unsigned short time_constants[]={ - MAKE_TIME(0, 1700), - MAKE_TIME(0, 3500), - MAKE_TIME(0, 6700), - MAKE_TIME(0, 13000), - MAKE_TIME(0, 26000), - MAKE_TIME(0, 53000), - MAKE_TIME(0,106000), - MAKE_TIME(0,212000), - MAKE_TIME(0,425000), - MAKE_TIME(0,850000), - MAKE_TIME(1,700000), - MAKE_TIME(2,400000), -}; - -static const unsigned short above_threshold_compression_ratio[]={ - MAKE_RATIO( 1, 70), - MAKE_RATIO( 1,140), - MAKE_RATIO( 1,230), - MAKE_RATIO( 1,330), - MAKE_RATIO( 1,450), - MAKE_RATIO( 1,600), - MAKE_RATIO( 1,780), - MAKE_RATIO( 2, 0), - MAKE_RATIO( 2,290), - MAKE_RATIO( 2,670), - MAKE_RATIO( 3,200), - MAKE_RATIO( 4, 0), - MAKE_RATIO( 5,330), - MAKE_RATIO( 8, 0), - MAKE_RATIO(16, 0), -}; - -static const unsigned short above_threshold_expansion_ratio[]={ - MAKE_RATIO(1, 60), - MAKE_RATIO(1,130), - MAKE_RATIO(1,190), - MAKE_RATIO(1,250), - MAKE_RATIO(1,310), - MAKE_RATIO(1,380), - MAKE_RATIO(1,440), - MAKE_RATIO(1,500) -}; - -static const unsigned short below_threshold_compression_ratio[]={ - MAKE_RATIO(1, 70), - MAKE_RATIO(1,140), - MAKE_RATIO(1,230), - MAKE_RATIO(1,330), - MAKE_RATIO(1,450), - MAKE_RATIO(1,600), - MAKE_RATIO(1,780), - MAKE_RATIO(2, 0) -}; - -static const unsigned short below_threshold_expansion_ratio[]={ - MAKE_RATIO(1, 60), - MAKE_RATIO(1,130), - MAKE_RATIO(1,190), - MAKE_RATIO(1,250), - MAKE_RATIO(1,310), - MAKE_RATIO(1,380), - MAKE_RATIO(1,440), - MAKE_RATIO(1,500), - MAKE_RATIO(1,560), - MAKE_RATIO(1,630), - MAKE_RATIO(1,690), - MAKE_RATIO(1,750), - MAKE_RATIO(1,810), - MAKE_RATIO(1,880), - MAKE_RATIO(1,940), - MAKE_RATIO(2, 0) -}; - -static inline int -search( unsigned short val, - const unsigned short *arr, - const int arrsize) { - /* - * This could be a binary search, but for small tables, - * a linear search is likely to be faster - */ - - int i; - - for (i=0; i < arrsize; i++) - if (arr[i] >= val) - goto _1; - return arrsize-1; - _1: - if (i == 0) - return 0; - return (arr[i]-val < val-arr[i-1]) ? i : i-1; -} - -#define SEARCH(a, b) search(a, b, ARRAY_SIZE(b)) - -static inline int -time_index(unsigned short time) -{ - return SEARCH(time, time_constants); -} - - -static inline int -above_threshold_compression_index(unsigned short ratio) -{ - return SEARCH(ratio, above_threshold_compression_ratio); -} - - -static inline int -above_threshold_expansion_index(unsigned short ratio) -{ - return SEARCH(ratio, above_threshold_expansion_ratio); -} - - -static inline int -below_threshold_compression_index(unsigned short ratio) -{ - return SEARCH(ratio, below_threshold_compression_ratio); -} - - -static inline int -below_threshold_expansion_index(unsigned short ratio) -{ - return SEARCH(ratio, below_threshold_expansion_ratio); -} - -static inline unsigned char db_to_regval(short db) { - int r=0; - - r=(db+0x59a0) / 0x60; - - if (r < 0x91) return 0x91; - if (r > 0xef) return 0xef; - return r; -} - -static inline short quantize_db(short db) -{ - return db_to_regval(db) * 0x60 - 0x59a0; -} - -static inline int -register_width(enum tas3004_reg_t r) -{ - switch(r) { - case TAS3004_REG_MCR: - case TAS3004_REG_TREBLE: - case TAS3004_REG_BASS: - case TAS3004_REG_ANALOG_CTRL: - case TAS3004_REG_TEST1: - case TAS3004_REG_TEST2: - case TAS3004_REG_MCR2: - return 1; - - case TAS3004_REG_LEFT_LOUD_BIQUAD_GAIN: - case TAS3004_REG_RIGHT_LOUD_BIQUAD_GAIN: - return 3; - - case TAS3004_REG_DRC: - case TAS3004_REG_VOLUME: - return 6; - - case TAS3004_REG_LEFT_MIXER: - case TAS3004_REG_RIGHT_MIXER: - return 9; - - case TAS3004_REG_TEST: - return 10; - - case TAS3004_REG_LEFT_BIQUAD0: - case TAS3004_REG_LEFT_BIQUAD1: - case TAS3004_REG_LEFT_BIQUAD2: - case TAS3004_REG_LEFT_BIQUAD3: - case TAS3004_REG_LEFT_BIQUAD4: - case TAS3004_REG_LEFT_BIQUAD5: - case TAS3004_REG_LEFT_BIQUAD6: - - case TAS3004_REG_RIGHT_BIQUAD0: - case TAS3004_REG_RIGHT_BIQUAD1: - case TAS3004_REG_RIGHT_BIQUAD2: - case TAS3004_REG_RIGHT_BIQUAD3: - case TAS3004_REG_RIGHT_BIQUAD4: - case TAS3004_REG_RIGHT_BIQUAD5: - case TAS3004_REG_RIGHT_BIQUAD6: - - case TAS3004_REG_LEFT_LOUD_BIQUAD: - case TAS3004_REG_RIGHT_LOUD_BIQUAD: - return 15; - - default: - return 0; - } -} - -static int -tas3004_write_register( struct tas3004_data_t *self, - enum tas3004_reg_t reg_num, - char *data, - uint write_mode) -{ - if (reg_num==TAS3004_REG_MCR || - reg_num==TAS3004_REG_BASS || - reg_num==TAS3004_REG_TREBLE || - reg_num==TAS3004_REG_ANALOG_CTRL) { - return tas_write_byte_register(&self->super, - (uint)reg_num, - *data, - write_mode); - } else { - return tas_write_register(&self->super, - (uint)reg_num, - register_width(reg_num), - data, - write_mode); - } -} - -static int -tas3004_sync_register( struct tas3004_data_t *self, - enum tas3004_reg_t reg_num) -{ - if (reg_num==TAS3004_REG_MCR || - reg_num==TAS3004_REG_BASS || - reg_num==TAS3004_REG_TREBLE || - reg_num==TAS3004_REG_ANALOG_CTRL) { - return tas_sync_byte_register(&self->super, - (uint)reg_num, - register_width(reg_num)); - } else { - return tas_sync_register(&self->super, - (uint)reg_num, - register_width(reg_num)); - } -} - -static int -tas3004_read_register( struct tas3004_data_t *self, - enum tas3004_reg_t reg_num, - char *data, - uint write_mode) -{ - return tas_read_register(&self->super, - (uint)reg_num, - register_width(reg_num), - data); -} - -static inline int -tas3004_fast_load(struct tas3004_data_t *self, int fast) -{ - if (fast) - self->super.shadow[TAS3004_REG_MCR][0] |= 0x80; - else - self->super.shadow[TAS3004_REG_MCR][0] &= 0x7f; - return tas3004_sync_register(self,TAS3004_REG_MCR); -} - -static uint -tas3004_supported_mixers(struct tas3004_data_t *self) -{ - return SOUND_MASK_VOLUME | - SOUND_MASK_PCM | - SOUND_MASK_ALTPCM | - SOUND_MASK_IMIX | - SOUND_MASK_TREBLE | - SOUND_MASK_BASS | - SOUND_MASK_MIC | - SOUND_MASK_LINE; -} - -static int -tas3004_mixer_is_stereo(struct tas3004_data_t *self, int mixer) -{ - switch(mixer) { - case SOUND_MIXER_VOLUME: - case SOUND_MIXER_PCM: - case SOUND_MIXER_ALTPCM: - case SOUND_MIXER_IMIX: - return 1; - default: - return 0; - } -} - -static uint -tas3004_stereo_mixers(struct tas3004_data_t *self) -{ - uint r = tas3004_supported_mixers(self); - uint i; - - for (i=1; i<SOUND_MIXER_NRDEVICES; i++) - if (r&(1<<i) && !tas3004_mixer_is_stereo(self,i)) - r &= ~(1<<i); - return r; -} - -static int -tas3004_get_mixer_level(struct tas3004_data_t *self, int mixer, uint *level) -{ - if (!self) - return -1; - - *level = self->super.mixer[mixer]; - - return 0; -} - -static int -tas3004_set_mixer_level(struct tas3004_data_t *self, int mixer, uint level) -{ - int rc; - tas_shadow_t *shadow; - uint temp; - uint offset=0; - - if (!self) - return -1; - - shadow = self->super.shadow; - - if (!tas3004_mixer_is_stereo(self,mixer)) - level = tas_mono_to_stereo(level); - switch(mixer) { - case SOUND_MIXER_VOLUME: - temp = tas3004_gain.master[level&0xff]; - SET_4_20(shadow[TAS3004_REG_VOLUME], 0, temp); - temp = tas3004_gain.master[(level>>8)&0xff]; - SET_4_20(shadow[TAS3004_REG_VOLUME], 3, temp); - rc = tas3004_sync_register(self,TAS3004_REG_VOLUME); - break; - case SOUND_MIXER_IMIX: - offset += 3; - case SOUND_MIXER_ALTPCM: - offset += 3; - case SOUND_MIXER_PCM: - /* - * Don't load these in fast mode. The documentation - * says it can be done in either mode, but testing it - * shows that fast mode produces ugly clicking. - */ - /* tas3004_fast_load(self,1); */ - temp = tas3004_gain.mixer[level&0xff]; - SET_4_20(shadow[TAS3004_REG_LEFT_MIXER], offset, temp); - temp = tas3004_gain.mixer[(level>>8)&0xff]; - SET_4_20(shadow[TAS3004_REG_RIGHT_MIXER], offset, temp); - rc = tas3004_sync_register(self,TAS3004_REG_LEFT_MIXER); - if (rc == 0) - rc=tas3004_sync_register(self,TAS3004_REG_RIGHT_MIXER); - /* tas3004_fast_load(self,0); */ - break; - case SOUND_MIXER_TREBLE: - temp = tas3004_gain.treble[level&0xff]; - shadow[TAS3004_REG_TREBLE][0]=temp&0xff; - rc = tas3004_sync_register(self,TAS3004_REG_TREBLE); - break; - case SOUND_MIXER_BASS: - temp = tas3004_gain.bass[level&0xff]; - shadow[TAS3004_REG_BASS][0]=temp&0xff; - rc = tas3004_sync_register(self,TAS3004_REG_BASS); - break; - case SOUND_MIXER_MIC: - if ((level&0xff)>0) { - software_input_volume = SW_INPUT_VOLUME_SCALE * (level&0xff); - if (self->super.mixer[mixer] == 0) { - self->super.mixer[SOUND_MIXER_LINE] = 0; - shadow[TAS3004_REG_ANALOG_CTRL][0]=0xc2; - rc = tas3004_sync_register(self,TAS3004_REG_ANALOG_CTRL); - } else rc=0; - } else { - self->super.mixer[SOUND_MIXER_LINE] = SW_INPUT_VOLUME_DEFAULT; - software_input_volume = SW_INPUT_VOLUME_SCALE * - (self->super.mixer[SOUND_MIXER_LINE]&0xff); - shadow[TAS3004_REG_ANALOG_CTRL][0]=0x00; - rc = tas3004_sync_register(self,TAS3004_REG_ANALOG_CTRL); - } - break; - case SOUND_MIXER_LINE: - if (self->super.mixer[SOUND_MIXER_MIC] == 0) { - software_input_volume = SW_INPUT_VOLUME_SCALE * (level&0xff); - rc=0; - } - break; - default: - rc = -1; - break; - } - if (rc < 0) - return rc; - self->super.mixer[mixer] = level; - - return 0; -} - -static int -tas3004_leave_sleep(struct tas3004_data_t *self) -{ - unsigned char mcr = (1<<6)+(2<<4)+(2<<2); - - if (!self) - return -1; - - /* Make sure something answers on the i2c bus */ - if (tas3004_write_register(self, TAS3004_REG_MCR, &mcr, - WRITE_NORMAL | FORCE_WRITE) < 0) - return -1; - - tas3004_fast_load(self, 1); - - (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD0); - (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD1); - (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD2); - (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD3); - (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD4); - (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD5); - (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD6); - - (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD0); - (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD1); - (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD2); - (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD3); - (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD4); - (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD5); - (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD6); - - tas3004_fast_load(self, 0); - - (void)tas3004_sync_register(self,TAS3004_REG_VOLUME); - (void)tas3004_sync_register(self,TAS3004_REG_LEFT_MIXER); - (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_MIXER); - (void)tas3004_sync_register(self,TAS3004_REG_TREBLE); - (void)tas3004_sync_register(self,TAS3004_REG_BASS); - (void)tas3004_sync_register(self,TAS3004_REG_ANALOG_CTRL); - - return 0; -} - -static int -tas3004_enter_sleep(struct tas3004_data_t *self) -{ - if (!self) - return -1; - return 0; -} - -static int -tas3004_sync_biquad( struct tas3004_data_t *self, - u_int channel, - u_int filter) -{ - enum tas3004_reg_t reg; - - if (channel >= TAS3004_BIQUAD_CHANNEL_COUNT || - filter >= TAS3004_BIQUAD_FILTER_COUNT) return -EINVAL; - - reg=( channel ? TAS3004_REG_RIGHT_BIQUAD0 : TAS3004_REG_LEFT_BIQUAD0 ) + filter; - - return tas3004_sync_register(self,reg); -} - -static int -tas3004_write_biquad_shadow( struct tas3004_data_t *self, - u_int channel, - u_int filter, - const union tas_biquad_t *biquad) -{ - tas_shadow_t *shadow=self->super.shadow; - enum tas3004_reg_t reg; - - if (channel >= TAS3004_BIQUAD_CHANNEL_COUNT || - filter >= TAS3004_BIQUAD_FILTER_COUNT) return -EINVAL; - - reg=( channel ? TAS3004_REG_RIGHT_BIQUAD0 : TAS3004_REG_LEFT_BIQUAD0 ) + filter; - - SET_4_20(shadow[reg], 0,biquad->coeff.b0); - SET_4_20(shadow[reg], 3,biquad->coeff.b1); - SET_4_20(shadow[reg], 6,biquad->coeff.b2); - SET_4_20(shadow[reg], 9,biquad->coeff.a1); - SET_4_20(shadow[reg],12,biquad->coeff.a2); - - return 0; -} - -static int -tas3004_write_biquad( struct tas3004_data_t *self, - u_int channel, - u_int filter, - const union tas_biquad_t *biquad) -{ - int rc; - - rc=tas3004_write_biquad_shadow(self, channel, filter, biquad); - if (rc < 0) return rc; - - return tas3004_sync_biquad(self, channel, filter); -} - -static int -tas3004_write_biquad_list( struct tas3004_data_t *self, - u_int filter_count, - u_int flags, - struct tas_biquad_ctrl_t *biquads) -{ - int i; - int rc; - - if (flags & TAS_BIQUAD_FAST_LOAD) tas3004_fast_load(self,1); - - for (i=0; i<filter_count; i++) { - rc=tas3004_write_biquad(self, - biquads[i].channel, - biquads[i].filter, - &biquads[i].data); - if (rc < 0) break; - } - - if (flags & TAS_BIQUAD_FAST_LOAD) tas3004_fast_load(self,0); - - return rc; -} - -static int -tas3004_read_biquad( struct tas3004_data_t *self, - u_int channel, - u_int filter, - union tas_biquad_t *biquad) -{ - tas_shadow_t *shadow=self->super.shadow; - enum tas3004_reg_t reg; - - if (channel >= TAS3004_BIQUAD_CHANNEL_COUNT || - filter >= TAS3004_BIQUAD_FILTER_COUNT) return -EINVAL; - - reg=( channel ? TAS3004_REG_RIGHT_BIQUAD0 : TAS3004_REG_LEFT_BIQUAD0 ) + filter; - - biquad->coeff.b0=GET_4_20(shadow[reg], 0); - biquad->coeff.b1=GET_4_20(shadow[reg], 3); - biquad->coeff.b2=GET_4_20(shadow[reg], 6); - biquad->coeff.a1=GET_4_20(shadow[reg], 9); - biquad->coeff.a2=GET_4_20(shadow[reg],12); - - return 0; -} - -static int -tas3004_eq_rw( struct tas3004_data_t *self, - u_int cmd, - u_long arg) -{ - void __user *argp = (void __user *)arg; - int rc; - struct tas_biquad_ctrl_t biquad; - - if (copy_from_user((void *)&biquad, argp, sizeof(struct tas_biquad_ctrl_t))) { - return -EFAULT; - } - - if (cmd & SIOC_IN) { - rc=tas3004_write_biquad(self, biquad.channel, biquad.filter, &biquad.data); - if (rc != 0) return rc; - } - - if (cmd & SIOC_OUT) { - rc=tas3004_read_biquad(self, biquad.channel, biquad.filter, &biquad.data); - if (rc != 0) return rc; - - if (copy_to_user(argp, &biquad, sizeof(struct tas_biquad_ctrl_t))) { - return -EFAULT; - } - - } - return 0; -} - -static int -tas3004_eq_list_rw( struct tas3004_data_t *self, - u_int cmd, - u_long arg) -{ - int rc = 0; - int filter_count; - int flags; - int i,j; - char sync_required[TAS3004_BIQUAD_CHANNEL_COUNT][TAS3004_BIQUAD_FILTER_COUNT]; - struct tas_biquad_ctrl_t biquad; - struct tas_biquad_ctrl_list_t __user *argp = (void __user *)arg; - - memset(sync_required,0,sizeof(sync_required)); - - if (copy_from_user(&filter_count, &argp->filter_count, sizeof(int))) - return -EFAULT; - - if (copy_from_user(&flags, &argp->flags, sizeof(int))) - return -EFAULT; - - if (cmd & SIOC_IN) { - } - - for (i=0; i < filter_count; i++) { - if (copy_from_user(&biquad, &argp->biquads[i], - sizeof(struct tas_biquad_ctrl_t))) { - return -EFAULT; - } - - if (cmd & SIOC_IN) { - sync_required[biquad.channel][biquad.filter]=1; - rc=tas3004_write_biquad_shadow(self, biquad.channel, biquad.filter, &biquad.data); - if (rc != 0) return rc; - } - - if (cmd & SIOC_OUT) { - rc=tas3004_read_biquad(self, biquad.channel, biquad.filter, &biquad.data); - if (rc != 0) return rc; - - if (copy_to_user(&argp->biquads[i], &biquad, - sizeof(struct tas_biquad_ctrl_t))) { - return -EFAULT; - } - } - } - - if (cmd & SIOC_IN) { - /* - * This is OK for the tas3004. For the - * tas3001c, going into fast load mode causes - * the treble and bass to be reset to 0dB, and - * volume controls to be muted. - */ - if (flags & TAS_BIQUAD_FAST_LOAD) tas3004_fast_load(self,1); - for (i=0; i<TAS3004_BIQUAD_CHANNEL_COUNT; i++) { - for (j=0; j<TAS3004_BIQUAD_FILTER_COUNT; j++) { - if (sync_required[i][j]) { - rc=tas3004_sync_biquad(self, i, j); - if (rc < 0) goto out; - } - } - } - out: - if (flags & TAS_BIQUAD_FAST_LOAD) - tas3004_fast_load(self,0); - } - - return rc; -} - -static int -tas3004_update_drce( struct tas3004_data_t *self, - int flags, - struct tas_drce_t *drce) -{ - tas_shadow_t *shadow; - int i; - shadow=self->super.shadow; - - if (flags & TAS_DRCE_ABOVE_RATIO) { - self->drce_state.above.expand = drce->above.expand; - if (drce->above.val == (1<<8)) { - self->drce_state.above.val = 1<<8; - shadow[TAS3004_REG_DRC][0] = 0x02; - - } else if (drce->above.expand) { - i=above_threshold_expansion_index(drce->above.val); - self->drce_state.above.val=above_threshold_expansion_ratio[i]; - shadow[TAS3004_REG_DRC][0] = 0x0a + (i<<3); - } else { - i=above_threshold_compression_index(drce->above.val); - self->drce_state.above.val=above_threshold_compression_ratio[i]; - shadow[TAS3004_REG_DRC][0] = 0x08 + (i<<3); - } - } - - if (flags & TAS_DRCE_BELOW_RATIO) { - self->drce_state.below.expand = drce->below.expand; - if (drce->below.val == (1<<8)) { - self->drce_state.below.val = 1<<8; - shadow[TAS3004_REG_DRC][1] = 0x02; - - } else if (drce->below.expand) { - i=below_threshold_expansion_index(drce->below.val); - self->drce_state.below.val=below_threshold_expansion_ratio[i]; - shadow[TAS3004_REG_DRC][1] = 0x08 + (i<<3); - } else { - i=below_threshold_compression_index(drce->below.val); - self->drce_state.below.val=below_threshold_compression_ratio[i]; - shadow[TAS3004_REG_DRC][1] = 0x0a + (i<<3); - } - } - - if (flags & TAS_DRCE_THRESHOLD) { - self->drce_state.threshold=quantize_db(drce->threshold); - shadow[TAS3004_REG_DRC][2] = db_to_regval(self->drce_state.threshold); - } - - if (flags & TAS_DRCE_ENERGY) { - i=time_index(drce->energy); - self->drce_state.energy=time_constants[i]; - shadow[TAS3004_REG_DRC][3] = 0x40 + (i<<4); - } - - if (flags & TAS_DRCE_ATTACK) { - i=time_index(drce->attack); - self->drce_state.attack=time_constants[i]; - shadow[TAS3004_REG_DRC][4] = 0x40 + (i<<4); - } - - if (flags & TAS_DRCE_DECAY) { - i=time_index(drce->decay); - self->drce_state.decay=time_constants[i]; - shadow[TAS3004_REG_DRC][5] = 0x40 + (i<<4); - } - - if (flags & TAS_DRCE_ENABLE) { - self->drce_state.enable = drce->enable; - } - - if (!self->drce_state.enable) { - shadow[TAS3004_REG_DRC][0] |= 0x01; - } - -#ifdef DEBUG_DRCE - printk("DRCE: set [ ENABLE:%x ABOVE:%x/%x BELOW:%x/%x THRESH:%x ENERGY:%x ATTACK:%x DECAY:%x\n", - self->drce_state.enable, - self->drce_state.above.expand,self->drce_state.above.val, - self->drce_state.below.expand,self->drce_state.below.val, - self->drce_state.threshold, - self->drce_state.energy, - self->drce_state.attack, - self->drce_state.decay); - - printk("DRCE: reg [ %02x %02x %02x %02x %02x %02x ]\n", - (unsigned char)shadow[TAS3004_REG_DRC][0], - (unsigned char)shadow[TAS3004_REG_DRC][1], - (unsigned char)shadow[TAS3004_REG_DRC][2], - (unsigned char)shadow[TAS3004_REG_DRC][3], - (unsigned char)shadow[TAS3004_REG_DRC][4], - (unsigned char)shadow[TAS3004_REG_DRC][5]); -#endif - - return tas3004_sync_register(self, TAS3004_REG_DRC); -} - -static int -tas3004_drce_rw( struct tas3004_data_t *self, - u_int cmd, - u_long arg) -{ - int rc; - struct tas_drce_ctrl_t drce_ctrl; - void __user *argp = (void __user *)arg; - - if (copy_from_user(&drce_ctrl, argp, sizeof(struct tas_drce_ctrl_t))) - return -EFAULT; - -#ifdef DEBUG_DRCE - printk("DRCE: input [ FLAGS:%x ENABLE:%x ABOVE:%x/%x BELOW:%x/%x THRESH:%x ENERGY:%x ATTACK:%x DECAY:%x\n", - drce_ctrl.flags, - drce_ctrl.data.enable, - drce_ctrl.data.above.expand,drce_ctrl.data.above.val, - drce_ctrl.data.below.expand,drce_ctrl.data.below.val, - drce_ctrl.data.threshold, - drce_ctrl.data.energy, - drce_ctrl.data.attack, - drce_ctrl.data.decay); -#endif - - if (cmd & SIOC_IN) { - rc = tas3004_update_drce(self, drce_ctrl.flags, &drce_ctrl.data); - if (rc < 0) return rc; - } - - if (cmd & SIOC_OUT) { - if (drce_ctrl.flags & TAS_DRCE_ENABLE) - drce_ctrl.data.enable = self->drce_state.enable; - if (drce_ctrl.flags & TAS_DRCE_ABOVE_RATIO) - drce_ctrl.data.above = self->drce_state.above; - if (drce_ctrl.flags & TAS_DRCE_BELOW_RATIO) - drce_ctrl.data.below = self->drce_state.below; - if (drce_ctrl.flags & TAS_DRCE_THRESHOLD) - drce_ctrl.data.threshold = self->drce_state.threshold; - if (drce_ctrl.flags & TAS_DRCE_ENERGY) - drce_ctrl.data.energy = self->drce_state.energy; - if (drce_ctrl.flags & TAS_DRCE_ATTACK) - drce_ctrl.data.attack = self->drce_state.attack; - if (drce_ctrl.flags & TAS_DRCE_DECAY) - drce_ctrl.data.decay = self->drce_state.decay; - - if (copy_to_user(argp, &drce_ctrl, - sizeof(struct tas_drce_ctrl_t))) { - return -EFAULT; - } - } - - return 0; -} - -static void -tas3004_update_device_parameters(struct tas3004_data_t *self) -{ - char data; - int i; - - if (!self) return; - - if (self->output_id == TAS_OUTPUT_HEADPHONES) { - /* turn on allPass when headphones are plugged in */ - data = 0x02; - } else { - data = 0x00; - } - - tas3004_write_register(self, TAS3004_REG_MCR2, &data, WRITE_NORMAL | FORCE_WRITE); - - for (i=0; tas3004_eq_prefs[i]; i++) { - struct tas_eq_pref_t *eq = tas3004_eq_prefs[i]; - - if (eq->device_id == self->device_id && - (eq->output_id == 0 || eq->output_id == self->output_id) && - (eq->speaker_id == 0 || eq->speaker_id == self->speaker_id)) { - - tas3004_update_drce(self, TAS_DRCE_ALL, eq->drce); - tas3004_write_biquad_list(self, eq->filter_count, TAS_BIQUAD_FAST_LOAD, eq->biquads); - - break; - } - } -} - -static void -tas3004_device_change_handler(struct work_struct *work) -{ - struct tas3004_data_t *self; - self = container_of(work, struct tas3004_data_t, change); - tas3004_update_device_parameters(self); -} - -static int -tas3004_output_device_change( struct tas3004_data_t *self, - int device_id, - int output_id, - int speaker_id) -{ - self->device_id=device_id; - self->output_id=output_id; - self->speaker_id=speaker_id; - - schedule_work(&self->change); - - return 0; -} - -static int -tas3004_device_ioctl( struct tas3004_data_t *self, - u_int cmd, - u_long arg) -{ - uint __user *argp = (void __user *)arg; - switch (cmd) { - case TAS_READ_EQ: - case TAS_WRITE_EQ: - return tas3004_eq_rw(self, cmd, arg); - - case TAS_READ_EQ_LIST: - case TAS_WRITE_EQ_LIST: - return tas3004_eq_list_rw(self, cmd, arg); - - case TAS_READ_EQ_FILTER_COUNT: - put_user(TAS3004_BIQUAD_FILTER_COUNT, argp); - return 0; - - case TAS_READ_EQ_CHANNEL_COUNT: - put_user(TAS3004_BIQUAD_CHANNEL_COUNT, argp); - return 0; - - case TAS_READ_DRCE: - case TAS_WRITE_DRCE: - return tas3004_drce_rw(self, cmd, arg); - - case TAS_READ_DRCE_CAPS: - put_user(TAS_DRCE_ENABLE | - TAS_DRCE_ABOVE_RATIO | - TAS_DRCE_BELOW_RATIO | - TAS_DRCE_THRESHOLD | - TAS_DRCE_ENERGY | - TAS_DRCE_ATTACK | - TAS_DRCE_DECAY, - argp); - return 0; - - case TAS_READ_DRCE_MIN: - case TAS_READ_DRCE_MAX: { - struct tas_drce_ctrl_t drce_ctrl; - const struct tas_drce_t *drce_copy; - - if (copy_from_user(&drce_ctrl, argp, - sizeof(struct tas_drce_ctrl_t))) { - return -EFAULT; - } - - if (cmd == TAS_READ_DRCE_MIN) { - drce_copy=&tas3004_drce_min; - } else { - drce_copy=&tas3004_drce_max; - } - - if (drce_ctrl.flags & TAS_DRCE_ABOVE_RATIO) { - drce_ctrl.data.above=drce_copy->above; - } - if (drce_ctrl.flags & TAS_DRCE_BELOW_RATIO) { - drce_ctrl.data.below=drce_copy->below; - } - if (drce_ctrl.flags & TAS_DRCE_THRESHOLD) { - drce_ctrl.data.threshold=drce_copy->threshold; - } - if (drce_ctrl.flags & TAS_DRCE_ENERGY) { - drce_ctrl.data.energy=drce_copy->energy; - } - if (drce_ctrl.flags & TAS_DRCE_ATTACK) { - drce_ctrl.data.attack=drce_copy->attack; - } - if (drce_ctrl.flags & TAS_DRCE_DECAY) { - drce_ctrl.data.decay=drce_copy->decay; - } - - if (copy_to_user(argp, &drce_ctrl, - sizeof(struct tas_drce_ctrl_t))) { - return -EFAULT; - } - } - } - - return -EINVAL; -} - -static int -tas3004_init_mixer(struct tas3004_data_t *self) -{ - unsigned char mcr = (1<<6)+(2<<4)+(2<<2); - - /* Make sure something answers on the i2c bus */ - if (tas3004_write_register(self, TAS3004_REG_MCR, &mcr, - WRITE_NORMAL | FORCE_WRITE) < 0) - return -1; - - tas3004_fast_load(self, 1); - - (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD0); - (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD1); - (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD2); - (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD3); - (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD4); - (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD5); - (void)tas3004_sync_register(self,TAS3004_REG_RIGHT_BIQUAD6); - - (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD0); - (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD1); - (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD2); - (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD3); - (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD4); - (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD5); - (void)tas3004_sync_register(self,TAS3004_REG_LEFT_BIQUAD6); - - tas3004_sync_register(self, TAS3004_REG_DRC); - - tas3004_sync_register(self, TAS3004_REG_MCR2); - - tas3004_fast_load(self, 0); - - tas3004_set_mixer_level(self, SOUND_MIXER_VOLUME, VOL_DEFAULT<<8 | VOL_DEFAULT); - tas3004_set_mixer_level(self, SOUND_MIXER_PCM, INPUT_DEFAULT<<8 | INPUT_DEFAULT); - tas3004_set_mixer_level(self, SOUND_MIXER_ALTPCM, 0); - tas3004_set_mixer_level(self, SOUND_MIXER_IMIX, 0); - - tas3004_set_mixer_level(self, SOUND_MIXER_BASS, BASS_DEFAULT); - tas3004_set_mixer_level(self, SOUND_MIXER_TREBLE, TREBLE_DEFAULT); - - tas3004_set_mixer_level(self, SOUND_MIXER_LINE,SW_INPUT_VOLUME_DEFAULT); - - return 0; -} - -static int -tas3004_uninit_mixer(struct tas3004_data_t *self) -{ - tas3004_set_mixer_level(self, SOUND_MIXER_VOLUME, 0); - tas3004_set_mixer_level(self, SOUND_MIXER_PCM, 0); - tas3004_set_mixer_level(self, SOUND_MIXER_ALTPCM, 0); - tas3004_set_mixer_level(self, SOUND_MIXER_IMIX, 0); - - tas3004_set_mixer_level(self, SOUND_MIXER_BASS, 0); - tas3004_set_mixer_level(self, SOUND_MIXER_TREBLE, 0); - - tas3004_set_mixer_level(self, SOUND_MIXER_LINE, 0); - - return 0; -} - -static int -tas3004_init(struct i2c_client *client) -{ - struct tas3004_data_t *self; - size_t sz = sizeof(*self) + (TAS3004_REG_MAX*sizeof(tas_shadow_t)); - char drce_init[] = { 0x69, 0x22, 0x9f, 0xb0, 0x60, 0xa0 }; - char mcr2 = 0; - int i, j; - - self = kzalloc(sz, GFP_KERNEL); - if (!self) - return -ENOMEM; - - self->super.client = client; - self->super.shadow = (tas_shadow_t *)(self+1); - self->output_id = TAS_OUTPUT_HEADPHONES; - - dev_set_drvdata(&client->dev, self); - - for (i = 0; i < TAS3004_BIQUAD_CHANNEL_COUNT; i++) - for (j = 0; j<TAS3004_BIQUAD_FILTER_COUNT; j++) - tas3004_write_biquad_shadow(self, i, j, - &tas3004_eq_unity); - - tas3004_write_register(self, TAS3004_REG_MCR2, &mcr2, WRITE_SHADOW); - tas3004_write_register(self, TAS3004_REG_DRC, drce_init, WRITE_SHADOW); - - INIT_WORK(&self->change, tas3004_device_change_handler); - return 0; -} - -static void -tas3004_uninit(struct tas3004_data_t *self) -{ - tas3004_uninit_mixer(self); - kfree(self); -} - - -struct tas_driver_hooks_t tas3004_hooks = { - .init = (tas_hook_init_t)tas3004_init, - .post_init = (tas_hook_post_init_t)tas3004_init_mixer, - .uninit = (tas_hook_uninit_t)tas3004_uninit, - .get_mixer_level = (tas_hook_get_mixer_level_t)tas3004_get_mixer_level, - .set_mixer_level = (tas_hook_set_mixer_level_t)tas3004_set_mixer_level, - .enter_sleep = (tas_hook_enter_sleep_t)tas3004_enter_sleep, - .leave_sleep = (tas_hook_leave_sleep_t)tas3004_leave_sleep, - .supported_mixers = (tas_hook_supported_mixers_t)tas3004_supported_mixers, - .mixer_is_stereo = (tas_hook_mixer_is_stereo_t)tas3004_mixer_is_stereo, - .stereo_mixers = (tas_hook_stereo_mixers_t)tas3004_stereo_mixers, - .output_device_change = (tas_hook_output_device_change_t)tas3004_output_device_change, - .device_ioctl = (tas_hook_device_ioctl_t)tas3004_device_ioctl -}; diff --git a/sound/oss/dmasound/tas3004.h b/sound/oss/dmasound/tas3004.h deleted file mode 100644 index c6d584bf2ca..00000000000 --- a/sound/oss/dmasound/tas3004.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Header file for the i2c/i2s based TA3004 sound chip used - * on some Apple hardware. Also known as "tumbler". - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive - * for more details. - * - * Written by Christopher C. Chimelis <chris@debian.org> - */ - -#ifndef _TAS3004_H_ -#define _TAS3004_H_ - -#include <linux/types.h> - -#include "tas_common.h" -#include "tas_eq_prefs.h" - -/* - * Macros that correspond to the registers that we write to - * when setting the various values. - */ - -#define TAS3004_VERSION "0.3" -#define TAS3004_DATE "20011214" - -#define I2C_DRIVERNAME_TAS3004 "TAS3004 driver V " TAS3004_VERSION -#define I2C_DRIVERID_TAS3004 (I2C_DRIVERID_TAS_BASE+1) - -extern struct tas_driver_hooks_t tas3004_hooks; -extern struct tas_gain_t tas3004_gain; -extern struct tas_eq_pref_t *tas3004_eq_prefs[]; - -enum tas3004_reg_t { - TAS3004_REG_MCR = 0x01, - TAS3004_REG_DRC = 0x02, - - TAS3004_REG_VOLUME = 0x04, - TAS3004_REG_TREBLE = 0x05, - TAS3004_REG_BASS = 0x06, - TAS3004_REG_LEFT_MIXER = 0x07, - TAS3004_REG_RIGHT_MIXER = 0x08, - - TAS3004_REG_LEFT_BIQUAD0 = 0x0a, - TAS3004_REG_LEFT_BIQUAD1 = 0x0b, - TAS3004_REG_LEFT_BIQUAD2 = 0x0c, - TAS3004_REG_LEFT_BIQUAD3 = 0x0d, - TAS3004_REG_LEFT_BIQUAD4 = 0x0e, - TAS3004_REG_LEFT_BIQUAD5 = 0x0f, - TAS3004_REG_LEFT_BIQUAD6 = 0x10, - - TAS3004_REG_RIGHT_BIQUAD0 = 0x13, - TAS3004_REG_RIGHT_BIQUAD1 = 0x14, - TAS3004_REG_RIGHT_BIQUAD2 = 0x15, - TAS3004_REG_RIGHT_BIQUAD3 = 0x16, - TAS3004_REG_RIGHT_BIQUAD4 = 0x17, - TAS3004_REG_RIGHT_BIQUAD5 = 0x18, - TAS3004_REG_RIGHT_BIQUAD6 = 0x19, - - TAS3004_REG_LEFT_LOUD_BIQUAD = 0x21, - TAS3004_REG_RIGHT_LOUD_BIQUAD = 0x22, - - TAS3004_REG_LEFT_LOUD_BIQUAD_GAIN = 0x23, - TAS3004_REG_RIGHT_LOUD_BIQUAD_GAIN = 0x24, - - TAS3004_REG_TEST = 0x29, - - TAS3004_REG_ANALOG_CTRL = 0x40, - TAS3004_REG_TEST1 = 0x41, - TAS3004_REG_TEST2 = 0x42, - TAS3004_REG_MCR2 = 0x43, - - TAS3004_REG_MAX = 0x44 -}; - -#endif /* _TAS3004_H_ */ diff --git a/sound/oss/dmasound/tas3004_tables.c b/sound/oss/dmasound/tas3004_tables.c deleted file mode 100644 index b910e0a6677..00000000000 --- a/sound/oss/dmasound/tas3004_tables.c +++ /dev/null @@ -1,301 +0,0 @@ -#include "tas3004.h" -#include "tas_eq_prefs.h" - -static struct tas_drce_t eqp_17_1_0_drce={ - .enable = 1, - .above = { .val = 3.0 * (1<<8), .expand = 0 }, - .below = { .val = 1.0 * (1<<8), .expand = 0 }, - .threshold = -19.12 * (1<<8), - .energy = 2.4 * (1<<12), - .attack = 0.013 * (1<<12), - .decay = 0.212 * (1<<12), -}; - -static struct tas_biquad_ctrl_t eqp_17_1_0_biquads[]={ - { .channel = 0, .filter = 0, .data = { .coeff = { 0x0fd0d4, 0xe05e56, 0x0fd0d4, 0xe05ee1, 0x0fa234 } } }, - { .channel = 0, .filter = 1, .data = { .coeff = { 0x0910d7, 0x088e1a, 0x030651, 0x01dcb1, 0x02c892 } } }, - { .channel = 0, .filter = 2, .data = { .coeff = { 0x0ff895, 0xe0970b, 0x0f7f00, 0xe0970b, 0x0f7795 } } }, - { .channel = 0, .filter = 3, .data = { .coeff = { 0x0fd1c4, 0xe1ac22, 0x0ec8cf, 0xe1ac22, 0x0e9a94 } } }, - { .channel = 0, .filter = 4, .data = { .coeff = { 0x0f7c1c, 0xe3cc03, 0x0df786, 0xe3cc03, 0x0d73a2 } } }, - { .channel = 0, .filter = 5, .data = { .coeff = { 0x11fb92, 0xf5a1a0, 0x073cd2, 0xf5a1a0, 0x093865 } } }, - { .channel = 0, .filter = 6, .data = { .coeff = { 0x0e17a9, 0x068b6c, 0x08a0e5, 0x068b6c, 0x06b88e } } }, - - { .channel = 1, .filter = 0, .data = { .coeff = { 0x0fd0d4, 0xe05e56, 0x0fd0d4, 0xe05ee1, 0x0fa234 } } }, - { .channel = 1, .filter = 1, .data = { .coeff = { 0x0910d7, 0x088e1a, 0x030651, 0x01dcb1, 0x02c892 } } }, - { .channel = 1, .filter = 2, .data = { .coeff = { 0x0ff895, 0xe0970b, 0x0f7f00, 0xe0970b, 0x0f7795 } } }, - { .channel = 1, .filter = 3, .data = { .coeff = { 0x0fd1c4, 0xe1ac22, 0x0ec8cf, 0xe1ac22, 0x0e9a94 } } }, - { .channel = 1, .filter = 4, .data = { .coeff = { 0x0f7c1c, 0xe3cc03, 0x0df786, 0xe3cc03, 0x0d73a2 } } }, - { .channel = 1, .filter = 5, .data = { .coeff = { 0x11fb92, 0xf5a1a0, 0x073cd2, 0xf5a1a0, 0x093865 } } }, - { .channel = 1, .filter = 6, .data = { .coeff = { 0x0e17a9, 0x068b6c, 0x08a0e5, 0x068b6c, 0x06b88e } } } -}; - -static struct tas_eq_pref_t eqp_17_1_0 = { - .sample_rate = 44100, - .device_id = 0x17, - .output_id = TAS_OUTPUT_INTERNAL_SPKR, - .speaker_id = 0x00, - - .drce = &eqp_17_1_0_drce, - - .filter_count = 14, - .biquads = eqp_17_1_0_biquads -}; - -/* ======================================================================== */ - -static struct tas_drce_t eqp_18_1_0_drce={ - .enable = 1, - .above = { .val = 3.0 * (1<<8), .expand = 0 }, - .below = { .val = 1.0 * (1<<8), .expand = 0 }, - .threshold = -13.14 * (1<<8), - .energy = 2.4 * (1<<12), - .attack = 0.013 * (1<<12), - .decay = 0.212 * (1<<12), -}; - -static struct tas_biquad_ctrl_t eqp_18_1_0_biquads[]={ - { .channel = 0, .filter = 0, .data = { .coeff = { 0x0f5514, 0xe155d7, 0x0f5514, 0xe15cfa, 0x0eb14b } } }, - { .channel = 0, .filter = 1, .data = { .coeff = { 0x06ec33, 0x02abe3, 0x015eef, 0xf764d9, 0x03922d } } }, - { .channel = 0, .filter = 2, .data = { .coeff = { 0x0ef5f2, 0xe67d1f, 0x0bcf37, 0xe67d1f, 0x0ac529 } } }, - { .channel = 0, .filter = 3, .data = { .coeff = { 0x0db050, 0xe5be4d, 0x0d0c78, 0xe5be4d, 0x0abcc8 } } }, - { .channel = 0, .filter = 4, .data = { .coeff = { 0x0f1298, 0xe64ec6, 0x0cc03e, 0xe64ec6, 0x0bd2d7 } } }, - { .channel = 0, .filter = 5, .data = { .coeff = { 0x0c641a, 0x06537a, 0x08d155, 0x06537a, 0x053570 } } }, - { .channel = 0, .filter = 6, .data = { .coeff = { 0x100000, 0x000000, 0x000000, 0x000000, 0x000000 } } }, - - { .channel = 1, .filter = 0, .data = { .coeff = { 0x0f5514, 0xe155d7, 0x0f5514, 0xe15cfa, 0x0eb14b } } }, - { .channel = 1, .filter = 1, .data = { .coeff = { 0x06ec33, 0x02abe3, 0x015eef, 0xf764d9, 0x03922d } } }, - { .channel = 1, .filter = 2, .data = { .coeff = { 0x0ef5f2, 0xe67d1f, 0x0bcf37, 0xe67d1f, 0x0ac529 } } }, - { .channel = 1, .filter = 3, .data = { .coeff = { 0x0db050, 0xe5be4d, 0x0d0c78, 0xe5be4d, 0x0abcc8 } } }, - { .channel = 1, .filter = 4, .data = { .coeff = { 0x0f1298, 0xe64ec6, 0x0cc03e, 0xe64ec6, 0x0bd2d7 } } }, - { .channel = 1, .filter = 5, .data = { .coeff = { 0x0c641a, 0x06537a, 0x08d155, 0x06537a, 0x053570 } } }, - { .channel = 1, .filter = 6, .data = { .coeff = { 0x100000, 0x000000, 0x000000, 0x000000, 0x000000 } } } -}; - -static struct tas_eq_pref_t eqp_18_1_0 = { - .sample_rate = 44100, - .device_id = 0x18, - .output_id = TAS_OUTPUT_INTERNAL_SPKR, - .speaker_id = 0x00, - - .drce = &eqp_18_1_0_drce, - - .filter_count = 14, - .biquads = eqp_18_1_0_biquads -}; - -/* ======================================================================== */ - -static struct tas_drce_t eqp_1a_1_0_drce={ - .enable = 1, - .above = { .val = 3.0 * (1<<8), .expand = 0 }, - .below = { .val = 1.0 * (1<<8), .expand = 0 }, - .threshold = -10.75 * (1<<8), - .energy = 2.4 * (1<<12), - .attack = 0.013 * (1<<12), - .decay = 0.212 * (1<<12), -}; - -static struct tas_biquad_ctrl_t eqp_1a_1_0_biquads[]={ - { .channel = 0, .filter = 0, .data = { .coeff = { 0x0fb8fd, 0xe08e04, 0x0fb8fd, 0xe08f40, 0x0f7336 } } }, - { .channel = 0, .filter = 1, .data = { .coeff = { 0x06371d, 0x0c6e3a, 0x06371d, 0x05bfd3, 0x031ca2 } } }, - { .channel = 0, .filter = 2, .data = { .coeff = { 0x0fa1c0, 0xe18692, 0x0f030e, 0xe18692, 0x0ea4ce } } }, - { .channel = 0, .filter = 3, .data = { .coeff = { 0x0fe495, 0xe17eff, 0x0f0452, 0xe17eff, 0x0ee8e7 } } }, - { .channel = 0, .filter = 4, .data = { .coeff = { 0x100857, 0xe7e71c, 0x0e9599, 0xe7e71c, 0x0e9df1 } } }, - { .channel = 0, .filter = 5, .data = { .coeff = { 0x0fb26e, 0x06a82c, 0x0db2b4, 0x06a82c, 0x0d6522 } } }, - { .channel = 0, .filter = 6, .data = { .coeff = { 0x11419d, 0xf06cbf, 0x0a4f6e, 0xf06cbf, 0x0b910c } } }, - - { .channel = 1, .filter = 0, .data = { .coeff = { 0x0fb8fd, 0xe08e04, 0x0fb8fd, 0xe08f40, 0x0f7336 } } }, - { .channel = 1, .filter = 1, .data = { .coeff = { 0x06371d, 0x0c6e3a, 0x06371d, 0x05bfd3, 0x031ca2 } } }, - { .channel = 1, .filter = 2, .data = { .coeff = { 0x0fa1c0, 0xe18692, 0x0f030e, 0xe18692, 0x0ea4ce } } }, - { .channel = 1, .filter = 3, .data = { .coeff = { 0x0fe495, 0xe17eff, 0x0f0452, 0xe17eff, 0x0ee8e7 } } }, - { .channel = 1, .filter = 4, .data = { .coeff = { 0x100857, 0xe7e71c, 0x0e9599, 0xe7e71c, 0x0e9df1 } } }, - { .channel = 1, .filter = 5, .data = { .coeff = { 0x0fb26e, 0x06a82c, 0x0db2b4, 0x06a82c, 0x0d6522 } } }, - { .channel = 1, .filter = 6, .data = { .coeff = { 0x11419d, 0xf06cbf, 0x0a4f6e, 0xf06cbf, 0x0b910c } } } -}; - -static struct tas_eq_pref_t eqp_1a_1_0 = { - .sample_rate = 44100, - .device_id = 0x1a, - .output_id = TAS_OUTPUT_INTERNAL_SPKR, - .speaker_id = 0x00, - - .drce = &eqp_1a_1_0_drce, - - .filter_count = 14, - .biquads = eqp_1a_1_0_biquads -}; - -/* ======================================================================== */ - -static struct tas_drce_t eqp_1c_1_0_drce={ - .enable = 1, - .above = { .val = 3.0 * (1<<8), .expand = 0 }, - .below = { .val = 1.0 * (1<<8), .expand = 0 }, - .threshold = -14.34 * (1<<8), - .energy = 2.4 * (1<<12), - .attack = 0.013 * (1<<12), - .decay = 0.212 * (1<<12), -}; - -static struct tas_biquad_ctrl_t eqp_1c_1_0_biquads[]={ - { .channel = 0, .filter = 0, .data = { .coeff = { 0x0f4f95, 0xe160d4, 0x0f4f95, 0xe1686e, 0x0ea6c5 } } }, - { .channel = 0, .filter = 1, .data = { .coeff = { 0x066b92, 0x0290d4, 0x0148a0, 0xf6853f, 0x03bfc7 } } }, - { .channel = 0, .filter = 2, .data = { .coeff = { 0x0f57dc, 0xe51c91, 0x0dd1cb, 0xe51c91, 0x0d29a8 } } }, - { .channel = 0, .filter = 3, .data = { .coeff = { 0x0df1cb, 0xe4fa84, 0x0d7cdc, 0xe4fa84, 0x0b6ea7 } } }, - { .channel = 0, .filter = 4, .data = { .coeff = { 0x0eba36, 0xe6aa48, 0x0b9f52, 0xe6aa48, 0x0a5989 } } }, - { .channel = 0, .filter = 5, .data = { .coeff = { 0x0caf02, 0x05ef9d, 0x084beb, 0x05ef9d, 0x04faee } } }, - { .channel = 0, .filter = 6, .data = { .coeff = { 0x0fc686, 0xe22947, 0x0e4b5d, 0xe22947, 0x0e11e4 } } }, - - { .channel = 1, .filter = 0, .data = { .coeff = { 0x0f4f95, 0xe160d4, 0x0f4f95, 0xe1686e, 0x0ea6c5 } } }, - { .channel = 1, .filter = 1, .data = { .coeff = { 0x066b92, 0x0290d4, 0x0148a0, 0xf6853f, 0x03bfc7 } } }, - { .channel = 1, .filter = 2, .data = { .coeff = { 0x0f57dc, 0xe51c91, 0x0dd1cb, 0xe51c91, 0x0d29a8 } } }, - { .channel = 1, .filter = 3, .data = { .coeff = { 0x0df1cb, 0xe4fa84, 0x0d7cdc, 0xe4fa84, 0x0b6ea7 } } }, - { .channel = 1, .filter = 4, .data = { .coeff = { 0x0eba36, 0xe6aa48, 0x0b9f52, 0xe6aa48, 0x0a5989 } } }, - { .channel = 1, .filter = 5, .data = { .coeff = { 0x0caf02, 0x05ef9d, 0x084beb, 0x05ef9d, 0x04faee } } }, - { .channel = 1, .filter = 6, .data = { .coeff = { 0x0fc686, 0xe22947, 0x0e4b5d, 0xe22947, 0x0e11e4 } } } -}; - -static struct tas_eq_pref_t eqp_1c_1_0 = { - .sample_rate = 44100, - .device_id = 0x1c, - .output_id = TAS_OUTPUT_INTERNAL_SPKR, - .speaker_id = 0x00, - - .drce = &eqp_1c_1_0_drce, - - .filter_count = 14, - .biquads = eqp_1c_1_0_biquads -}; - -/* ======================================================================== */ - -static uint tas3004_master_tab[]={ - 0x0, 0x75, 0x9c, 0xbb, - 0xdb, 0xfb, 0x11e, 0x143, - 0x16b, 0x196, 0x1c3, 0x1f5, - 0x229, 0x263, 0x29f, 0x2e1, - 0x328, 0x373, 0x3c5, 0x41b, - 0x478, 0x4dc, 0x547, 0x5b8, - 0x633, 0x6b5, 0x740, 0x7d5, - 0x873, 0x91c, 0x9d2, 0xa92, - 0xb5e, 0xc39, 0xd22, 0xe19, - 0xf20, 0x1037, 0x1161, 0x129e, - 0x13ed, 0x1551, 0x16ca, 0x185d, - 0x1a08, 0x1bcc, 0x1dac, 0x1fa7, - 0x21c1, 0x23fa, 0x2655, 0x28d6, - 0x2b7c, 0x2e4a, 0x3141, 0x3464, - 0x37b4, 0x3b35, 0x3ee9, 0x42d3, - 0x46f6, 0x4b53, 0x4ff0, 0x54ce, - 0x59f2, 0x5f5f, 0x6519, 0x6b24, - 0x7183, 0x783c, 0x7f53, 0x86cc, - 0x8ead, 0x96fa, 0x9fba, 0xa8f2, - 0xb2a7, 0xbce1, 0xc7a5, 0xd2fa, - 0xdee8, 0xeb75, 0xf8aa, 0x1068e, - 0x1152a, 0x12487, 0x134ad, 0x145a5, - 0x1577b, 0x16a37, 0x17df5, 0x192bd, - 0x1a890, 0x1bf7b, 0x1d78d, 0x1f0d1, - 0x20b55, 0x22727, 0x24456, 0x262f2, - 0x2830b -}; - -static uint tas3004_mixer_tab[]={ - 0x0, 0x748, 0x9be, 0xbaf, - 0xda4, 0xfb1, 0x11de, 0x1431, - 0x16ad, 0x1959, 0x1c37, 0x1f4b, - 0x2298, 0x2628, 0x29fb, 0x2e12, - 0x327d, 0x3734, 0x3c47, 0x41b4, - 0x4787, 0x4dbe, 0x546d, 0x5b86, - 0x632e, 0x6b52, 0x7400, 0x7d54, - 0x873b, 0x91c6, 0x9d1a, 0xa920, - 0xb5e5, 0xc38c, 0xd21b, 0xe18f, - 0xf1f5, 0x1036a, 0x1160f, 0x129d6, - 0x13ed0, 0x1550c, 0x16ca0, 0x185c9, - 0x1a07b, 0x1bcc3, 0x1dab9, 0x1fa75, - 0x21c0f, 0x23fa3, 0x26552, 0x28d64, - 0x2b7c9, 0x2e4a2, 0x31411, 0x3463b, - 0x37b44, 0x3b353, 0x3ee94, 0x42d30, - 0x46f55, 0x4b533, 0x4fefc, 0x54ce5, - 0x59f25, 0x5f5f6, 0x65193, 0x6b23c, - 0x71835, 0x783c3, 0x7f52c, 0x86cc0, - 0x8eacc, 0x96fa5, 0x9fba0, 0xa8f1a, - 0xb2a71, 0xbce0a, 0xc7a4a, 0xd2fa0, - 0xdee7b, 0xeb752, 0xf8a9f, 0x1068e4, - 0x1152a3, 0x12486a, 0x134ac8, 0x145a55, - 0x1577ac, 0x16a370, 0x17df51, 0x192bc2, - 0x1a88f8, 0x1bf7b7, 0x1d78c9, 0x1f0d04, - 0x20b542, 0x227268, 0x244564, 0x262f26, - 0x2830af -}; - -static uint tas3004_treble_tab[]={ - 0x96, 0x95, 0x95, 0x94, - 0x93, 0x92, 0x92, 0x91, - 0x90, 0x90, 0x8f, 0x8e, - 0x8d, 0x8d, 0x8c, 0x8b, - 0x8a, 0x8a, 0x89, 0x88, - 0x88, 0x87, 0x86, 0x85, - 0x85, 0x84, 0x83, 0x83, - 0x82, 0x81, 0x80, 0x80, - 0x7f, 0x7e, 0x7e, 0x7d, - 0x7c, 0x7b, 0x7b, 0x7a, - 0x79, 0x78, 0x78, 0x77, - 0x76, 0x76, 0x75, 0x74, - 0x73, 0x73, 0x72, 0x71, - 0x71, 0x68, 0x45, 0x5b, - 0x6d, 0x6c, 0x6b, 0x6a, - 0x69, 0x68, 0x67, 0x66, - 0x65, 0x63, 0x62, 0x62, - 0x60, 0x5e, 0x5c, 0x5b, - 0x59, 0x57, 0x55, 0x53, - 0x52, 0x4f, 0x4d, 0x4a, - 0x48, 0x46, 0x43, 0x40, - 0x3d, 0x3a, 0x36, 0x33, - 0x2f, 0x2c, 0x27, 0x23, - 0x1f, 0x1a, 0x15, 0xf, - 0x8, 0x5, 0x2, 0x1, - 0x1 -}; - -static uint tas3004_bass_tab[]={ - 0x96, 0x95, 0x95, 0x94, - 0x93, 0x92, 0x92, 0x91, - 0x90, 0x90, 0x8f, 0x8e, - 0x8d, 0x8d, 0x8c, 0x8b, - 0x8a, 0x8a, 0x89, 0x88, - 0x88, 0x87, 0x86, 0x85, - 0x85, 0x84, 0x83, 0x83, - 0x82, 0x81, 0x80, 0x80, - 0x7f, 0x7e, 0x7e, 0x7d, - 0x7c, 0x7b, 0x7b, 0x7a, - 0x79, 0x78, 0x78, 0x77, - 0x76, 0x76, 0x75, 0x74, - 0x73, 0x73, 0x72, 0x71, - 0x70, 0x6f, 0x6e, 0x6d, - 0x6c, 0x6b, 0x6a, 0x6a, - 0x69, 0x67, 0x66, 0x66, - 0x65, 0x63, 0x62, 0x62, - 0x61, 0x60, 0x5e, 0x5d, - 0x5b, 0x59, 0x57, 0x55, - 0x53, 0x51, 0x4f, 0x4c, - 0x4a, 0x48, 0x46, 0x44, - 0x41, 0x3e, 0x3b, 0x38, - 0x36, 0x33, 0x2f, 0x2b, - 0x28, 0x24, 0x20, 0x1c, - 0x17, 0x12, 0xd, 0x7, - 0x1 -}; - -struct tas_gain_t tas3004_gain={ - .master = tas3004_master_tab, - .treble = tas3004_treble_tab, - .bass = tas3004_bass_tab, - .mixer = tas3004_mixer_tab -}; - -struct tas_eq_pref_t *tas3004_eq_prefs[]={ - &eqp_17_1_0, - &eqp_18_1_0, - &eqp_1a_1_0, - &eqp_1c_1_0, - NULL -}; diff --git a/sound/oss/dmasound/tas_common.c b/sound/oss/dmasound/tas_common.c deleted file mode 100644 index b295ef68219..00000000000 --- a/sound/oss/dmasound/tas_common.c +++ /dev/null @@ -1,214 +0,0 @@ -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/proc_fs.h> -#include <linux/ioport.h> -#include <linux/sysctl.h> -#include <linux/types.h> -#include <linux/i2c.h> -#include <linux/init.h> -#include <linux/soundcard.h> -#include <asm/uaccess.h> -#include <asm/errno.h> -#include <asm/io.h> -#include <asm/prom.h> - -#include "tas_common.h" - -#define CALL0(proc) \ - do { \ - struct tas_data_t *self; \ - if (!tas_client || driver_hooks == NULL) \ - return -1; \ - self = dev_get_drvdata(&tas_client->dev); \ - if (driver_hooks->proc) \ - return driver_hooks->proc(self); \ - else \ - return -EINVAL; \ - } while (0) - -#define CALL(proc,arg...) \ - do { \ - struct tas_data_t *self; \ - if (!tas_client || driver_hooks == NULL) \ - return -1; \ - self = dev_get_drvdata(&tas_client->dev); \ - if (driver_hooks->proc) \ - return driver_hooks->proc(self, ## arg); \ - else \ - return -EINVAL; \ - } while (0) - - -static u8 tas_i2c_address = 0x34; -static struct i2c_client *tas_client; - -static int tas_attach_adapter(struct i2c_adapter *); -static int tas_detach_client(struct i2c_client *); - -struct i2c_driver tas_driver = { - .driver = { - .name = "tas", - }, - .attach_adapter = tas_attach_adapter, - .detach_client = tas_detach_client, -}; - -struct tas_driver_hooks_t *driver_hooks; - -int -tas_register_driver(struct tas_driver_hooks_t *hooks) -{ - driver_hooks = hooks; - return 0; -} - -int -tas_get_mixer_level(int mixer, uint *level) -{ - CALL(get_mixer_level,mixer,level); -} - -int -tas_set_mixer_level(int mixer,uint level) -{ - CALL(set_mixer_level,mixer,level); -} - -int -tas_enter_sleep(void) -{ - CALL0(enter_sleep); -} - -int -tas_leave_sleep(void) -{ - CALL0(leave_sleep); -} - -int -tas_supported_mixers(void) -{ - CALL0(supported_mixers); -} - -int -tas_mixer_is_stereo(int mixer) -{ - CALL(mixer_is_stereo,mixer); -} - -int -tas_stereo_mixers(void) -{ - CALL0(stereo_mixers); -} - -int -tas_output_device_change(int device_id,int layout_id,int speaker_id) -{ - CALL(output_device_change,device_id,layout_id,speaker_id); -} - -int -tas_device_ioctl(u_int cmd, u_long arg) -{ - CALL(device_ioctl,cmd,arg); -} - -int -tas_post_init(void) -{ - CALL0(post_init); -} - -static int -tas_detect_client(struct i2c_adapter *adapter, int address) -{ - static const char *client_name = "tas Digital Equalizer"; - struct i2c_client *new_client; - int rc = -ENODEV; - - if (!driver_hooks) { - printk(KERN_ERR "tas_detect_client called with no hooks !\n"); - return -ENODEV; - } - - new_client = kzalloc(sizeof(*new_client), GFP_KERNEL); - if (!new_client) - return -ENOMEM; - - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &tas_driver; - strlcpy(new_client->name, client_name, DEVICE_NAME_SIZE); - - if (driver_hooks->init(new_client)) - goto bail; - - /* Tell the i2c layer a new client has arrived */ - if (i2c_attach_client(new_client)) { - driver_hooks->uninit(dev_get_drvdata(&new_client->dev)); - goto bail; - } - - tas_client = new_client; - return 0; - bail: - tas_client = NULL; - kfree(new_client); - return rc; -} - -static int -tas_attach_adapter(struct i2c_adapter *adapter) -{ - if (!strncmp(adapter->name, "mac-io", 6)) - return tas_detect_client(adapter, tas_i2c_address); - return 0; -} - -static int -tas_detach_client(struct i2c_client *client) -{ - if (client == tas_client) { - driver_hooks->uninit(dev_get_drvdata(&client->dev)); - - i2c_detach_client(client); - kfree(client); - } - return 0; -} - -void -tas_cleanup(void) -{ - i2c_del_driver(&tas_driver); -} - -int __init -tas_init(int driver_id, const char *driver_name) -{ - const u32* paddr; - struct device_node *tas_node; - - printk(KERN_INFO "tas driver [%s])\n", driver_name); - -#ifndef CONFIG_I2C_POWERMAC - request_module("i2c-powermac"); -#endif - tas_node = of_find_node_by_name("deq"); - if (tas_node == NULL) - return -ENODEV; - paddr = of_get_property(tas_node, "i2c-address", NULL); - if (paddr) { - tas_i2c_address = (*paddr) >> 1; - printk(KERN_INFO "using i2c address: 0x%x from device-tree\n", - tas_i2c_address); - } else - printk(KERN_INFO "using i2c address: 0x%x (default)\n", - tas_i2c_address); - of_node_put(tas_node); - - return i2c_add_driver(&tas_driver); -} diff --git a/sound/oss/dmasound/tas_common.h b/sound/oss/dmasound/tas_common.h deleted file mode 100644 index 0741c28e56c..00000000000 --- a/sound/oss/dmasound/tas_common.h +++ /dev/null @@ -1,284 +0,0 @@ -#ifndef _TAS_COMMON_H_ -#define _TAS_COMMON_H_ - -#include <linux/i2c.h> -#include <linux/soundcard.h> -#include <asm/string.h> - -#define I2C_DRIVERID_TAS_BASE (0xFEBA) - -#define SET_4_20(shadow, offset, val) \ - do { \ - (shadow)[(offset)+0] = ((val) >> 16) & 0xff; \ - (shadow)[(offset)+1] = ((val) >> 8) & 0xff; \ - (shadow)[(offset)+2] = ((val) >> 0) & 0xff; \ - } while (0) - -#define GET_4_20(shadow, offset) \ - (((u_int)((shadow)[(offset)+0]) << 16) | \ - ((u_int)((shadow)[(offset)+1]) << 8) | \ - ((u_int)((shadow)[(offset)+2]) << 0)) - - -#define TAS_BIQUAD_FAST_LOAD 0x01 - -#define TAS_DRCE_ENABLE 0x01 -#define TAS_DRCE_ABOVE_RATIO 0x02 -#define TAS_DRCE_BELOW_RATIO 0x04 -#define TAS_DRCE_THRESHOLD 0x08 -#define TAS_DRCE_ENERGY 0x10 -#define TAS_DRCE_ATTACK 0x20 -#define TAS_DRCE_DECAY 0x40 - -#define TAS_DRCE_ALL 0x7f - - -#define TAS_OUTPUT_HEADPHONES 0x00 -#define TAS_OUTPUT_INTERNAL_SPKR 0x01 -#define TAS_OUTPUT_EXTERNAL_SPKR 0x02 - - -union tas_biquad_t { - struct { - int b0,b1,b2,a1,a2; - } coeff; - int buf[5]; -}; - -struct tas_biquad_ctrl_t { - u_int channel:4; - u_int filter:4; - - union tas_biquad_t data; -}; - -struct tas_biquad_ctrl_list_t { - int flags; - int filter_count; - struct tas_biquad_ctrl_t biquads[0]; -}; - -struct tas_ratio_t { - unsigned short val; /* 8.8 */ - unsigned short expand; /* 0 = compress, !0 = expand. */ -}; - -struct tas_drce_t { - unsigned short enable; - struct tas_ratio_t above; - struct tas_ratio_t below; - short threshold; /* dB, 8.8 signed */ - unsigned short energy; /* seconds, 4.12 unsigned */ - unsigned short attack; /* seconds, 4.12 unsigned */ - unsigned short decay; /* seconds, 4.12 unsigned */ -}; - -struct tas_drce_ctrl_t { - uint flags; - - struct tas_drce_t data; -}; - -struct tas_gain_t -{ - unsigned int *master; - unsigned int *treble; - unsigned int *bass; - unsigned int *mixer; -}; - -typedef char tas_shadow_t[0x45]; - -struct tas_data_t -{ - struct i2c_client *client; - tas_shadow_t *shadow; - uint mixer[SOUND_MIXER_NRDEVICES]; -}; - -typedef int (*tas_hook_init_t)(struct i2c_client *); -typedef int (*tas_hook_post_init_t)(struct tas_data_t *); -typedef void (*tas_hook_uninit_t)(struct tas_data_t *); - -typedef int (*tas_hook_get_mixer_level_t)(struct tas_data_t *,int,uint *); -typedef int (*tas_hook_set_mixer_level_t)(struct tas_data_t *,int,uint); - -typedef int (*tas_hook_enter_sleep_t)(struct tas_data_t *); -typedef int (*tas_hook_leave_sleep_t)(struct tas_data_t *); - -typedef int (*tas_hook_supported_mixers_t)(struct tas_data_t *); -typedef int (*tas_hook_mixer_is_stereo_t)(struct tas_data_t *,int); -typedef int (*tas_hook_stereo_mixers_t)(struct tas_data_t *); - -typedef int (*tas_hook_output_device_change_t)(struct tas_data_t *,int,int,int); -typedef int (*tas_hook_device_ioctl_t)(struct tas_data_t *,u_int,u_long); - -struct tas_driver_hooks_t { - /* - * All hardware initialisation must be performed in - * post_init(), as tas_dmasound_init() does a hardware reset. - * - * init() is called before tas_dmasound_init() so that - * ouput_device_change() is always called after i2c driver - * initialisation. The implication is that - * output_device_change() must cope with the fact that it - * may be called before post_init(). - */ - - tas_hook_init_t init; - tas_hook_post_init_t post_init; - tas_hook_uninit_t uninit; - - tas_hook_get_mixer_level_t get_mixer_level; - tas_hook_set_mixer_level_t set_mixer_level; - - tas_hook_enter_sleep_t enter_sleep; - tas_hook_leave_sleep_t leave_sleep; - - tas_hook_supported_mixers_t supported_mixers; - tas_hook_mixer_is_stereo_t mixer_is_stereo; - tas_hook_stereo_mixers_t stereo_mixers; - - tas_hook_output_device_change_t output_device_change; - tas_hook_device_ioctl_t device_ioctl; -}; - -enum tas_write_mode_t { - WRITE_HW = 0x01, - WRITE_SHADOW = 0x02, - WRITE_NORMAL = 0x03, - FORCE_WRITE = 0x04 -}; - -static inline uint -tas_mono_to_stereo(uint mono) -{ - mono &=0xff; - return mono | (mono<<8); -} - -/* - * Todo: make these functions a bit more efficient ! - */ -static inline int -tas_write_register( struct tas_data_t *self, - uint reg_num, - uint reg_width, - char *data, - uint write_mode) -{ - int rc; - - if (reg_width==0 || data==NULL || self==NULL) - return -EINVAL; - if (!(write_mode & FORCE_WRITE) && - !memcmp(data,self->shadow[reg_num],reg_width)) - return 0; - - if (write_mode & WRITE_SHADOW) - memcpy(self->shadow[reg_num],data,reg_width); - if (write_mode & WRITE_HW) { - rc=i2c_smbus_write_i2c_block_data(self->client, - reg_num, - reg_width, - data); - if (rc < 0) { - printk("tas: I2C block write failed \n"); - return rc; - } - } - return 0; -} - -static inline int -tas_sync_register( struct tas_data_t *self, - uint reg_num, - uint reg_width) -{ - int rc; - - if (reg_width==0 || self==NULL) - return -EINVAL; - rc=i2c_smbus_write_i2c_block_data(self->client, - reg_num, - reg_width, - self->shadow[reg_num]); - if (rc < 0) { - printk("tas: I2C block write failed \n"); - return rc; - } - return 0; -} - -static inline int -tas_write_byte_register( struct tas_data_t *self, - uint reg_num, - char data, - uint write_mode) -{ - if (self==NULL) - return -1; - if (!(write_mode & FORCE_WRITE) && data != self->shadow[reg_num][0]) - return 0; - if (write_mode & WRITE_SHADOW) - self->shadow[reg_num][0]=data; - if (write_mode & WRITE_HW) { - if (i2c_smbus_write_byte_data(self->client, reg_num, data) < 0) { - printk("tas: I2C byte write failed \n"); - return -1; - } - } - return 0; -} - -static inline int -tas_sync_byte_register( struct tas_data_t *self, - uint reg_num, - uint reg_width) -{ - if (reg_width==0 || self==NULL) - return -1; - if (i2c_smbus_write_byte_data( - self->client, reg_num, self->shadow[reg_num][0]) < 0) { - printk("tas: I2C byte write failed \n"); - return -1; - } - return 0; -} - -static inline int -tas_read_register( struct tas_data_t *self, - uint reg_num, - uint reg_width, - char *data) -{ - if (reg_width==0 || data==NULL || self==NULL) - return -1; - memcpy(data,self->shadow[reg_num],reg_width); - return 0; -} - -extern int tas_register_driver(struct tas_driver_hooks_t *hooks); - -extern int tas_get_mixer_level(int mixer,uint *level); -extern int tas_set_mixer_level(int mixer,uint level); -extern int tas_enter_sleep(void); -extern int tas_leave_sleep(void); -extern int tas_supported_mixers(void); -extern int tas_mixer_is_stereo(int mixer); -extern int tas_stereo_mixers(void); -extern int tas_output_device_change(int,int,int); -extern int tas_device_ioctl(u_int, u_long); - -extern void tas_cleanup(void); -extern int tas_init(int driver_id,const char *driver_name); -extern int tas_post_init(void); - -#endif /* _TAS_COMMON_H_ */ -/* - * Local Variables: - * tab-width: 8 - * indent-tabs-mode: t - * c-basic-offset: 8 - * End: - */ diff --git a/sound/oss/dmasound/tas_eq_prefs.h b/sound/oss/dmasound/tas_eq_prefs.h deleted file mode 100644 index 3a994eda6ab..00000000000 --- a/sound/oss/dmasound/tas_eq_prefs.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef _TAS_EQ_PREFS_H_ -#define _TAS_EQ_PREFS_H_ - -struct tas_eq_pref_t { - u_int sample_rate; - u_int device_id; - u_int output_id; - u_int speaker_id; - - struct tas_drce_t *drce; - - u_int filter_count; - struct tas_biquad_ctrl_t *biquads; -}; - -#endif /* _TAS_EQ_PREFS_H_ */ - -/* - * Local Variables: - * tab-width: 8 - * indent-tabs-mode: t - * c-basic-offset: 8 - * End: - */ diff --git a/sound/oss/dmasound/tas_ioctl.h b/sound/oss/dmasound/tas_ioctl.h deleted file mode 100644 index 9d12b373b4a..00000000000 --- a/sound/oss/dmasound/tas_ioctl.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef _TAS_IOCTL_H_ -#define _TAS_IOCTL_H_ - -#include <linux/soundcard.h> - - -#define TAS_READ_EQ _SIOR('t',0,struct tas_biquad_ctrl_t) -#define TAS_WRITE_EQ _SIOW('t',0,struct tas_biquad_ctrl_t) - -#define TAS_READ_EQ_LIST _SIOR('t',1,struct tas_biquad_ctrl_t) -#define TAS_WRITE_EQ_LIST _SIOW('t',1,struct tas_biquad_ctrl_t) - -#define TAS_READ_EQ_FILTER_COUNT _SIOR('t',2,int) -#define TAS_READ_EQ_CHANNEL_COUNT _SIOR('t',3,int) - -#define TAS_READ_DRCE _SIOR('t',4,struct tas_drce_ctrl_t) -#define TAS_WRITE_DRCE _SIOW('t',4,struct tas_drce_ctrl_t) - -#define TAS_READ_DRCE_CAPS _SIOR('t',5,int) -#define TAS_READ_DRCE_MIN _SIOR('t',6,int) -#define TAS_READ_DRCE_MAX _SIOR('t',7,int) - -#endif diff --git a/sound/oss/dmasound/trans_16.c b/sound/oss/dmasound/trans_16.c deleted file mode 100644 index ca973ac2a30..00000000000 --- a/sound/oss/dmasound/trans_16.c +++ /dev/null @@ -1,898 +0,0 @@ -/* - * linux/sound/oss/dmasound/trans_16.c - * - * 16 bit translation routines. Only used by Power mac at present. - * - * See linux/sound/oss/dmasound/dmasound_core.c for copyright and - * history prior to 08/02/2001. - * - * 08/02/2001 Iain Sandoe - * split from dmasound_awacs.c - * 11/29/2003 Renzo Davoli (King Enzo) - * - input resampling (for soft rate < hard rate) - * - software line in gain control - */ - -#include <linux/soundcard.h> -#include <asm/uaccess.h> -#include "dmasound.h" - -extern int expand_bal; /* Balance factor for expanding (not volume!) */ -static short dmasound_alaw2dma16[] ; -static short dmasound_ulaw2dma16[] ; - -static ssize_t pmac_ct_law(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft); -static ssize_t pmac_ct_s8(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft); -static ssize_t pmac_ct_u8(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft); -static ssize_t pmac_ct_s16(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft); -static ssize_t pmac_ct_u16(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft); - -static ssize_t pmac_ctx_law(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft); -static ssize_t pmac_ctx_s8(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft); -static ssize_t pmac_ctx_u8(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft); -static ssize_t pmac_ctx_s16(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft); -static ssize_t pmac_ctx_u16(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft); - -static ssize_t pmac_ct_s16_read(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft); -static ssize_t pmac_ct_u16_read(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft); - -/*** Translations ************************************************************/ - -static int expand_data; /* Data for expanding */ - -static ssize_t pmac_ct_law(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft) -{ - short *table = dmasound.soft.format == AFMT_MU_LAW - ? dmasound_ulaw2dma16 : dmasound_alaw2dma16; - ssize_t count, used; - short *p = (short *) &frame[*frameUsed]; - int val, stereo = dmasound.soft.stereo; - - frameLeft >>= 2; - if (stereo) - userCount >>= 1; - used = count = min_t(unsigned long, userCount, frameLeft); - while (count > 0) { - u_char data; - if (get_user(data, userPtr++)) - return -EFAULT; - val = table[data]; - *p++ = val; - if (stereo) { - if (get_user(data, userPtr++)) - return -EFAULT; - val = table[data]; - } - *p++ = val; - count--; - } - *frameUsed += used * 4; - return stereo? used * 2: used; -} - - -static ssize_t pmac_ct_s8(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft) -{ - ssize_t count, used; - short *p = (short *) &frame[*frameUsed]; - int val, stereo = dmasound.soft.stereo; - - frameLeft >>= 2; - if (stereo) - userCount >>= 1; - used = count = min_t(unsigned long, userCount, frameLeft); - while (count > 0) { - u_char data; - if (get_user(data, userPtr++)) - return -EFAULT; - val = data << 8; - *p++ = val; - if (stereo) { - if (get_user(data, userPtr++)) - return -EFAULT; - val = data << 8; - } - *p++ = val; - count--; - } - *frameUsed += used * 4; - return stereo? used * 2: used; -} - - -static ssize_t pmac_ct_u8(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft) -{ - ssize_t count, used; - short *p = (short *) &frame[*frameUsed]; - int val, stereo = dmasound.soft.stereo; - - frameLeft >>= 2; - if (stereo) - userCount >>= 1; - used = count = min_t(unsigned long, userCount, frameLeft); - while (count > 0) { - u_char data; - if (get_user(data, userPtr++)) - return -EFAULT; - val = (data ^ 0x80) << 8; - *p++ = val; - if (stereo) { - if (get_user(data, userPtr++)) - return -EFAULT; - val = (data ^ 0x80) << 8; - } - *p++ = val; - count--; - } - *frameUsed += used * 4; - return stereo? used * 2: used; -} - - -static ssize_t pmac_ct_s16(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft) -{ - ssize_t count, used; - int stereo = dmasound.soft.stereo; - short *fp = (short *) &frame[*frameUsed]; - - frameLeft >>= 2; - userCount >>= (stereo? 2: 1); - used = count = min_t(unsigned long, userCount, frameLeft); - if (!stereo) { - short __user *up = (short __user *) userPtr; - while (count > 0) { - short data; - if (get_user(data, up++)) - return -EFAULT; - *fp++ = data; - *fp++ = data; - count--; - } - } else { - if (copy_from_user(fp, userPtr, count * 4)) - return -EFAULT; - } - *frameUsed += used * 4; - return stereo? used * 4: used * 2; -} - -static ssize_t pmac_ct_u16(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft) -{ - ssize_t count, used; - int mask = (dmasound.soft.format == AFMT_U16_LE? 0x0080: 0x8000); - int stereo = dmasound.soft.stereo; - short *fp = (short *) &frame[*frameUsed]; - short __user *up = (short __user *) userPtr; - - frameLeft >>= 2; - userCount >>= (stereo? 2: 1); - used = count = min_t(unsigned long, userCount, frameLeft); - while (count > 0) { - short data; - if (get_user(data, up++)) - return -EFAULT; - data ^= mask; - *fp++ = data; - if (stereo) { - if (get_user(data, up++)) - return -EFAULT; - data ^= mask; - } - *fp++ = data; - count--; - } - *frameUsed += used * 4; - return stereo? used * 4: used * 2; -} - - -static ssize_t pmac_ctx_law(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft) -{ - unsigned short *table = (unsigned short *) - (dmasound.soft.format == AFMT_MU_LAW - ? dmasound_ulaw2dma16 : dmasound_alaw2dma16); - unsigned int data = expand_data; - unsigned int *p = (unsigned int *) &frame[*frameUsed]; - int bal = expand_bal; - int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; - int utotal, ftotal; - int stereo = dmasound.soft.stereo; - - frameLeft >>= 2; - if (stereo) - userCount >>= 1; - ftotal = frameLeft; - utotal = userCount; - while (frameLeft) { - u_char c; - if (bal < 0) { - if (userCount == 0) - break; - if (get_user(c, userPtr++)) - return -EFAULT; - data = table[c]; - if (stereo) { - if (get_user(c, userPtr++)) - return -EFAULT; - data = (data << 16) + table[c]; - } else - data = (data << 16) + data; - userCount--; - bal += hSpeed; - } - *p++ = data; - frameLeft--; - bal -= sSpeed; - } - expand_bal = bal; - expand_data = data; - *frameUsed += (ftotal - frameLeft) * 4; - utotal -= userCount; - return stereo? utotal * 2: utotal; -} - -static ssize_t pmac_ctx_s8(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft) -{ - unsigned int *p = (unsigned int *) &frame[*frameUsed]; - unsigned int data = expand_data; - int bal = expand_bal; - int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; - int stereo = dmasound.soft.stereo; - int utotal, ftotal; - - frameLeft >>= 2; - if (stereo) - userCount >>= 1; - ftotal = frameLeft; - utotal = userCount; - while (frameLeft) { - u_char c; - if (bal < 0) { - if (userCount == 0) - break; - if (get_user(c, userPtr++)) - return -EFAULT; - data = c << 8; - if (stereo) { - if (get_user(c, userPtr++)) - return -EFAULT; - data = (data << 16) + (c << 8); - } else - data = (data << 16) + data; - userCount--; - bal += hSpeed; - } - *p++ = data; - frameLeft--; - bal -= sSpeed; - } - expand_bal = bal; - expand_data = data; - *frameUsed += (ftotal - frameLeft) * 4; - utotal -= userCount; - return stereo? utotal * 2: utotal; -} - - -static ssize_t pmac_ctx_u8(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft) -{ - unsigned int *p = (unsigned int *) &frame[*frameUsed]; - unsigned int data = expand_data; - int bal = expand_bal; - int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; - int stereo = dmasound.soft.stereo; - int utotal, ftotal; - - frameLeft >>= 2; - if (stereo) - userCount >>= 1; - ftotal = frameLeft; - utotal = userCount; - while (frameLeft) { - u_char c; - if (bal < 0) { - if (userCount == 0) - break; - if (get_user(c, userPtr++)) - return -EFAULT; - data = (c ^ 0x80) << 8; - if (stereo) { - if (get_user(c, userPtr++)) - return -EFAULT; - data = (data << 16) + ((c ^ 0x80) << 8); - } else - data = (data << 16) + data; - userCount--; - bal += hSpeed; - } - *p++ = data; - frameLeft--; - bal -= sSpeed; - } - expand_bal = bal; - expand_data = data; - *frameUsed += (ftotal - frameLeft) * 4; - utotal -= userCount; - return stereo? utotal * 2: utotal; -} - - -static ssize_t pmac_ctx_s16(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft) -{ - unsigned int *p = (unsigned int *) &frame[*frameUsed]; - unsigned int data = expand_data; - unsigned short __user *up = (unsigned short __user *) userPtr; - int bal = expand_bal; - int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; - int stereo = dmasound.soft.stereo; - int utotal, ftotal; - - frameLeft >>= 2; - userCount >>= (stereo? 2: 1); - ftotal = frameLeft; - utotal = userCount; - while (frameLeft) { - unsigned short c; - if (bal < 0) { - if (userCount == 0) - break; - if (get_user(data, up++)) - return -EFAULT; - if (stereo) { - if (get_user(c, up++)) - return -EFAULT; - data = (data << 16) + c; - } else - data = (data << 16) + data; - userCount--; - bal += hSpeed; - } - *p++ = data; - frameLeft--; - bal -= sSpeed; - } - expand_bal = bal; - expand_data = data; - *frameUsed += (ftotal - frameLeft) * 4; - utotal -= userCount; - return stereo? utotal * 4: utotal * 2; -} - - -static ssize_t pmac_ctx_u16(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft) -{ - int mask = (dmasound.soft.format == AFMT_U16_LE? 0x0080: 0x8000); - unsigned int *p = (unsigned int *) &frame[*frameUsed]; - unsigned int data = expand_data; - unsigned short __user *up = (unsigned short __user *) userPtr; - int bal = expand_bal; - int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; - int stereo = dmasound.soft.stereo; - int utotal, ftotal; - - frameLeft >>= 2; - userCount >>= (stereo? 2: 1); - ftotal = frameLeft; - utotal = userCount; - while (frameLeft) { - unsigned short c; - if (bal < 0) { - if (userCount == 0) - break; - if (get_user(data, up++)) - return -EFAULT; - data ^= mask; - if (stereo) { - if (get_user(c, up++)) - return -EFAULT; - data = (data << 16) + (c ^ mask); - } else - data = (data << 16) + data; - userCount--; - bal += hSpeed; - } - *p++ = data; - frameLeft--; - bal -= sSpeed; - } - expand_bal = bal; - expand_data = data; - *frameUsed += (ftotal - frameLeft) * 4; - utotal -= userCount; - return stereo? utotal * 4: utotal * 2; -} - -/* data in routines... */ - -static ssize_t pmac_ct_s8_read(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft) -{ - ssize_t count, used; - short *p = (short *) &frame[*frameUsed]; - int val, stereo = dmasound.soft.stereo; - - frameLeft >>= 2; - if (stereo) - userCount >>= 1; - used = count = min_t(unsigned long, userCount, frameLeft); - while (count > 0) { - u_char data; - - val = *p++; - val = (val * software_input_volume) >> 7; - data = val >> 8; - if (put_user(data, (u_char __user *)userPtr++)) - return -EFAULT; - if (stereo) { - val = *p; - val = (val * software_input_volume) >> 7; - data = val >> 8; - if (put_user(data, (u_char __user *)userPtr++)) - return -EFAULT; - } - p++; - count--; - } - *frameUsed += used * 4; - return stereo? used * 2: used; -} - - -static ssize_t pmac_ct_u8_read(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft) -{ - ssize_t count, used; - short *p = (short *) &frame[*frameUsed]; - int val, stereo = dmasound.soft.stereo; - - frameLeft >>= 2; - if (stereo) - userCount >>= 1; - used = count = min_t(unsigned long, userCount, frameLeft); - while (count > 0) { - u_char data; - - val = *p++; - val = (val * software_input_volume) >> 7; - data = (val >> 8) ^ 0x80; - if (put_user(data, (u_char __user *)userPtr++)) - return -EFAULT; - if (stereo) { - val = *p; - val = (val * software_input_volume) >> 7; - data = (val >> 8) ^ 0x80; - if (put_user(data, (u_char __user *)userPtr++)) - return -EFAULT; - } - p++; - count--; - } - *frameUsed += used * 4; - return stereo? used * 2: used; -} - -static ssize_t pmac_ct_s16_read(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft) -{ - ssize_t count, used; - int stereo = dmasound.soft.stereo; - short *fp = (short *) &frame[*frameUsed]; - short __user *up = (short __user *) userPtr; - - frameLeft >>= 2; - userCount >>= (stereo? 2: 1); - used = count = min_t(unsigned long, userCount, frameLeft); - while (count > 0) { - short data; - - data = *fp++; - data = (data * software_input_volume) >> 7; - if (put_user(data, up++)) - return -EFAULT; - if (stereo) { - data = *fp; - data = (data * software_input_volume) >> 7; - if (put_user(data, up++)) - return -EFAULT; - } - fp++; - count--; - } - *frameUsed += used * 4; - return stereo? used * 4: used * 2; -} - -static ssize_t pmac_ct_u16_read(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft) -{ - ssize_t count, used; - int mask = (dmasound.soft.format == AFMT_U16_LE? 0x0080: 0x8000); - int stereo = dmasound.soft.stereo; - short *fp = (short *) &frame[*frameUsed]; - short __user *up = (short __user *) userPtr; - - frameLeft >>= 2; - userCount >>= (stereo? 2: 1); - used = count = min_t(unsigned long, userCount, frameLeft); - while (count > 0) { - int data; - - data = *fp++; - data = (data * software_input_volume) >> 7; - data ^= mask; - if (put_user(data, up++)) - return -EFAULT; - if (stereo) { - data = *fp; - data = (data * software_input_volume) >> 7; - data ^= mask; - if (put_user(data, up++)) - return -EFAULT; - } - fp++; - count--; - } - *frameUsed += used * 4; - return stereo? used * 4: used * 2; -} - -/* data in routines (reducing speed)... */ - -static ssize_t pmac_ctx_s8_read(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft) -{ - short *p = (short *) &frame[*frameUsed]; - int bal = expand_read_bal; - int vall,valr, stereo = dmasound.soft.stereo; - int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; - int utotal, ftotal; - - frameLeft >>= 2; - if (stereo) - userCount >>= 1; - ftotal = frameLeft; - utotal = userCount; - while (frameLeft) { - u_char data; - - if (bal<0 && userCount == 0) - break; - vall = *p++; - vall = (vall * software_input_volume) >> 7; - if (stereo) { - valr = *p; - valr = (valr * software_input_volume) >> 7; - } - p++; - if (bal < 0) { - data = vall >> 8; - if (put_user(data, (u_char __user *)userPtr++)) - return -EFAULT; - if (stereo) { - data = valr >> 8; - if (put_user(data, (u_char __user *)userPtr++)) - return -EFAULT; - } - userCount--; - bal += hSpeed; - } - frameLeft--; - bal -= sSpeed; - } - expand_read_bal=bal; - *frameUsed += (ftotal - frameLeft) * 4; - utotal -= userCount; - return stereo? utotal * 2: utotal; -} - - -static ssize_t pmac_ctx_u8_read(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft) -{ - short *p = (short *) &frame[*frameUsed]; - int bal = expand_read_bal; - int vall,valr, stereo = dmasound.soft.stereo; - int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; - int utotal, ftotal; - - frameLeft >>= 2; - if (stereo) - userCount >>= 1; - ftotal = frameLeft; - utotal = userCount; - while (frameLeft) { - u_char data; - - if (bal<0 && userCount == 0) - break; - - vall = *p++; - vall = (vall * software_input_volume) >> 7; - if (stereo) { - valr = *p; - valr = (valr * software_input_volume) >> 7; - } - p++; - if (bal < 0) { - data = (vall >> 8) ^ 0x80; - if (put_user(data, (u_char __user *)userPtr++)) - return -EFAULT; - if (stereo) { - data = (valr >> 8) ^ 0x80; - if (put_user(data, (u_char __user *)userPtr++)) - return -EFAULT; - } - userCount--; - bal += hSpeed; - } - frameLeft--; - bal -= sSpeed; - } - expand_read_bal=bal; - *frameUsed += (ftotal - frameLeft) * 4; - utotal -= userCount; - return stereo? utotal * 2: utotal; -} - -static ssize_t pmac_ctx_s16_read(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft) -{ - int bal = expand_read_bal; - short *fp = (short *) &frame[*frameUsed]; - short __user *up = (short __user *) userPtr; - int stereo = dmasound.soft.stereo; - int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; - int utotal, ftotal; - - frameLeft >>= 2; - userCount >>= (stereo? 2: 1); - ftotal = frameLeft; - utotal = userCount; - while (frameLeft) { - int datal,datar; - - if (bal<0 && userCount == 0) - break; - - datal = *fp++; - datal = (datal * software_input_volume) >> 7; - if (stereo) { - datar = *fp; - datar = (datar * software_input_volume) >> 7; - } - fp++; - if (bal < 0) { - if (put_user(datal, up++)) - return -EFAULT; - if (stereo) { - if (put_user(datar, up++)) - return -EFAULT; - } - userCount--; - bal += hSpeed; - } - frameLeft--; - bal -= sSpeed; - } - expand_read_bal=bal; - *frameUsed += (ftotal - frameLeft) * 4; - utotal -= userCount; - return stereo? utotal * 4: utotal * 2; -} - -static ssize_t pmac_ctx_u16_read(const u_char __user *userPtr, size_t userCount, - u_char frame[], ssize_t *frameUsed, - ssize_t frameLeft) -{ - int bal = expand_read_bal; - int mask = (dmasound.soft.format == AFMT_U16_LE? 0x0080: 0x8000); - short *fp = (short *) &frame[*frameUsed]; - short __user *up = (short __user *) userPtr; - int stereo = dmasound.soft.stereo; - int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed; - int utotal, ftotal; - - frameLeft >>= 2; - userCount >>= (stereo? 2: 1); - ftotal = frameLeft; - utotal = userCount; - while (frameLeft) { - int datal,datar; - - if (bal<0 && userCount == 0) - break; - - datal = *fp++; - datal = (datal * software_input_volume) >> 7; - datal ^= mask; - if (stereo) { - datar = *fp; - datar = (datar * software_input_volume) >> 7; - datar ^= mask; - } - fp++; - if (bal < 0) { - if (put_user(datal, up++)) - return -EFAULT; - if (stereo) { - if (put_user(datar, up++)) - return -EFAULT; - } - userCount--; - bal += hSpeed; - } - frameLeft--; - bal -= sSpeed; - } - expand_read_bal=bal; - *frameUsed += (ftotal - frameLeft) * 4; - utotal -= userCount; - return stereo? utotal * 4: utotal * 2; -} - - -TRANS transAwacsNormal = { - .ct_ulaw= pmac_ct_law, - .ct_alaw= pmac_ct_law, - .ct_s8= pmac_ct_s8, - .ct_u8= pmac_ct_u8, - .ct_s16be= pmac_ct_s16, - .ct_u16be= pmac_ct_u16, - .ct_s16le= pmac_ct_s16, - .ct_u16le= pmac_ct_u16, -}; - -TRANS transAwacsExpand = { - .ct_ulaw= pmac_ctx_law, - .ct_alaw= pmac_ctx_law, - .ct_s8= pmac_ctx_s8, - .ct_u8= pmac_ctx_u8, - .ct_s16be= pmac_ctx_s16, - .ct_u16be= pmac_ctx_u16, - .ct_s16le= pmac_ctx_s16, - .ct_u16le= pmac_ctx_u16, -}; - -TRANS transAwacsNormalRead = { - .ct_s8= pmac_ct_s8_read, - .ct_u8= pmac_ct_u8_read, - .ct_s16be= pmac_ct_s16_read, - .ct_u16be= pmac_ct_u16_read, - .ct_s16le= pmac_ct_s16_read, - .ct_u16le= pmac_ct_u16_read, -}; - -TRANS transAwacsExpandRead = { - .ct_s8= pmac_ctx_s8_read, - .ct_u8= pmac_ctx_u8_read, - .ct_s16be= pmac_ctx_s16_read, - .ct_u16be= pmac_ctx_u16_read, - .ct_s16le= pmac_ctx_s16_read, - .ct_u16le= pmac_ctx_u16_read, -}; - -/* translation tables */ -/* 16 bit mu-law */ - -static short dmasound_ulaw2dma16[] = { - -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956, - -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764, - -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412, - -11900, -11388, -10876, -10364, -9852, -9340, -8828, -8316, - -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140, - -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092, - -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004, - -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980, - -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436, - -1372, -1308, -1244, -1180, -1116, -1052, -988, -924, - -876, -844, -812, -780, -748, -716, -684, -652, - -620, -588, -556, -524, -492, -460, -428, -396, - -372, -356, -340, -324, -308, -292, -276, -260, - -244, -228, -212, -196, -180, -164, -148, -132, - -120, -112, -104, -96, -88, -80, -72, -64, - -56, -48, -40, -32, -24, -16, -8, 0, - 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956, - 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764, - 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412, - 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316, - 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140, - 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092, - 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004, - 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980, - 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436, - 1372, 1308, 1244, 1180, 1116, 1052, 988, 924, - 876, 844, 812, 780, 748, 716, 684, 652, - 620, 588, 556, 524, 492, 460, 428, 396, - 372, 356, 340, 324, 308, 292, 276, 260, - 244, 228, 212, 196, 180, 164, 148, 132, - 120, 112, 104, 96, 88, 80, 72, 64, - 56, 48, 40, 32, 24, 16, 8, 0, -}; - -/* 16 bit A-law */ - -static short dmasound_alaw2dma16[] = { - -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736, - -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784, - -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368, - -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392, - -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944, - -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136, - -11008, -10496, -12032, -11520, -8960, -8448, -9984, -9472, - -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568, - -344, -328, -376, -360, -280, -264, -312, -296, - -472, -456, -504, -488, -408, -392, -440, -424, - -88, -72, -120, -104, -24, -8, -56, -40, - -216, -200, -248, -232, -152, -136, -184, -168, - -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184, - -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696, - -688, -656, -752, -720, -560, -528, -624, -592, - -944, -912, -1008, -976, -816, -784, -880, -848, - 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736, - 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784, - 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368, - 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392, - 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944, - 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136, - 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472, - 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568, - 344, 328, 376, 360, 280, 264, 312, 296, - 472, 456, 504, 488, 408, 392, 440, 424, - 88, 72, 120, 104, 24, 8, 56, 40, - 216, 200, 248, 232, 152, 136, 184, 168, - 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184, - 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696, - 688, 656, 752, 720, 560, 528, 624, 592, - 944, 912, 1008, 976, 816, 784, 880, 848, -}; diff --git a/sound/oss/es1371.c b/sound/oss/es1371.c deleted file mode 100644 index 52648573f60..00000000000 --- a/sound/oss/es1371.c +++ /dev/null @@ -1,3131 +0,0 @@ -/*****************************************************************************/ - -/* - * es1371.c -- Creative Ensoniq ES1371. - * - * Copyright (C) 1998-2001, 2003 Thomas Sailer (t.sailer@alumni.ethz.ch) - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Special thanks to Ensoniq - * - * Supported devices: - * /dev/dsp standard /dev/dsp device, (mostly) OSS compatible - * /dev/mixer standard /dev/mixer device, (mostly) OSS compatible - * /dev/dsp1 additional DAC, like /dev/dsp, but outputs to mixer "SYNTH" setting - * /dev/midi simple MIDI UART interface, no ioctl - * - * NOTE: the card does not have any FM/Wavetable synthesizer, it is supposed - * to be done in software. That is what /dev/dac is for. By now (Q2 1998) - * there are several MIDI to PCM (WAV) packages, one of them is timidity. - * - * Revision history - * 04.06.1998 0.1 Initial release - * Mixer stuff should be overhauled; especially optional AC97 mixer bits - * should be detected. This results in strange behaviour of some mixer - * settings, like master volume and mic. - * 08.06.1998 0.2 First release using Alan Cox' soundcore instead of miscdevice - * 03.08.1998 0.3 Do not include modversions.h - * Now mixer behaviour can basically be selected between - * "OSS documented" and "OSS actual" behaviour - * 31.08.1998 0.4 Fix realplayer problems - dac.count issues - * 27.10.1998 0.5 Fix joystick support - * -- Oliver Neukum (c188@org.chemie.uni-muenchen.de) - * 10.12.1998 0.6 Fix drain_dac trying to wait on not yet initialized DMA - * 23.12.1998 0.7 Fix a few f_file & FMODE_ bugs - * Don't wake up app until there are fragsize bytes to read/write - * 06.01.1999 0.8 remove the silly SA_INTERRUPT flag. - * hopefully killed the egcs section type conflict - * 12.03.1999 0.9 cinfo.blocks should be reset after GETxPTR ioctl. - * reported by Johan Maes <joma@telindus.be> - * 22.03.1999 0.10 return EAGAIN instead of EBUSY when O_NONBLOCK - * read/write cannot be executed - * 07.04.1999 0.11 implemented the following ioctl's: SOUND_PCM_READ_RATE, - * SOUND_PCM_READ_CHANNELS, SOUND_PCM_READ_BITS; - * Alpha fixes reported by Peter Jones <pjones@redhat.com> - * Another Alpha fix (wait_src_ready in init routine) - * reported by "Ivan N. Kokshaysky" <ink@jurassic.park.msu.ru> - * Note: joystick address handling might still be wrong on archs - * other than i386 - * 15.06.1999 0.12 Fix bad allocation bug. - * Thanks to Deti Fliegl <fliegl@in.tum.de> - * 28.06.1999 0.13 Add pci_set_master - * 03.08.1999 0.14 adapt to Linus' new __setup/__initcall - * added kernel command line option "es1371=joystickaddr" - * removed CONFIG_SOUND_ES1371_JOYPORT_BOOT kludge - * 10.08.1999 0.15 (Re)added S/PDIF module option for cards revision >= 4. - * Initial version by Dave Platt <dplatt@snulbug.mtview.ca.us>. - * module_init/__setup fixes - * 08.16.1999 0.16 Joe Cotellese <joec@ensoniq.com> - * Added detection for ES1371 revision ID so that we can - * detect the ES1373 and later parts. - * added AC97 #defines for readability - * added a /proc file system for dumping hardware state - * updated SRC and CODEC w/r functions to accommodate bugs - * in some versions of the ES137x chips. - * 31.08.1999 0.17 add spin_lock_init - * replaced current->state = x with set_current_state(x) - * 03.09.1999 0.18 change read semantics for MIDI to match - * OSS more closely; remove possible wakeup race - * 21.10.1999 0.19 Round sampling rates, requested by - * Kasamatsu Kenichi <t29w0267@ip.media.kyoto-u.ac.jp> - * 27.10.1999 0.20 Added SigmaTel 3D enhancement string - * Codec ID printing changes - * 28.10.1999 0.21 More waitqueue races fixed - * Joe Cotellese <joec@ensoniq.com> - * Changed PCI detection routine so we can more easily - * detect ES137x chip and derivatives. - * 05.01.2000 0.22 Should now work with rev7 boards; patch by - * Eric Lemar, elemar@cs.washington.edu - * 08.01.2000 0.23 Prevent some ioctl's from returning bad count values on underrun/overrun; - * Tim Janik's BSE (Bedevilled Sound Engine) found this - * 07.02.2000 0.24 Use pci_alloc_consistent and pci_register_driver - * 07.02.2000 0.25 Use ac97_codec - * 01.03.2000 0.26 SPDIF patch by Mikael Bouillot <mikael.bouillot@bigfoot.com> - * Use pci_module_init - * 21.11.2000 0.27 Initialize dma buffers in poll, otherwise poll may return a bogus mask - * 12.12.2000 0.28 More dma buffer initializations, patch from - * Tjeerd Mulder <tjeerd.mulder@fujitsu-siemens.com> - * 05.01.2001 0.29 Hopefully updates will not be required anymore when Creative bumps - * the CT5880 revision. - * suggested by Stephan Müller <smueller@chronox.de> - * 31.01.2001 0.30 Register/Unregister gameport - * Fix SETTRIGGER non OSS API conformity - * 14.07.2001 0.31 Add list of laptops needing amplifier control - * 03.01.2003 0.32 open_mode fixes from Georg Acher <acher@in.tum.de> - */ - -/*****************************************************************************/ - -#include <linux/interrupt.h> -#include <linux/module.h> -#include <linux/string.h> -#include <linux/ioport.h> -#include <linux/sched.h> -#include <linux/delay.h> -#include <linux/sound.h> -#include <linux/slab.h> -#include <linux/soundcard.h> -#include <linux/pci.h> -#include <linux/init.h> -#include <linux/poll.h> -#include <linux/bitops.h> -#include <linux/proc_fs.h> -#include <linux/spinlock.h> -#include <linux/smp_lock.h> -#include <linux/ac97_codec.h> -#include <linux/gameport.h> -#include <linux/wait.h> -#include <linux/dma-mapping.h> -#include <linux/mutex.h> -#include <linux/mm.h> -#include <linux/kernel.h> - -#include <asm/io.h> -#include <asm/page.h> -#include <asm/uaccess.h> - -#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) -#define SUPPORT_JOYSTICK -#endif - -/* --------------------------------------------------------------------- */ - -#undef OSS_DOCUMENTED_MIXER_SEMANTICS -#define ES1371_DEBUG -#define DBG(x) {} -/*#define DBG(x) {x}*/ - -/* --------------------------------------------------------------------- */ - -#ifndef PCI_VENDOR_ID_ENSONIQ -#define PCI_VENDOR_ID_ENSONIQ 0x1274 -#endif - -#ifndef PCI_VENDOR_ID_ECTIVA -#define PCI_VENDOR_ID_ECTIVA 0x1102 -#endif - -#ifndef PCI_DEVICE_ID_ENSONIQ_ES1371 -#define PCI_DEVICE_ID_ENSONIQ_ES1371 0x1371 -#endif - -#ifndef PCI_DEVICE_ID_ENSONIQ_CT5880 -#define PCI_DEVICE_ID_ENSONIQ_CT5880 0x5880 -#endif - -#ifndef PCI_DEVICE_ID_ECTIVA_EV1938 -#define PCI_DEVICE_ID_ECTIVA_EV1938 0x8938 -#endif - -/* ES1371 chip ID */ -/* This is a little confusing because all ES1371 compatible chips have the - same DEVICE_ID, the only thing differentiating them is the REV_ID field. - This is only significant if you want to enable features on the later parts. - Yes, I know it's stupid and why didn't we use the sub IDs? -*/ -#define ES1371REV_ES1373_A 0x04 -#define ES1371REV_ES1373_B 0x06 -#define ES1371REV_CT5880_A 0x07 -#define CT5880REV_CT5880_C 0x02 -#define CT5880REV_CT5880_D 0x03 -#define ES1371REV_ES1371_B 0x09 -#define EV1938REV_EV1938_A 0x00 -#define ES1371REV_ES1373_8 0x08 - -#define ES1371_MAGIC ((PCI_VENDOR_ID_ENSONIQ<<16)|PCI_DEVICE_ID_ENSONIQ_ES1371) - -#define ES1371_EXTENT 0x40 -#define JOY_EXTENT 8 - -#define ES1371_REG_CONTROL 0x00 -#define ES1371_REG_STATUS 0x04 /* on the 5880 it is control/status */ -#define ES1371_REG_UART_DATA 0x08 -#define ES1371_REG_UART_STATUS 0x09 -#define ES1371_REG_UART_CONTROL 0x09 -#define ES1371_REG_UART_TEST 0x0a -#define ES1371_REG_MEMPAGE 0x0c -#define ES1371_REG_SRCONV 0x10 -#define ES1371_REG_CODEC 0x14 -#define ES1371_REG_LEGACY 0x18 -#define ES1371_REG_SERIAL_CONTROL 0x20 -#define ES1371_REG_DAC1_SCOUNT 0x24 -#define ES1371_REG_DAC2_SCOUNT 0x28 -#define ES1371_REG_ADC_SCOUNT 0x2c - -#define ES1371_REG_DAC1_FRAMEADR 0xc30 -#define ES1371_REG_DAC1_FRAMECNT 0xc34 -#define ES1371_REG_DAC2_FRAMEADR 0xc38 -#define ES1371_REG_DAC2_FRAMECNT 0xc3c -#define ES1371_REG_ADC_FRAMEADR 0xd30 -#define ES1371_REG_ADC_FRAMECNT 0xd34 - -#define ES1371_FMT_U8_MONO 0 -#define ES1371_FMT_U8_STEREO 1 -#define ES1371_FMT_S16_MONO 2 -#define ES1371_FMT_S16_STEREO 3 -#define ES1371_FMT_STEREO 1 -#define ES1371_FMT_S16 2 -#define ES1371_FMT_MASK 3 - -static const unsigned sample_size[] = { 1, 2, 2, 4 }; -static const unsigned sample_shift[] = { 0, 1, 1, 2 }; - -#define CTRL_RECEN_B 0x08000000 /* 1 = don't mix analog in to digital out */ -#define CTRL_SPDIFEN_B 0x04000000 -#define CTRL_JOY_SHIFT 24 -#define CTRL_JOY_MASK 3 -#define CTRL_JOY_200 0x00000000 /* joystick base address */ -#define CTRL_JOY_208 0x01000000 -#define CTRL_JOY_210 0x02000000 -#define CTRL_JOY_218 0x03000000 -#define CTRL_GPIO_IN0 0x00100000 /* general purpose inputs/outputs */ -#define CTRL_GPIO_IN1 0x00200000 -#define CTRL_GPIO_IN2 0x00400000 -#define CTRL_GPIO_IN3 0x00800000 -#define CTRL_GPIO_OUT0 0x00010000 -#define CTRL_GPIO_OUT1 0x00020000 -#define CTRL_GPIO_OUT2 0x00040000 -#define CTRL_GPIO_OUT3 0x00080000 -#define CTRL_MSFMTSEL 0x00008000 /* MPEG serial data fmt: 0 = Sony, 1 = I2S */ -#define CTRL_SYNCRES 0x00004000 /* AC97 warm reset */ -#define CTRL_ADCSTOP 0x00002000 /* stop ADC transfers */ -#define CTRL_PWR_INTRM 0x00001000 /* 1 = power level ints enabled */ -#define CTRL_M_CB 0x00000800 /* recording source: 0 = ADC, 1 = MPEG */ -#define CTRL_CCB_INTRM 0x00000400 /* 1 = CCB "voice" ints enabled */ -#define CTRL_PDLEV0 0x00000000 /* power down level */ -#define CTRL_PDLEV1 0x00000100 -#define CTRL_PDLEV2 0x00000200 -#define CTRL_PDLEV3 0x00000300 -#define CTRL_BREQ 0x00000080 /* 1 = test mode (internal mem test) */ -#define CTRL_DAC1_EN 0x00000040 /* enable DAC1 */ -#define CTRL_DAC2_EN 0x00000020 /* enable DAC2 */ -#define CTRL_ADC_EN 0x00000010 /* enable ADC */ -#define CTRL_UART_EN 0x00000008 /* enable MIDI uart */ -#define CTRL_JYSTK_EN 0x00000004 /* enable Joystick port */ -#define CTRL_XTALCLKDIS 0x00000002 /* 1 = disable crystal clock input */ -#define CTRL_PCICLKDIS 0x00000001 /* 1 = disable PCI clock distribution */ - - -#define STAT_INTR 0x80000000 /* wired or of all interrupt bits */ -#define CSTAT_5880_AC97_RST 0x20000000 /* CT5880 Reset bit */ -#define STAT_EN_SPDIF 0x00040000 /* enable S/PDIF circuitry */ -#define STAT_TS_SPDIF 0x00020000 /* test S/PDIF circuitry */ -#define STAT_TESTMODE 0x00010000 /* test ASIC */ -#define STAT_SYNC_ERR 0x00000100 /* 1 = codec sync error */ -#define STAT_VC 0x000000c0 /* CCB int source, 0=DAC1, 1=DAC2, 2=ADC, 3=undef */ -#define STAT_SH_VC 6 -#define STAT_MPWR 0x00000020 /* power level interrupt */ -#define STAT_MCCB 0x00000010 /* CCB int pending */ -#define STAT_UART 0x00000008 /* UART int pending */ -#define STAT_DAC1 0x00000004 /* DAC1 int pending */ -#define STAT_DAC2 0x00000002 /* DAC2 int pending */ -#define STAT_ADC 0x00000001 /* ADC int pending */ - -#define USTAT_RXINT 0x80 /* UART rx int pending */ -#define USTAT_TXINT 0x04 /* UART tx int pending */ -#define USTAT_TXRDY 0x02 /* UART tx ready */ -#define USTAT_RXRDY 0x01 /* UART rx ready */ - -#define UCTRL_RXINTEN 0x80 /* 1 = enable RX ints */ -#define UCTRL_TXINTEN 0x60 /* TX int enable field mask */ -#define UCTRL_ENA_TXINT 0x20 /* enable TX int */ -#define UCTRL_CNTRL 0x03 /* control field */ -#define UCTRL_CNTRL_SWR 0x03 /* software reset command */ - -/* sample rate converter */ -#define SRC_OKSTATE 1 - -#define SRC_RAMADDR_MASK 0xfe000000 -#define SRC_RAMADDR_SHIFT 25 -#define SRC_DAC1FREEZE (1UL << 21) -#define SRC_DAC2FREEZE (1UL << 20) -#define SRC_ADCFREEZE (1UL << 19) - - -#define SRC_WE 0x01000000 /* read/write control for SRC RAM */ -#define SRC_BUSY 0x00800000 /* SRC busy */ -#define SRC_DIS 0x00400000 /* 1 = disable SRC */ -#define SRC_DDAC1 0x00200000 /* 1 = disable accum update for DAC1 */ -#define SRC_DDAC2 0x00100000 /* 1 = disable accum update for DAC2 */ -#define SRC_DADC 0x00080000 /* 1 = disable accum update for ADC2 */ -#define SRC_CTLMASK 0x00780000 -#define SRC_RAMDATA_MASK 0x0000ffff -#define SRC_RAMDATA_SHIFT 0 - -#define SRCREG_ADC 0x78 -#define SRCREG_DAC1 0x70 -#define SRCREG_DAC2 0x74 -#define SRCREG_VOL_ADC 0x6c -#define SRCREG_VOL_DAC1 0x7c -#define SRCREG_VOL_DAC2 0x7e - -#define SRCREG_TRUNC_N 0x00 -#define SRCREG_INT_REGS 0x01 -#define SRCREG_ACCUM_FRAC 0x02 -#define SRCREG_VFREQ_FRAC 0x03 - -#define CODEC_PIRD 0x00800000 /* 0 = write AC97 register */ -#define CODEC_PIADD_MASK 0x007f0000 -#define CODEC_PIADD_SHIFT 16 -#define CODEC_PIDAT_MASK 0x0000ffff -#define CODEC_PIDAT_SHIFT 0 - -#define CODEC_RDY 0x80000000 /* AC97 read data valid */ -#define CODEC_WIP 0x40000000 /* AC97 write in progress */ -#define CODEC_PORD 0x00800000 /* 0 = write AC97 register */ -#define CODEC_POADD_MASK 0x007f0000 -#define CODEC_POADD_SHIFT 16 -#define CODEC_PODAT_MASK 0x0000ffff -#define CODEC_PODAT_SHIFT 0 - - -#define LEGACY_JFAST 0x80000000 /* fast joystick timing */ -#define LEGACY_FIRQ 0x01000000 /* force IRQ */ - -#define SCTRL_DACTEST 0x00400000 /* 1 = DAC test, test vector generation purposes */ -#define SCTRL_P2ENDINC 0x00380000 /* */ -#define SCTRL_SH_P2ENDINC 19 -#define SCTRL_P2STINC 0x00070000 /* */ -#define SCTRL_SH_P2STINC 16 -#define SCTRL_R1LOOPSEL 0x00008000 /* 0 = loop mode */ -#define SCTRL_P2LOOPSEL 0x00004000 /* 0 = loop mode */ -#define SCTRL_P1LOOPSEL 0x00002000 /* 0 = loop mode */ -#define SCTRL_P2PAUSE 0x00001000 /* 1 = pause mode */ -#define SCTRL_P1PAUSE 0x00000800 /* 1 = pause mode */ -#define SCTRL_R1INTEN 0x00000400 /* enable interrupt */ -#define SCTRL_P2INTEN 0x00000200 /* enable interrupt */ -#define SCTRL_P1INTEN 0x00000100 /* enable interrupt */ -#define SCTRL_P1SCTRLD 0x00000080 /* reload sample count register for DAC1 */ -#define SCTRL_P2DACSEN 0x00000040 /* 1 = DAC2 play back last sample when disabled */ -#define SCTRL_R1SEB 0x00000020 /* 1 = 16bit */ -#define SCTRL_R1SMB 0x00000010 /* 1 = stereo */ -#define SCTRL_R1FMT 0x00000030 /* format mask */ -#define SCTRL_SH_R1FMT 4 -#define SCTRL_P2SEB 0x00000008 /* 1 = 16bit */ -#define SCTRL_P2SMB 0x00000004 /* 1 = stereo */ -#define SCTRL_P2FMT 0x0000000c /* format mask */ -#define SCTRL_SH_P2FMT 2 -#define SCTRL_P1SEB 0x00000002 /* 1 = 16bit */ -#define SCTRL_P1SMB 0x00000001 /* 1 = stereo */ -#define SCTRL_P1FMT 0x00000003 /* format mask */ -#define SCTRL_SH_P1FMT 0 - - -/* misc stuff */ -#define POLL_COUNT 0x1000 -#define FMODE_DAC 4 /* slight misuse of mode_t */ - -/* MIDI buffer sizes */ - -#define MIDIINBUF 256 -#define MIDIOUTBUF 256 - -#define FMODE_MIDI_SHIFT 3 -#define FMODE_MIDI_READ (FMODE_READ << FMODE_MIDI_SHIFT) -#define FMODE_MIDI_WRITE (FMODE_WRITE << FMODE_MIDI_SHIFT) - -#define ES1371_MODULE_NAME "es1371" -#define PFX ES1371_MODULE_NAME ": " - -/* --------------------------------------------------------------------- */ - -struct es1371_state { - /* magic */ - unsigned int magic; - - /* list of es1371 devices */ - struct list_head devs; - - /* the corresponding pci_dev structure */ - struct pci_dev *dev; - - /* soundcore stuff */ - int dev_audio; - int dev_dac; - int dev_midi; - - /* hardware resources */ - unsigned long io; /* long for SPARC */ - unsigned int irq; - - /* PCI ID's */ - u16 vendor; - u16 device; - u8 rev; /* the chip revision */ - - /* options */ - int spdif_volume; /* S/PDIF output is enabled if != -1 */ - -#ifdef ES1371_DEBUG - /* debug /proc entry */ - struct proc_dir_entry *ps; -#endif /* ES1371_DEBUG */ - - struct ac97_codec *codec; - - /* wave stuff */ - unsigned ctrl; - unsigned sctrl; - unsigned dac1rate, dac2rate, adcrate; - - spinlock_t lock; - struct mutex open_mutex; - mode_t open_mode; - wait_queue_head_t open_wait; - - struct dmabuf { - void *rawbuf; - dma_addr_t dmaaddr; - unsigned buforder; - unsigned numfrag; - unsigned fragshift; - unsigned hwptr, swptr; - unsigned total_bytes; - int count; - unsigned error; /* over/underrun */ - wait_queue_head_t wait; - /* redundant, but makes calculations easier */ - unsigned fragsize; - unsigned dmasize; - unsigned fragsamples; - /* OSS stuff */ - unsigned mapped:1; - unsigned ready:1; - unsigned endcleared:1; - unsigned enabled:1; - unsigned ossfragshift; - int ossmaxfrags; - unsigned subdivision; - } dma_dac1, dma_dac2, dma_adc; - - /* midi stuff */ - struct { - unsigned ird, iwr, icnt; - unsigned ord, owr, ocnt; - wait_queue_head_t iwait; - wait_queue_head_t owait; - unsigned char ibuf[MIDIINBUF]; - unsigned char obuf[MIDIOUTBUF]; - } midi; - -#ifdef SUPPORT_JOYSTICK - struct gameport *gameport; -#endif - - struct mutex sem; -}; - -/* --------------------------------------------------------------------- */ - -static LIST_HEAD(devs); - -/* --------------------------------------------------------------------- */ - -static inline unsigned ld2(unsigned int x) -{ - unsigned r = 0; - - if (x >= 0x10000) { - x >>= 16; - r += 16; - } - if (x >= 0x100) { - x >>= 8; - r += 8; - } - if (x >= 0x10) { - x >>= 4; - r += 4; - } - if (x >= 4) { - x >>= 2; - r += 2; - } - if (x >= 2) - r++; - return r; -} - -/* --------------------------------------------------------------------- */ - -static unsigned wait_src_ready(struct es1371_state *s) -{ - unsigned int t, r; - - for (t = 0; t < POLL_COUNT; t++) { - if (!((r = inl(s->io + ES1371_REG_SRCONV)) & SRC_BUSY)) - return r; - udelay(1); - } - printk(KERN_DEBUG PFX "sample rate converter timeout r = 0x%08x\n", r); - return r; -} - -static unsigned src_read(struct es1371_state *s, unsigned reg) -{ - unsigned int temp,i,orig; - - /* wait for ready */ - temp = wait_src_ready (s); - - /* we can only access the SRC at certain times, make sure - we're allowed to before we read */ - - orig = temp; - /* expose the SRC state bits */ - outl ( (temp & SRC_CTLMASK) | (reg << SRC_RAMADDR_SHIFT) | 0x10000UL, - s->io + ES1371_REG_SRCONV); - - /* now, wait for busy and the correct time to read */ - temp = wait_src_ready (s); - - if ( (temp & 0x00870000UL ) != ( SRC_OKSTATE << 16 )){ - /* wait for the right state */ - for (i=0; i<POLL_COUNT; i++){ - temp = inl (s->io + ES1371_REG_SRCONV); - if ( (temp & 0x00870000UL ) == ( SRC_OKSTATE << 16 )) - break; - } - } - - /* hide the state bits */ - outl ((orig & SRC_CTLMASK) | (reg << SRC_RAMADDR_SHIFT), s->io + ES1371_REG_SRCONV); - return temp; - - -} - -static void src_write(struct es1371_state *s, unsigned reg, unsigned data) -{ - - unsigned int r; - - r = wait_src_ready(s) & (SRC_DIS | SRC_DDAC1 | SRC_DDAC2 | SRC_DADC); - r |= (reg << SRC_RAMADDR_SHIFT) & SRC_RAMADDR_MASK; - r |= (data << SRC_RAMDATA_SHIFT) & SRC_RAMDATA_MASK; - outl(r | SRC_WE, s->io + ES1371_REG_SRCONV); - -} - -/* --------------------------------------------------------------------- */ - -/* most of the following here is black magic */ -static void set_adc_rate(struct es1371_state *s, unsigned rate) -{ - unsigned long flags; - unsigned int n, truncm, freq; - - if (rate > 48000) - rate = 48000; - if (rate < 4000) - rate = 4000; - n = rate / 3000; - if ((1 << n) & ((1 << 15) | (1 << 13) | (1 << 11) | (1 << 9))) - n--; - truncm = (21 * n - 1) | 1; - freq = ((48000UL << 15) / rate) * n; - s->adcrate = (48000UL << 15) / (freq / n); - spin_lock_irqsave(&s->lock, flags); - if (rate >= 24000) { - if (truncm > 239) - truncm = 239; - src_write(s, SRCREG_ADC+SRCREG_TRUNC_N, - (((239 - truncm) >> 1) << 9) | (n << 4)); - } else { - if (truncm > 119) - truncm = 119; - src_write(s, SRCREG_ADC+SRCREG_TRUNC_N, - 0x8000 | (((119 - truncm) >> 1) << 9) | (n << 4)); - } - src_write(s, SRCREG_ADC+SRCREG_INT_REGS, - (src_read(s, SRCREG_ADC+SRCREG_INT_REGS) & 0x00ff) | - ((freq >> 5) & 0xfc00)); - src_write(s, SRCREG_ADC+SRCREG_VFREQ_FRAC, freq & 0x7fff); - src_write(s, SRCREG_VOL_ADC, n << 8); - src_write(s, SRCREG_VOL_ADC+1, n << 8); - spin_unlock_irqrestore(&s->lock, flags); -} - - -static void set_dac1_rate(struct es1371_state *s, unsigned rate) -{ - unsigned long flags; - unsigned int freq, r; - - if (rate > 48000) - rate = 48000; - if (rate < 4000) - rate = 4000; - freq = ((rate << 15) + 1500) / 3000; - s->dac1rate = (freq * 3000 + 16384) >> 15; - spin_lock_irqsave(&s->lock, flags); - r = (wait_src_ready(s) & (SRC_DIS | SRC_DDAC2 | SRC_DADC)) | SRC_DDAC1; - outl(r, s->io + ES1371_REG_SRCONV); - src_write(s, SRCREG_DAC1+SRCREG_INT_REGS, - (src_read(s, SRCREG_DAC1+SRCREG_INT_REGS) & 0x00ff) | - ((freq >> 5) & 0xfc00)); - src_write(s, SRCREG_DAC1+SRCREG_VFREQ_FRAC, freq & 0x7fff); - r = (wait_src_ready(s) & (SRC_DIS | SRC_DDAC2 | SRC_DADC)); - outl(r, s->io + ES1371_REG_SRCONV); - spin_unlock_irqrestore(&s->lock, flags); -} - -static void set_dac2_rate(struct es1371_state *s, unsigned rate) -{ - unsigned long flags; - unsigned int freq, r; - - if (rate > 48000) - rate = 48000; - if (rate < 4000) - rate = 4000; - freq = ((rate << 15) + 1500) / 3000; - s->dac2rate = (freq * 3000 + 16384) >> 15; - spin_lock_irqsave(&s->lock, flags); - r = (wait_src_ready(s) & (SRC_DIS | SRC_DDAC1 | SRC_DADC)) | SRC_DDAC2; - outl(r, s->io + ES1371_REG_SRCONV); - src_write(s, SRCREG_DAC2+SRCREG_INT_REGS, - (src_read(s, SRCREG_DAC2+SRCREG_INT_REGS) & 0x00ff) | - ((freq >> 5) & 0xfc00)); - src_write(s, SRCREG_DAC2+SRCREG_VFREQ_FRAC, freq & 0x7fff); - r = (wait_src_ready(s) & (SRC_DIS | SRC_DDAC1 | SRC_DADC)); - outl(r, s->io + ES1371_REG_SRCONV); - spin_unlock_irqrestore(&s->lock, flags); -} - -/* --------------------------------------------------------------------- */ - -static void __devinit src_init(struct es1371_state *s) -{ - unsigned int i; - - /* before we enable or disable the SRC we need - to wait for it to become ready */ - wait_src_ready(s); - - outl(SRC_DIS, s->io + ES1371_REG_SRCONV); - - for (i = 0; i < 0x80; i++) - src_write(s, i, 0); - - src_write(s, SRCREG_DAC1+SRCREG_TRUNC_N, 16 << 4); - src_write(s, SRCREG_DAC1+SRCREG_INT_REGS, 16 << 10); - src_write(s, SRCREG_DAC2+SRCREG_TRUNC_N, 16 << 4); - src_write(s, SRCREG_DAC2+SRCREG_INT_REGS, 16 << 10); - src_write(s, SRCREG_VOL_ADC, 1 << 12); - src_write(s, SRCREG_VOL_ADC+1, 1 << 12); - src_write(s, SRCREG_VOL_DAC1, 1 << 12); - src_write(s, SRCREG_VOL_DAC1+1, 1 << 12); - src_write(s, SRCREG_VOL_DAC2, 1 << 12); - src_write(s, SRCREG_VOL_DAC2+1, 1 << 12); - set_adc_rate(s, 22050); - set_dac1_rate(s, 22050); - set_dac2_rate(s, 22050); - - /* WARNING: - * enabling the sample rate converter without properly programming - * its parameters causes the chip to lock up (the SRC busy bit will - * be stuck high, and I've found no way to rectify this other than - * power cycle) - */ - wait_src_ready(s); - outl(0, s->io+ES1371_REG_SRCONV); -} - -/* --------------------------------------------------------------------- */ - -static void wrcodec(struct ac97_codec *codec, u8 addr, u16 data) -{ - struct es1371_state *s = (struct es1371_state *)codec->private_data; - unsigned long flags; - unsigned t, x; - - spin_lock_irqsave(&s->lock, flags); - for (t = 0; t < POLL_COUNT; t++) - if (!(inl(s->io+ES1371_REG_CODEC) & CODEC_WIP)) - break; - - /* save the current state for later */ - x = wait_src_ready(s); - - /* enable SRC state data in SRC mux */ - outl((x & (SRC_DIS | SRC_DDAC1 | SRC_DDAC2 | SRC_DADC)) | 0x00010000, - s->io+ES1371_REG_SRCONV); - - /* wait for not busy (state 0) first to avoid - transition states */ - for (t=0; t<POLL_COUNT; t++){ - if((inl(s->io+ES1371_REG_SRCONV) & 0x00870000) ==0 ) - break; - udelay(1); - } - - /* wait for a SAFE time to write addr/data and then do it, dammit */ - for (t=0; t<POLL_COUNT; t++){ - if((inl(s->io+ES1371_REG_SRCONV) & 0x00870000) ==0x00010000) - break; - udelay(1); - } - - outl(((addr << CODEC_POADD_SHIFT) & CODEC_POADD_MASK) | - ((data << CODEC_PODAT_SHIFT) & CODEC_PODAT_MASK), s->io+ES1371_REG_CODEC); - - /* restore SRC reg */ - wait_src_ready(s); - outl(x, s->io+ES1371_REG_SRCONV); - spin_unlock_irqrestore(&s->lock, flags); -} - -static u16 rdcodec(struct ac97_codec *codec, u8 addr) -{ - struct es1371_state *s = (struct es1371_state *)codec->private_data; - unsigned long flags; - unsigned t, x; - - spin_lock_irqsave(&s->lock, flags); - - /* wait for WIP to go away */ - for (t = 0; t < 0x1000; t++) - if (!(inl(s->io+ES1371_REG_CODEC) & CODEC_WIP)) - break; - - /* save the current state for later */ - x = (wait_src_ready(s) & (SRC_DIS | SRC_DDAC1 | SRC_DDAC2 | SRC_DADC)); - - /* enable SRC state data in SRC mux */ - outl( x | 0x00010000, - s->io+ES1371_REG_SRCONV); - - /* wait for not busy (state 0) first to avoid - transition states */ - for (t=0; t<POLL_COUNT; t++){ - if((inl(s->io+ES1371_REG_SRCONV) & 0x00870000) ==0 ) - break; - udelay(1); - } - - /* wait for a SAFE time to write addr/data and then do it, dammit */ - for (t=0; t<POLL_COUNT; t++){ - if((inl(s->io+ES1371_REG_SRCONV) & 0x00870000) ==0x00010000) - break; - udelay(1); - } - - outl(((addr << CODEC_POADD_SHIFT) & CODEC_POADD_MASK) | CODEC_PORD, s->io+ES1371_REG_CODEC); - /* restore SRC reg */ - wait_src_ready(s); - outl(x, s->io+ES1371_REG_SRCONV); - - /* wait for WIP again */ - for (t = 0; t < 0x1000; t++) - if (!(inl(s->io+ES1371_REG_CODEC) & CODEC_WIP)) - break; - - /* now wait for the stinkin' data (RDY) */ - for (t = 0; t < POLL_COUNT; t++) - if ((x = inl(s->io+ES1371_REG_CODEC)) & CODEC_RDY) - break; - - spin_unlock_irqrestore(&s->lock, flags); - return ((x & CODEC_PIDAT_MASK) >> CODEC_PIDAT_SHIFT); -} - -/* --------------------------------------------------------------------- */ - -static inline void stop_adc(struct es1371_state *s) -{ - unsigned long flags; - - spin_lock_irqsave(&s->lock, flags); - s->ctrl &= ~CTRL_ADC_EN; - outl(s->ctrl, s->io+ES1371_REG_CONTROL); - spin_unlock_irqrestore(&s->lock, flags); -} - -static inline void stop_dac1(struct es1371_state *s) -{ - unsigned long flags; - - spin_lock_irqsave(&s->lock, flags); - s->ctrl &= ~CTRL_DAC1_EN; - outl(s->ctrl, s->io+ES1371_REG_CONTROL); - spin_unlock_irqrestore(&s->lock, flags); -} - -static inline void stop_dac2(struct es1371_state *s) -{ - unsigned long flags; - - spin_lock_irqsave(&s->lock, flags); - s->ctrl &= ~CTRL_DAC2_EN; - outl(s->ctrl, s->io+ES1371_REG_CONTROL); - spin_unlock_irqrestore(&s->lock, flags); -} - -static void start_dac1(struct es1371_state *s) -{ - unsigned long flags; - unsigned fragremain, fshift; - - spin_lock_irqsave(&s->lock, flags); - if (!(s->ctrl & CTRL_DAC1_EN) && (s->dma_dac1.mapped || s->dma_dac1.count > 0) - && s->dma_dac1.ready) { - s->ctrl |= CTRL_DAC1_EN; - s->sctrl = (s->sctrl & ~(SCTRL_P1LOOPSEL | SCTRL_P1PAUSE | SCTRL_P1SCTRLD)) | SCTRL_P1INTEN; - outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL); - fragremain = ((- s->dma_dac1.hwptr) & (s->dma_dac1.fragsize-1)); - fshift = sample_shift[(s->sctrl & SCTRL_P1FMT) >> SCTRL_SH_P1FMT]; - if (fragremain < 2*fshift) - fragremain = s->dma_dac1.fragsize; - outl((fragremain >> fshift) - 1, s->io+ES1371_REG_DAC1_SCOUNT); - outl(s->ctrl, s->io+ES1371_REG_CONTROL); - outl((s->dma_dac1.fragsize >> fshift) - 1, s->io+ES1371_REG_DAC1_SCOUNT); - } - spin_unlock_irqrestore(&s->lock, flags); -} - -static void start_dac2(struct es1371_state *s) -{ - unsigned long flags; - unsigned fragremain, fshift; - - spin_lock_irqsave(&s->lock, flags); - if (!(s->ctrl & CTRL_DAC2_EN) && (s->dma_dac2.mapped || s->dma_dac2.count > 0) - && s->dma_dac2.ready) { - s->ctrl |= CTRL_DAC2_EN; - s->sctrl = (s->sctrl & ~(SCTRL_P2LOOPSEL | SCTRL_P2PAUSE | SCTRL_P2DACSEN | - SCTRL_P2ENDINC | SCTRL_P2STINC)) | SCTRL_P2INTEN | - (((s->sctrl & SCTRL_P2FMT) ? 2 : 1) << SCTRL_SH_P2ENDINC) | - (0 << SCTRL_SH_P2STINC); - outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL); - fragremain = ((- s->dma_dac2.hwptr) & (s->dma_dac2.fragsize-1)); - fshift = sample_shift[(s->sctrl & SCTRL_P2FMT) >> SCTRL_SH_P2FMT]; - if (fragremain < 2*fshift) - fragremain = s->dma_dac2.fragsize; - outl((fragremain >> fshift) - 1, s->io+ES1371_REG_DAC2_SCOUNT); - outl(s->ctrl, s->io+ES1371_REG_CONTROL); - outl((s->dma_dac2.fragsize >> fshift) - 1, s->io+ES1371_REG_DAC2_SCOUNT); - } - spin_unlock_irqrestore(&s->lock, flags); -} - -static void start_adc(struct es1371_state *s) -{ - unsigned long flags; - unsigned fragremain, fshift; - - spin_lock_irqsave(&s->lock, flags); - if (!(s->ctrl & CTRL_ADC_EN) && (s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize)) - && s->dma_adc.ready) { - s->ctrl |= CTRL_ADC_EN; - s->sctrl = (s->sctrl & ~SCTRL_R1LOOPSEL) | SCTRL_R1INTEN; - outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL); - fragremain = ((- s->dma_adc.hwptr) & (s->dma_adc.fragsize-1)); - fshift = sample_shift[(s->sctrl & SCTRL_R1FMT) >> SCTRL_SH_R1FMT]; - if (fragremain < 2*fshift) - fragremain = s->dma_adc.fragsize; - outl((fragremain >> fshift) - 1, s->io+ES1371_REG_ADC_SCOUNT); - outl(s->ctrl, s->io+ES1371_REG_CONTROL); - outl((s->dma_adc.fragsize >> fshift) - 1, s->io+ES1371_REG_ADC_SCOUNT); - } - spin_unlock_irqrestore(&s->lock, flags); -} - -/* --------------------------------------------------------------------- */ - -#define DMABUF_DEFAULTORDER (17-PAGE_SHIFT) -#define DMABUF_MINORDER 1 - - -static inline void dealloc_dmabuf(struct es1371_state *s, struct dmabuf *db) -{ - struct page *page, *pend; - - if (db->rawbuf) { - /* undo marking the pages as reserved */ - pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1); - for (page = virt_to_page(db->rawbuf); page <= pend; page++) - ClearPageReserved(page); - pci_free_consistent(s->dev, PAGE_SIZE << db->buforder, db->rawbuf, db->dmaaddr); - } - db->rawbuf = NULL; - db->mapped = db->ready = 0; -} - -static int prog_dmabuf(struct es1371_state *s, struct dmabuf *db, unsigned rate, unsigned fmt, unsigned reg) -{ - int order; - unsigned bytepersec; - unsigned bufs; - struct page *page, *pend; - - db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0; - if (!db->rawbuf) { - db->ready = db->mapped = 0; - for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) - if ((db->rawbuf = pci_alloc_consistent(s->dev, PAGE_SIZE << order, &db->dmaaddr))) - break; - if (!db->rawbuf) - return -ENOMEM; - db->buforder = order; - /* now mark the pages as reserved; otherwise remap_pfn_range doesn't do what we want */ - pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1); - for (page = virt_to_page(db->rawbuf); page <= pend; page++) - SetPageReserved(page); - } - fmt &= ES1371_FMT_MASK; - bytepersec = rate << sample_shift[fmt]; - bufs = PAGE_SIZE << db->buforder; - if (db->ossfragshift) { - if ((1000 << db->ossfragshift) < bytepersec) - db->fragshift = ld2(bytepersec/1000); - else - db->fragshift = db->ossfragshift; - } else { - db->fragshift = ld2(bytepersec/100/(db->subdivision ? db->subdivision : 1)); - if (db->fragshift < 3) - db->fragshift = 3; - } - db->numfrag = bufs >> db->fragshift; - while (db->numfrag < 4 && db->fragshift > 3) { - db->fragshift--; - db->numfrag = bufs >> db->fragshift; - } - db->fragsize = 1 << db->fragshift; - if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag) - db->numfrag = db->ossmaxfrags; - db->fragsamples = db->fragsize >> sample_shift[fmt]; - db->dmasize = db->numfrag << db->fragshift; - memset(db->rawbuf, (fmt & ES1371_FMT_S16) ? 0 : 0x80, db->dmasize); - outl((reg >> 8) & 15, s->io+ES1371_REG_MEMPAGE); - outl(db->dmaaddr, s->io+(reg & 0xff)); - outl((db->dmasize >> 2)-1, s->io+((reg + 4) & 0xff)); - db->enabled = 1; - db->ready = 1; - return 0; -} - -static inline int prog_dmabuf_adc(struct es1371_state *s) -{ - stop_adc(s); - return prog_dmabuf(s, &s->dma_adc, s->adcrate, (s->sctrl >> SCTRL_SH_R1FMT) & ES1371_FMT_MASK, - ES1371_REG_ADC_FRAMEADR); -} - -static inline int prog_dmabuf_dac2(struct es1371_state *s) -{ - stop_dac2(s); - return prog_dmabuf(s, &s->dma_dac2, s->dac2rate, (s->sctrl >> SCTRL_SH_P2FMT) & ES1371_FMT_MASK, - ES1371_REG_DAC2_FRAMEADR); -} - -static inline int prog_dmabuf_dac1(struct es1371_state *s) -{ - stop_dac1(s); - return prog_dmabuf(s, &s->dma_dac1, s->dac1rate, (s->sctrl >> SCTRL_SH_P1FMT) & ES1371_FMT_MASK, - ES1371_REG_DAC1_FRAMEADR); -} - -static inline unsigned get_hwptr(struct es1371_state *s, struct dmabuf *db, unsigned reg) -{ - unsigned hwptr, diff; - - outl((reg >> 8) & 15, s->io+ES1371_REG_MEMPAGE); - hwptr = (inl(s->io+(reg & 0xff)) >> 14) & 0x3fffc; - diff = (db->dmasize + hwptr - db->hwptr) % db->dmasize; - db->hwptr = hwptr; - return diff; -} - -static inline void clear_advance(void *buf, unsigned bsize, unsigned bptr, unsigned len, unsigned char c) -{ - if (bptr + len > bsize) { - unsigned x = bsize - bptr; - memset(((char *)buf) + bptr, c, x); - bptr = 0; - len -= x; - } - memset(((char *)buf) + bptr, c, len); -} - -/* call with spinlock held! */ -static void es1371_update_ptr(struct es1371_state *s) -{ - int diff; - - /* update ADC pointer */ - if (s->ctrl & CTRL_ADC_EN) { - diff = get_hwptr(s, &s->dma_adc, ES1371_REG_ADC_FRAMECNT); - s->dma_adc.total_bytes += diff; - s->dma_adc.count += diff; - if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) - wake_up(&s->dma_adc.wait); - if (!s->dma_adc.mapped) { - if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) { - s->ctrl &= ~CTRL_ADC_EN; - outl(s->ctrl, s->io+ES1371_REG_CONTROL); - s->dma_adc.error++; - } - } - } - /* update DAC1 pointer */ - if (s->ctrl & CTRL_DAC1_EN) { - diff = get_hwptr(s, &s->dma_dac1, ES1371_REG_DAC1_FRAMECNT); - s->dma_dac1.total_bytes += diff; - if (s->dma_dac1.mapped) { - s->dma_dac1.count += diff; - if (s->dma_dac1.count >= (signed)s->dma_dac1.fragsize) - wake_up(&s->dma_dac1.wait); - } else { - s->dma_dac1.count -= diff; - if (s->dma_dac1.count <= 0) { - s->ctrl &= ~CTRL_DAC1_EN; - outl(s->ctrl, s->io+ES1371_REG_CONTROL); - s->dma_dac1.error++; - } else if (s->dma_dac1.count <= (signed)s->dma_dac1.fragsize && !s->dma_dac1.endcleared) { - clear_advance(s->dma_dac1.rawbuf, s->dma_dac1.dmasize, s->dma_dac1.swptr, - s->dma_dac1.fragsize, (s->sctrl & SCTRL_P1SEB) ? 0 : 0x80); - s->dma_dac1.endcleared = 1; - } - if (s->dma_dac1.count + (signed)s->dma_dac1.fragsize <= (signed)s->dma_dac1.dmasize) - wake_up(&s->dma_dac1.wait); - } - } - /* update DAC2 pointer */ - if (s->ctrl & CTRL_DAC2_EN) { - diff = get_hwptr(s, &s->dma_dac2, ES1371_REG_DAC2_FRAMECNT); - s->dma_dac2.total_bytes += diff; - if (s->dma_dac2.mapped) { - s->dma_dac2.count += diff; - if (s->dma_dac2.count >= (signed)s->dma_dac2.fragsize) - wake_up(&s->dma_dac2.wait); - } else { - s->dma_dac2.count -= diff; - if (s->dma_dac2.count <= 0) { - s->ctrl &= ~CTRL_DAC2_EN; - outl(s->ctrl, s->io+ES1371_REG_CONTROL); - s->dma_dac2.error++; - } else if (s->dma_dac2.count <= (signed)s->dma_dac2.fragsize && !s->dma_dac2.endcleared) { - clear_advance(s->dma_dac2.rawbuf, s->dma_dac2.dmasize, s->dma_dac2.swptr, - s->dma_dac2.fragsize, (s->sctrl & SCTRL_P2SEB) ? 0 : 0x80); - s->dma_dac2.endcleared = 1; - } - if (s->dma_dac2.count + (signed)s->dma_dac2.fragsize <= (signed)s->dma_dac2.dmasize) - wake_up(&s->dma_dac2.wait); - } - } -} - -/* hold spinlock for the following! */ -static void es1371_handle_midi(struct es1371_state *s) -{ - unsigned char ch; - int wake; - - if (!(s->ctrl & CTRL_UART_EN)) - return; - wake = 0; - while (inb(s->io+ES1371_REG_UART_STATUS) & USTAT_RXRDY) { - ch = inb(s->io+ES1371_REG_UART_DATA); - if (s->midi.icnt < MIDIINBUF) { - s->midi.ibuf[s->midi.iwr] = ch; - s->midi.iwr = (s->midi.iwr + 1) % MIDIINBUF; - s->midi.icnt++; - } - wake = 1; - } - if (wake) - wake_up(&s->midi.iwait); - wake = 0; - while ((inb(s->io+ES1371_REG_UART_STATUS) & USTAT_TXRDY) && s->midi.ocnt > 0) { - outb(s->midi.obuf[s->midi.ord], s->io+ES1371_REG_UART_DATA); - s->midi.ord = (s->midi.ord + 1) % MIDIOUTBUF; - s->midi.ocnt--; - if (s->midi.ocnt < MIDIOUTBUF-16) - wake = 1; - } - if (wake) - wake_up(&s->midi.owait); - outb((s->midi.ocnt > 0) ? UCTRL_RXINTEN | UCTRL_ENA_TXINT : UCTRL_RXINTEN, s->io+ES1371_REG_UART_CONTROL); -} - -static irqreturn_t es1371_interrupt(int irq, void *dev_id) -{ - struct es1371_state *s = dev_id; - unsigned int intsrc, sctl; - - /* fastpath out, to ease interrupt sharing */ - intsrc = inl(s->io+ES1371_REG_STATUS); - if (!(intsrc & 0x80000000)) - return IRQ_NONE; - spin_lock(&s->lock); - /* clear audio interrupts first */ - sctl = s->sctrl; - if (intsrc & STAT_ADC) - sctl &= ~SCTRL_R1INTEN; - if (intsrc & STAT_DAC1) - sctl &= ~SCTRL_P1INTEN; - if (intsrc & STAT_DAC2) - sctl &= ~SCTRL_P2INTEN; - outl(sctl, s->io+ES1371_REG_SERIAL_CONTROL); - outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL); - es1371_update_ptr(s); - es1371_handle_midi(s); - spin_unlock(&s->lock); - return IRQ_HANDLED; -} - -/* --------------------------------------------------------------------- */ - -static const char invalid_magic[] = KERN_CRIT PFX "invalid magic value\n"; - -#define VALIDATE_STATE(s) \ -({ \ - if (!(s) || (s)->magic != ES1371_MAGIC) { \ - printk(invalid_magic); \ - return -ENXIO; \ - } \ -}) - -/* --------------------------------------------------------------------- */ - -/* Conversion table for S/PDIF PCM volume emulation through the SRC */ -/* dB-linear table of DAC vol values; -0dB to -46.5dB with mute */ -static const unsigned short DACVolTable[101] = -{ - 0x1000, 0x0f2a, 0x0e60, 0x0da0, 0x0cea, 0x0c3e, 0x0b9a, 0x0aff, - 0x0a6d, 0x09e1, 0x095e, 0x08e1, 0x086a, 0x07fa, 0x078f, 0x072a, - 0x06cb, 0x0670, 0x061a, 0x05c9, 0x057b, 0x0532, 0x04ed, 0x04ab, - 0x046d, 0x0432, 0x03fa, 0x03c5, 0x0392, 0x0363, 0x0335, 0x030b, - 0x02e2, 0x02bc, 0x0297, 0x0275, 0x0254, 0x0235, 0x0217, 0x01fb, - 0x01e1, 0x01c8, 0x01b0, 0x0199, 0x0184, 0x0170, 0x015d, 0x014b, - 0x0139, 0x0129, 0x0119, 0x010b, 0x00fd, 0x00f0, 0x00e3, 0x00d7, - 0x00cc, 0x00c1, 0x00b7, 0x00ae, 0x00a5, 0x009c, 0x0094, 0x008c, - 0x0085, 0x007e, 0x0077, 0x0071, 0x006b, 0x0066, 0x0060, 0x005b, - 0x0057, 0x0052, 0x004e, 0x004a, 0x0046, 0x0042, 0x003f, 0x003c, - 0x0038, 0x0036, 0x0033, 0x0030, 0x002e, 0x002b, 0x0029, 0x0027, - 0x0025, 0x0023, 0x0021, 0x001f, 0x001e, 0x001c, 0x001b, 0x0019, - 0x0018, 0x0017, 0x0016, 0x0014, 0x0000 -}; - -/* - * when we are in S/PDIF mode, we want to disable any analog output so - * we filter the mixer ioctls - */ -static int mixdev_ioctl(struct ac97_codec *codec, unsigned int cmd, unsigned long arg) -{ - struct es1371_state *s = (struct es1371_state *)codec->private_data; - int val; - unsigned long flags; - unsigned int left, right; - - VALIDATE_STATE(s); - /* filter mixer ioctls to catch PCM and MASTER volume when in S/PDIF mode */ - if (s->spdif_volume == -1) - return codec->mixer_ioctl(codec, cmd, arg); - switch (cmd) { - case SOUND_MIXER_WRITE_VOLUME: - return 0; - - case SOUND_MIXER_WRITE_PCM: /* use SRC for PCM volume */ - if (get_user(val, (int __user *)arg)) - return -EFAULT; - right = ((val >> 8) & 0xff); - left = (val & 0xff); - if (right > 100) - right = 100; - if (left > 100) - left = 100; - s->spdif_volume = (right << 8) | left; - spin_lock_irqsave(&s->lock, flags); - src_write(s, SRCREG_VOL_DAC2, DACVolTable[100 - left]); - src_write(s, SRCREG_VOL_DAC2+1, DACVolTable[100 - right]); - spin_unlock_irqrestore(&s->lock, flags); - return 0; - - case SOUND_MIXER_READ_PCM: - return put_user(s->spdif_volume, (int __user *)arg); - } - return codec->mixer_ioctl(codec, cmd, arg); -} - -/* --------------------------------------------------------------------- */ - -/* - * AC97 Mixer Register to Connections mapping of the Concert 97 board - * - * AC97_MASTER_VOL_STEREO Line Out - * AC97_MASTER_VOL_MONO TAD Output - * AC97_PCBEEP_VOL none - * AC97_PHONE_VOL TAD Input (mono) - * AC97_MIC_VOL MIC Input (mono) - * AC97_LINEIN_VOL Line Input (stereo) - * AC97_CD_VOL CD Input (stereo) - * AC97_VIDEO_VOL none - * AC97_AUX_VOL Aux Input (stereo) - * AC97_PCMOUT_VOL Wave Output (stereo) - */ - -static int es1371_open_mixdev(struct inode *inode, struct file *file) -{ - int minor = iminor(inode); - struct list_head *list; - struct es1371_state *s; - - for (list = devs.next; ; list = list->next) { - if (list == &devs) - return -ENODEV; - s = list_entry(list, struct es1371_state, devs); - if (s->codec->dev_mixer == minor) - break; - } - VALIDATE_STATE(s); - file->private_data = s; - return nonseekable_open(inode, file); -} - -static int es1371_release_mixdev(struct inode *inode, struct file *file) -{ - struct es1371_state *s = (struct es1371_state *)file->private_data; - - VALIDATE_STATE(s); - return 0; -} - -static int es1371_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -{ - struct es1371_state *s = (struct es1371_state *)file->private_data; - struct ac97_codec *codec = s->codec; - - return mixdev_ioctl(codec, cmd, arg); -} - -static /*const*/ struct file_operations es1371_mixer_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .ioctl = es1371_ioctl_mixdev, - .open = es1371_open_mixdev, - .release = es1371_release_mixdev, -}; - -/* --------------------------------------------------------------------- */ - -static int drain_dac1(struct es1371_state *s, int nonblock) -{ - DECLARE_WAITQUEUE(wait, current); - unsigned long flags; - int count, tmo; - - if (s->dma_dac1.mapped || !s->dma_dac1.ready) - return 0; - add_wait_queue(&s->dma_dac1.wait, &wait); - for (;;) { - __set_current_state(TASK_INTERRUPTIBLE); - spin_lock_irqsave(&s->lock, flags); - count = s->dma_dac1.count; - spin_unlock_irqrestore(&s->lock, flags); - if (count <= 0) - break; - if (signal_pending(current)) - break; - if (nonblock) { - remove_wait_queue(&s->dma_dac1.wait, &wait); - set_current_state(TASK_RUNNING); - return -EBUSY; - } - tmo = 3 * HZ * (count + s->dma_dac1.fragsize) / 2 / s->dac1rate; - tmo >>= sample_shift[(s->sctrl & SCTRL_P1FMT) >> SCTRL_SH_P1FMT]; - if (!schedule_timeout(tmo + 1)) - DBG(printk(KERN_DEBUG PFX "dac1 dma timed out??\n");) - } - remove_wait_queue(&s->dma_dac1.wait, &wait); - set_current_state(TASK_RUNNING); - if (signal_pending(current)) - return -ERESTARTSYS; - return 0; -} - -static int drain_dac2(struct es1371_state *s, int nonblock) -{ - DECLARE_WAITQUEUE(wait, current); - unsigned long flags; - int count, tmo; - - if (s->dma_dac2.mapped || !s->dma_dac2.ready) - return 0; - add_wait_queue(&s->dma_dac2.wait, &wait); - for (;;) { - __set_current_state(TASK_UNINTERRUPTIBLE); - spin_lock_irqsave(&s->lock, flags); - count = s->dma_dac2.count; - spin_unlock_irqrestore(&s->lock, flags); - if (count <= 0) - break; - if (signal_pending(current)) - break; - if (nonblock) { - remove_wait_queue(&s->dma_dac2.wait, &wait); - set_current_state(TASK_RUNNING); - return -EBUSY; - } - tmo = 3 * HZ * (count + s->dma_dac2.fragsize) / 2 / s->dac2rate; - tmo >>= sample_shift[(s->sctrl & SCTRL_P2FMT) >> SCTRL_SH_P2FMT]; - if (!schedule_timeout(tmo + 1)) - DBG(printk(KERN_DEBUG PFX "dac2 dma timed out??\n");) - } - remove_wait_queue(&s->dma_dac2.wait, &wait); - set_current_state(TASK_RUNNING); - if (signal_pending(current)) - return -ERESTARTSYS; - return 0; -} - -/* --------------------------------------------------------------------- */ - -static ssize_t es1371_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) -{ - struct es1371_state *s = (struct es1371_state *)file->private_data; - DECLARE_WAITQUEUE(wait, current); - ssize_t ret = 0; - unsigned long flags; - unsigned swptr; - int cnt; - - VALIDATE_STATE(s); - if (s->dma_adc.mapped) - return -ENXIO; - if (!access_ok(VERIFY_WRITE, buffer, count)) - return -EFAULT; - mutex_lock(&s->sem); - if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s))) - goto out2; - - add_wait_queue(&s->dma_adc.wait, &wait); - while (count > 0) { - spin_lock_irqsave(&s->lock, flags); - swptr = s->dma_adc.swptr; - cnt = s->dma_adc.dmasize-swptr; - if (s->dma_adc.count < cnt) - cnt = s->dma_adc.count; - if (cnt <= 0) - __set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irqrestore(&s->lock, flags); - if (cnt > count) - cnt = count; - if (cnt <= 0) { - if (s->dma_adc.enabled) - start_adc(s); - if (file->f_flags & O_NONBLOCK) { - if (!ret) - ret = -EAGAIN; - goto out; - } - mutex_unlock(&s->sem); - schedule(); - if (signal_pending(current)) { - if (!ret) - ret = -ERESTARTSYS; - goto out2; - } - mutex_lock(&s->sem); - if (s->dma_adc.mapped) - { - ret = -ENXIO; - goto out; - } - continue; - } - if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) { - if (!ret) - ret = -EFAULT; - goto out; - } - swptr = (swptr + cnt) % s->dma_adc.dmasize; - spin_lock_irqsave(&s->lock, flags); - s->dma_adc.swptr = swptr; - s->dma_adc.count -= cnt; - spin_unlock_irqrestore(&s->lock, flags); - count -= cnt; - buffer += cnt; - ret += cnt; - if (s->dma_adc.enabled) - start_adc(s); - } -out: - mutex_unlock(&s->sem); -out2: - remove_wait_queue(&s->dma_adc.wait, &wait); - set_current_state(TASK_RUNNING); - return ret; -} - -static ssize_t es1371_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) -{ - struct es1371_state *s = (struct es1371_state *)file->private_data; - DECLARE_WAITQUEUE(wait, current); - ssize_t ret; - unsigned long flags; - unsigned swptr; - int cnt; - - VALIDATE_STATE(s); - if (s->dma_dac2.mapped) - return -ENXIO; - if (!access_ok(VERIFY_READ, buffer, count)) - return -EFAULT; - mutex_lock(&s->sem); - if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s))) - goto out3; - ret = 0; - add_wait_queue(&s->dma_dac2.wait, &wait); - while (count > 0) { - spin_lock_irqsave(&s->lock, flags); - if (s->dma_dac2.count < 0) { - s->dma_dac2.count = 0; - s->dma_dac2.swptr = s->dma_dac2.hwptr; - } - swptr = s->dma_dac2.swptr; - cnt = s->dma_dac2.dmasize-swptr; - if (s->dma_dac2.count + cnt > s->dma_dac2.dmasize) - cnt = s->dma_dac2.dmasize - s->dma_dac2.count; - if (cnt <= 0) - __set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irqrestore(&s->lock, flags); - if (cnt > count) - cnt = count; - if (cnt <= 0) { - if (s->dma_dac2.enabled) - start_dac2(s); - if (file->f_flags & O_NONBLOCK) { - if (!ret) - ret = -EAGAIN; - goto out; - } - mutex_unlock(&s->sem); - schedule(); - if (signal_pending(current)) { - if (!ret) - ret = -ERESTARTSYS; - goto out2; - } - mutex_lock(&s->sem); - if (s->dma_dac2.mapped) - { - ret = -ENXIO; - goto out; - } - continue; - } - if (copy_from_user(s->dma_dac2.rawbuf + swptr, buffer, cnt)) { - if (!ret) - ret = -EFAULT; - goto out; - } - swptr = (swptr + cnt) % s->dma_dac2.dmasize; - spin_lock_irqsave(&s->lock, flags); - s->dma_dac2.swptr = swptr; - s->dma_dac2.count += cnt; - s->dma_dac2.endcleared = 0; - spin_unlock_irqrestore(&s->lock, flags); - count -= cnt; - buffer += cnt; - ret += cnt; - if (s->dma_dac2.enabled) - start_dac2(s); - } -out: - mutex_unlock(&s->sem); -out2: - remove_wait_queue(&s->dma_dac2.wait, &wait); -out3: - set_current_state(TASK_RUNNING); - return ret; -} - -/* No kernel lock - we have our own spinlock */ -static unsigned int es1371_poll(struct file *file, struct poll_table_struct *wait) -{ - struct es1371_state *s = (struct es1371_state *)file->private_data; - unsigned long flags; - unsigned int mask = 0; - - VALIDATE_STATE(s); - if (file->f_mode & FMODE_WRITE) { - if (!s->dma_dac2.ready && prog_dmabuf_dac2(s)) - return 0; - poll_wait(file, &s->dma_dac2.wait, wait); - } - if (file->f_mode & FMODE_READ) { - if (!s->dma_adc.ready && prog_dmabuf_adc(s)) - return 0; - poll_wait(file, &s->dma_adc.wait, wait); - } - spin_lock_irqsave(&s->lock, flags); - es1371_update_ptr(s); - if (file->f_mode & FMODE_READ) { - if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) - mask |= POLLIN | POLLRDNORM; - } - if (file->f_mode & FMODE_WRITE) { - if (s->dma_dac2.mapped) { - if (s->dma_dac2.count >= (signed)s->dma_dac2.fragsize) - mask |= POLLOUT | POLLWRNORM; - } else { - if ((signed)s->dma_dac2.dmasize >= s->dma_dac2.count + (signed)s->dma_dac2.fragsize) - mask |= POLLOUT | POLLWRNORM; - } - } - spin_unlock_irqrestore(&s->lock, flags); - return mask; -} - -static int es1371_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct es1371_state *s = (struct es1371_state *)file->private_data; - struct dmabuf *db; - int ret = 0; - unsigned long size; - - VALIDATE_STATE(s); - lock_kernel(); - mutex_lock(&s->sem); - - if (vma->vm_flags & VM_WRITE) { - if ((ret = prog_dmabuf_dac2(s)) != 0) { - goto out; - } - db = &s->dma_dac2; - } else if (vma->vm_flags & VM_READ) { - if ((ret = prog_dmabuf_adc(s)) != 0) { - goto out; - } - db = &s->dma_adc; - } else { - ret = -EINVAL; - goto out; - } - if (vma->vm_pgoff != 0) { - ret = -EINVAL; - goto out; - } - size = vma->vm_end - vma->vm_start; - if (size > (PAGE_SIZE << db->buforder)) { - ret = -EINVAL; - goto out; - } - if (remap_pfn_range(vma, vma->vm_start, - virt_to_phys(db->rawbuf) >> PAGE_SHIFT, - size, vma->vm_page_prot)) { - ret = -EAGAIN; - goto out; - } - db->mapped = 1; -out: - mutex_unlock(&s->sem); - unlock_kernel(); - return ret; -} - -static int es1371_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -{ - struct es1371_state *s = (struct es1371_state *)file->private_data; - unsigned long flags; - audio_buf_info abinfo; - count_info cinfo; - int count; - int val, mapped, ret; - void __user *argp = (void __user *)arg; - int __user *p = argp; - - VALIDATE_STATE(s); - mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac2.mapped) || - ((file->f_mode & FMODE_READ) && s->dma_adc.mapped); - switch (cmd) { - case OSS_GETVERSION: - return put_user(SOUND_VERSION, p); - - case SNDCTL_DSP_SYNC: - if (file->f_mode & FMODE_WRITE) - return drain_dac2(s, 0/*file->f_flags & O_NONBLOCK*/); - return 0; - - case SNDCTL_DSP_SETDUPLEX: - return 0; - - case SNDCTL_DSP_GETCAPS: - return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, p); - - case SNDCTL_DSP_RESET: - if (file->f_mode & FMODE_WRITE) { - stop_dac2(s); - synchronize_irq(s->irq); - s->dma_dac2.swptr = s->dma_dac2.hwptr = s->dma_dac2.count = s->dma_dac2.total_bytes = 0; - } - if (file->f_mode & FMODE_READ) { - stop_adc(s); - synchronize_irq(s->irq); - s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0; - } - return 0; - - case SNDCTL_DSP_SPEED: - if (get_user(val, p)) - return -EFAULT; - if (val >= 0) { - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.ready = 0; - set_adc_rate(s, val); - } - if (file->f_mode & FMODE_WRITE) { - stop_dac2(s); - s->dma_dac2.ready = 0; - set_dac2_rate(s, val); - } - } - return put_user((file->f_mode & FMODE_READ) ? s->adcrate : s->dac2rate, p); - - case SNDCTL_DSP_STEREO: - if (get_user(val, p)) - return -EFAULT; - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.ready = 0; - spin_lock_irqsave(&s->lock, flags); - if (val) - s->sctrl |= SCTRL_R1SMB; - else - s->sctrl &= ~SCTRL_R1SMB; - outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL); - spin_unlock_irqrestore(&s->lock, flags); - } - if (file->f_mode & FMODE_WRITE) { - stop_dac2(s); - s->dma_dac2.ready = 0; - spin_lock_irqsave(&s->lock, flags); - if (val) - s->sctrl |= SCTRL_P2SMB; - else - s->sctrl &= ~SCTRL_P2SMB; - outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL); - spin_unlock_irqrestore(&s->lock, flags); - } - return 0; - - case SNDCTL_DSP_CHANNELS: - if (get_user(val, p)) - return -EFAULT; - if (val != 0) { - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.ready = 0; - spin_lock_irqsave(&s->lock, flags); - if (val >= 2) - s->sctrl |= SCTRL_R1SMB; - else - s->sctrl &= ~SCTRL_R1SMB; - outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL); - spin_unlock_irqrestore(&s->lock, flags); - } - if (file->f_mode & FMODE_WRITE) { - stop_dac2(s); - s->dma_dac2.ready = 0; - spin_lock_irqsave(&s->lock, flags); - if (val >= 2) - s->sctrl |= SCTRL_P2SMB; - else - s->sctrl &= ~SCTRL_P2SMB; - outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL); - spin_unlock_irqrestore(&s->lock, flags); - } - } - return put_user((s->sctrl & ((file->f_mode & FMODE_READ) ? SCTRL_R1SMB : SCTRL_P2SMB)) ? 2 : 1, p); - - case SNDCTL_DSP_GETFMTS: /* Returns a mask */ - return put_user(AFMT_S16_LE|AFMT_U8, p); - - case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/ - if (get_user(val, p)) - return -EFAULT; - if (val != AFMT_QUERY) { - if (file->f_mode & FMODE_READ) { - stop_adc(s); - s->dma_adc.ready = 0; - spin_lock_irqsave(&s->lock, flags); - if (val == AFMT_S16_LE) - s->sctrl |= SCTRL_R1SEB; - else - s->sctrl &= ~SCTRL_R1SEB; - outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL); - spin_unlock_irqrestore(&s->lock, flags); - } - if (file->f_mode & FMODE_WRITE) { - stop_dac2(s); - s->dma_dac2.ready = 0; - spin_lock_irqsave(&s->lock, flags); - if (val == AFMT_S16_LE) - s->sctrl |= SCTRL_P2SEB; - else - s->sctrl &= ~SCTRL_P2SEB; - outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL); - spin_unlock_irqrestore(&s->lock, flags); - } - } - return put_user((s->sctrl & ((file->f_mode & FMODE_READ) ? SCTRL_R1SEB : SCTRL_P2SEB)) ? - AFMT_S16_LE : AFMT_U8, p); - - case SNDCTL_DSP_POST: - return 0; - - case SNDCTL_DSP_GETTRIGGER: - val = 0; - if (file->f_mode & FMODE_READ && s->ctrl & CTRL_ADC_EN) - val |= PCM_ENABLE_INPUT; - if (file->f_mode & FMODE_WRITE && s->ctrl & CTRL_DAC2_EN) - val |= PCM_ENABLE_OUTPUT; - return put_user(val, p); - - case SNDCTL_DSP_SETTRIGGER: - if (get_user(val, p)) - return -EFAULT; - if (file->f_mode & FMODE_READ) { - if (val & PCM_ENABLE_INPUT) { - if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s))) - return ret; - s->dma_adc.enabled = 1; - start_adc(s); - } else { - s->dma_adc.enabled = 0; - stop_adc(s); - } - } - if (file->f_mode & FMODE_WRITE) { - if (val & PCM_ENABLE_OUTPUT) { - if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s))) - return ret; - s->dma_dac2.enabled = 1; - start_dac2(s); - } else { - s->dma_dac2.enabled = 0; - stop_dac2(s); - } - } - return 0; - - case SNDCTL_DSP_GETOSPACE: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0) - return val; - spin_lock_irqsave(&s->lock, flags); - es1371_update_ptr(s); - abinfo.fragsize = s->dma_dac2.fragsize; - count = s->dma_dac2.count; - if (count < 0) - count = 0; - abinfo.bytes = s->dma_dac2.dmasize - count; - abinfo.fragstotal = s->dma_dac2.numfrag; - abinfo.fragments = abinfo.bytes >> s->dma_dac2.fragshift; - spin_unlock_irqrestore(&s->lock, flags); - return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_GETISPACE: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0) - return val; - spin_lock_irqsave(&s->lock, flags); - es1371_update_ptr(s); - abinfo.fragsize = s->dma_adc.fragsize; - count = s->dma_adc.count; - if (count < 0) - count = 0; - abinfo.bytes = count; - abinfo.fragstotal = s->dma_adc.numfrag; - abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift; - spin_unlock_irqrestore(&s->lock, flags); - return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_NONBLOCK: - file->f_flags |= O_NONBLOCK; - return 0; - - case SNDCTL_DSP_GETODELAY: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0) - return val; - spin_lock_irqsave(&s->lock, flags); - es1371_update_ptr(s); - count = s->dma_dac2.count; - spin_unlock_irqrestore(&s->lock, flags); - if (count < 0) - count = 0; - return put_user(count, p); - - case SNDCTL_DSP_GETIPTR: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0) - return val; - spin_lock_irqsave(&s->lock, flags); - es1371_update_ptr(s); - cinfo.bytes = s->dma_adc.total_bytes; - count = s->dma_adc.count; - if (count < 0) - count = 0; - cinfo.blocks = count >> s->dma_adc.fragshift; - cinfo.ptr = s->dma_adc.hwptr; - if (s->dma_adc.mapped) - s->dma_adc.count &= s->dma_adc.fragsize-1; - spin_unlock_irqrestore(&s->lock, flags); - if (copy_to_user(argp, &cinfo, sizeof(cinfo))) - return -EFAULT; - return 0; - - case SNDCTL_DSP_GETOPTR: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0) - return val; - spin_lock_irqsave(&s->lock, flags); - es1371_update_ptr(s); - cinfo.bytes = s->dma_dac2.total_bytes; - count = s->dma_dac2.count; - if (count < 0) - count = 0; - cinfo.blocks = count >> s->dma_dac2.fragshift; - cinfo.ptr = s->dma_dac2.hwptr; - if (s->dma_dac2.mapped) - s->dma_dac2.count &= s->dma_dac2.fragsize-1; - spin_unlock_irqrestore(&s->lock, flags); - if (copy_to_user(argp, &cinfo, sizeof(cinfo))) - return -EFAULT; - return 0; - - case SNDCTL_DSP_GETBLKSIZE: - if (file->f_mode & FMODE_WRITE) { - if ((val = prog_dmabuf_dac2(s))) - return val; - return put_user(s->dma_dac2.fragsize, p); - } - if ((val = prog_dmabuf_adc(s))) - return val; - return put_user(s->dma_adc.fragsize, p); - - case SNDCTL_DSP_SETFRAGMENT: - if (get_user(val, p)) - return -EFAULT; - if (file->f_mode & FMODE_READ) { - s->dma_adc.ossfragshift = val & 0xffff; - s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff; - if (s->dma_adc.ossfragshift < 4) - s->dma_adc.ossfragshift = 4; - if (s->dma_adc.ossfragshift > 15) - s->dma_adc.ossfragshift = 15; - if (s->dma_adc.ossmaxfrags < 4) - s->dma_adc.ossmaxfrags = 4; - } - if (file->f_mode & FMODE_WRITE) { - s->dma_dac2.ossfragshift = val & 0xffff; - s->dma_dac2.ossmaxfrags = (val >> 16) & 0xffff; - if (s->dma_dac2.ossfragshift < 4) - s->dma_dac2.ossfragshift = 4; - if (s->dma_dac2.ossfragshift > 15) - s->dma_dac2.ossfragshift = 15; - if (s->dma_dac2.ossmaxfrags < 4) - s->dma_dac2.ossmaxfrags = 4; - } - return 0; - - case SNDCTL_DSP_SUBDIVIDE: - if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) || - (file->f_mode & FMODE_WRITE && s->dma_dac2.subdivision)) - return -EINVAL; - if (get_user(val, p)) - return -EFAULT; - if (val != 1 && val != 2 && val != 4) - return -EINVAL; - if (file->f_mode & FMODE_READ) - s->dma_adc.subdivision = val; - if (file->f_mode & FMODE_WRITE) - s->dma_dac2.subdivision = val; - return 0; - - case SOUND_PCM_READ_RATE: - return put_user((file->f_mode & FMODE_READ) ? s->adcrate : s->dac2rate, p); - - case SOUND_PCM_READ_CHANNELS: - return put_user((s->sctrl & ((file->f_mode & FMODE_READ) ? SCTRL_R1SMB : SCTRL_P2SMB)) ? 2 : 1, p); - - case SOUND_PCM_READ_BITS: - return put_user((s->sctrl & ((file->f_mode & FMODE_READ) ? SCTRL_R1SEB : SCTRL_P2SEB)) ? 16 : 8, p); - - case SOUND_PCM_WRITE_FILTER: - case SNDCTL_DSP_SETSYNCRO: - case SOUND_PCM_READ_FILTER: - return -EINVAL; - - } - return mixdev_ioctl(s->codec, cmd, arg); -} - -static int es1371_open(struct inode *inode, struct file *file) -{ - int minor = iminor(inode); - DECLARE_WAITQUEUE(wait, current); - unsigned long flags; - struct list_head *list; - struct es1371_state *s; - - for (list = devs.next; ; list = list->next) { - if (list == &devs) - return -ENODEV; - s = list_entry(list, struct es1371_state, devs); - if (!((s->dev_audio ^ minor) & ~0xf)) - break; - } - VALIDATE_STATE(s); - file->private_data = s; - /* wait for device to become free */ - mutex_lock(&s->open_mutex); - while (s->open_mode & file->f_mode) { - if (file->f_flags & O_NONBLOCK) { - mutex_unlock(&s->open_mutex); - return -EBUSY; - } - add_wait_queue(&s->open_wait, &wait); - __set_current_state(TASK_INTERRUPTIBLE); - mutex_unlock(&s->open_mutex); - schedule(); - remove_wait_queue(&s->open_wait, &wait); - set_current_state(TASK_RUNNING); - if (signal_pending(current)) - return -ERESTARTSYS; - mutex_lock(&s->open_mutex); - } - if (file->f_mode & FMODE_READ) { - s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0; - s->dma_adc.enabled = 1; - set_adc_rate(s, 8000); - } - if (file->f_mode & FMODE_WRITE) { - s->dma_dac2.ossfragshift = s->dma_dac2.ossmaxfrags = s->dma_dac2.subdivision = 0; - s->dma_dac2.enabled = 1; - set_dac2_rate(s, 8000); - } - spin_lock_irqsave(&s->lock, flags); - if (file->f_mode & FMODE_READ) { - s->sctrl &= ~SCTRL_R1FMT; - if ((minor & 0xf) == SND_DEV_DSP16) - s->sctrl |= ES1371_FMT_S16_MONO << SCTRL_SH_R1FMT; - else - s->sctrl |= ES1371_FMT_U8_MONO << SCTRL_SH_R1FMT; - } - if (file->f_mode & FMODE_WRITE) { - s->sctrl &= ~SCTRL_P2FMT; - if ((minor & 0xf) == SND_DEV_DSP16) - s->sctrl |= ES1371_FMT_S16_MONO << SCTRL_SH_P2FMT; - else - s->sctrl |= ES1371_FMT_U8_MONO << SCTRL_SH_P2FMT; - } - outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL); - spin_unlock_irqrestore(&s->lock, flags); - s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); - mutex_unlock(&s->open_mutex); - mutex_init(&s->sem); - return nonseekable_open(inode, file); -} - -static int es1371_release(struct inode *inode, struct file *file) -{ - struct es1371_state *s = (struct es1371_state *)file->private_data; - - VALIDATE_STATE(s); - lock_kernel(); - if (file->f_mode & FMODE_WRITE) - drain_dac2(s, file->f_flags & O_NONBLOCK); - mutex_lock(&s->open_mutex); - if (file->f_mode & FMODE_WRITE) { - stop_dac2(s); - dealloc_dmabuf(s, &s->dma_dac2); - } - if (file->f_mode & FMODE_READ) { - stop_adc(s); - dealloc_dmabuf(s, &s->dma_adc); - } - s->open_mode &= ~(file->f_mode & (FMODE_READ|FMODE_WRITE)); - mutex_unlock(&s->open_mutex); - wake_up(&s->open_wait); - unlock_kernel(); - return 0; -} - -static /*const*/ struct file_operations es1371_audio_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = es1371_read, - .write = es1371_write, - .poll = es1371_poll, - .ioctl = es1371_ioctl, - .mmap = es1371_mmap, - .open = es1371_open, - .release = es1371_release, -}; - -/* --------------------------------------------------------------------- */ - -static ssize_t es1371_write_dac(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) -{ - struct es1371_state *s = (struct es1371_state *)file->private_data; - DECLARE_WAITQUEUE(wait, current); - ssize_t ret = 0; - unsigned long flags; - unsigned swptr; - int cnt; - - VALIDATE_STATE(s); - if (s->dma_dac1.mapped) - return -ENXIO; - if (!s->dma_dac1.ready && (ret = prog_dmabuf_dac1(s))) - return ret; - if (!access_ok(VERIFY_READ, buffer, count)) - return -EFAULT; - add_wait_queue(&s->dma_dac1.wait, &wait); - while (count > 0) { - spin_lock_irqsave(&s->lock, flags); - if (s->dma_dac1.count < 0) { - s->dma_dac1.count = 0; - s->dma_dac1.swptr = s->dma_dac1.hwptr; - } - swptr = s->dma_dac1.swptr; - cnt = s->dma_dac1.dmasize-swptr; - if (s->dma_dac1.count + cnt > s->dma_dac1.dmasize) - cnt = s->dma_dac1.dmasize - s->dma_dac1.count; - if (cnt <= 0) - __set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irqrestore(&s->lock, flags); - if (cnt > count) - cnt = count; - if (cnt <= 0) { - if (s->dma_dac1.enabled) - start_dac1(s); - if (file->f_flags & O_NONBLOCK) { - if (!ret) - ret = -EAGAIN; - break; - } - schedule(); - if (signal_pending(current)) { - if (!ret) - ret = -ERESTARTSYS; - break; - } - continue; - } - if (copy_from_user(s->dma_dac1.rawbuf + swptr, buffer, cnt)) { - if (!ret) - ret = -EFAULT; - break; - } - swptr = (swptr + cnt) % s->dma_dac1.dmasize; - spin_lock_irqsave(&s->lock, flags); - s->dma_dac1.swptr = swptr; - s->dma_dac1.count += cnt; - s->dma_dac1.endcleared = 0; - spin_unlock_irqrestore(&s->lock, flags); - count -= cnt; - buffer += cnt; - ret += cnt; - if (s->dma_dac1.enabled) - start_dac1(s); - } - remove_wait_queue(&s->dma_dac1.wait, &wait); - set_current_state(TASK_RUNNING); - return ret; -} - -/* No kernel lock - we have our own spinlock */ -static unsigned int es1371_poll_dac(struct file *file, struct poll_table_struct *wait) -{ - struct es1371_state *s = (struct es1371_state *)file->private_data; - unsigned long flags; - unsigned int mask = 0; - - VALIDATE_STATE(s); - if (!s->dma_dac1.ready && prog_dmabuf_dac1(s)) - return 0; - poll_wait(file, &s->dma_dac1.wait, wait); - spin_lock_irqsave(&s->lock, flags); - es1371_update_ptr(s); - if (s->dma_dac1.mapped) { - if (s->dma_dac1.count >= (signed)s->dma_dac1.fragsize) - mask |= POLLOUT | POLLWRNORM; - } else { - if ((signed)s->dma_dac1.dmasize >= s->dma_dac1.count + (signed)s->dma_dac1.fragsize) - mask |= POLLOUT | POLLWRNORM; - } - spin_unlock_irqrestore(&s->lock, flags); - return mask; -} - -static int es1371_mmap_dac(struct file *file, struct vm_area_struct *vma) -{ - struct es1371_state *s = (struct es1371_state *)file->private_data; - int ret; - unsigned long size; - - VALIDATE_STATE(s); - if (!(vma->vm_flags & VM_WRITE)) - return -EINVAL; - lock_kernel(); - if ((ret = prog_dmabuf_dac1(s)) != 0) - goto out; - ret = -EINVAL; - if (vma->vm_pgoff != 0) - goto out; - size = vma->vm_end - vma->vm_start; - if (size > (PAGE_SIZE << s->dma_dac1.buforder)) - goto out; - ret = -EAGAIN; - if (remap_pfn_range(vma, vma->vm_start, - virt_to_phys(s->dma_dac1.rawbuf) >> PAGE_SHIFT, - size, vma->vm_page_prot)) - goto out; - s->dma_dac1.mapped = 1; - ret = 0; -out: - unlock_kernel(); - return ret; -} - -static int es1371_ioctl_dac(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -{ - struct es1371_state *s = (struct es1371_state *)file->private_data; - unsigned long flags; - audio_buf_info abinfo; - count_info cinfo; - int count; - int val, ret; - int __user *p = (int __user *)arg; - - VALIDATE_STATE(s); - switch (cmd) { - case OSS_GETVERSION: - return put_user(SOUND_VERSION, p); - - case SNDCTL_DSP_SYNC: - return drain_dac1(s, 0/*file->f_flags & O_NONBLOCK*/); - - case SNDCTL_DSP_SETDUPLEX: - return -EINVAL; - - case SNDCTL_DSP_GETCAPS: - return put_user(DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, p); - - case SNDCTL_DSP_RESET: - stop_dac1(s); - synchronize_irq(s->irq); - s->dma_dac1.swptr = s->dma_dac1.hwptr = s->dma_dac1.count = s->dma_dac1.total_bytes = 0; - return 0; - - case SNDCTL_DSP_SPEED: - if (get_user(val, p)) - return -EFAULT; - if (val >= 0) { - stop_dac1(s); - s->dma_dac1.ready = 0; - set_dac1_rate(s, val); - } - return put_user(s->dac1rate, p); - - case SNDCTL_DSP_STEREO: - if (get_user(val, p)) - return -EFAULT; - stop_dac1(s); - s->dma_dac1.ready = 0; - spin_lock_irqsave(&s->lock, flags); - if (val) - s->sctrl |= SCTRL_P1SMB; - else - s->sctrl &= ~SCTRL_P1SMB; - outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL); - spin_unlock_irqrestore(&s->lock, flags); - return 0; - - case SNDCTL_DSP_CHANNELS: - if (get_user(val, p)) - return -EFAULT; - if (val != 0) { - stop_dac1(s); - s->dma_dac1.ready = 0; - spin_lock_irqsave(&s->lock, flags); - if (val >= 2) - s->sctrl |= SCTRL_P1SMB; - else - s->sctrl &= ~SCTRL_P1SMB; - outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL); - spin_unlock_irqrestore(&s->lock, flags); - } - return put_user((s->sctrl & SCTRL_P1SMB) ? 2 : 1, p); - - case SNDCTL_DSP_GETFMTS: /* Returns a mask */ - return put_user(AFMT_S16_LE|AFMT_U8, p); - - case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/ - if (get_user(val, p)) - return -EFAULT; - if (val != AFMT_QUERY) { - stop_dac1(s); - s->dma_dac1.ready = 0; - spin_lock_irqsave(&s->lock, flags); - if (val == AFMT_S16_LE) - s->sctrl |= SCTRL_P1SEB; - else - s->sctrl &= ~SCTRL_P1SEB; - outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL); - spin_unlock_irqrestore(&s->lock, flags); - } - return put_user((s->sctrl & SCTRL_P1SEB) ? AFMT_S16_LE : AFMT_U8, p); - - case SNDCTL_DSP_POST: - return 0; - - case SNDCTL_DSP_GETTRIGGER: - return put_user((s->ctrl & CTRL_DAC1_EN) ? PCM_ENABLE_OUTPUT : 0, p); - - case SNDCTL_DSP_SETTRIGGER: - if (get_user(val, p)) - return -EFAULT; - if (val & PCM_ENABLE_OUTPUT) { - if (!s->dma_dac1.ready && (ret = prog_dmabuf_dac1(s))) - return ret; - s->dma_dac1.enabled = 1; - start_dac1(s); - } else { - s->dma_dac1.enabled = 0; - stop_dac1(s); - } - return 0; - - case SNDCTL_DSP_GETOSPACE: - if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0) - return val; - spin_lock_irqsave(&s->lock, flags); - es1371_update_ptr(s); - abinfo.fragsize = s->dma_dac1.fragsize; - count = s->dma_dac1.count; - if (count < 0) - count = 0; - abinfo.bytes = s->dma_dac1.dmasize - count; - abinfo.fragstotal = s->dma_dac1.numfrag; - abinfo.fragments = abinfo.bytes >> s->dma_dac1.fragshift; - spin_unlock_irqrestore(&s->lock, flags); - return copy_to_user((void __user *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_NONBLOCK: - file->f_flags |= O_NONBLOCK; - return 0; - - case SNDCTL_DSP_GETODELAY: - if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0) - return val; - spin_lock_irqsave(&s->lock, flags); - es1371_update_ptr(s); - count = s->dma_dac1.count; - spin_unlock_irqrestore(&s->lock, flags); - if (count < 0) - count = 0; - return put_user(count, p); - - case SNDCTL_DSP_GETOPTR: - if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0) - return val; - spin_lock_irqsave(&s->lock, flags); - es1371_update_ptr(s); - cinfo.bytes = s->dma_dac1.total_bytes; - count = s->dma_dac1.count; - if (count < 0) - count = 0; - cinfo.blocks = count >> s->dma_dac1.fragshift; - cinfo.ptr = s->dma_dac1.hwptr; - if (s->dma_dac1.mapped) - s->dma_dac1.count &= s->dma_dac1.fragsize-1; - spin_unlock_irqrestore(&s->lock, flags); - if (copy_to_user((void __user *)arg, &cinfo, sizeof(cinfo))) - return -EFAULT; - return 0; - - case SNDCTL_DSP_GETBLKSIZE: - if ((val = prog_dmabuf_dac1(s))) - return val; - return put_user(s->dma_dac1.fragsize, p); - - case SNDCTL_DSP_SETFRAGMENT: - if (get_user(val, p)) - return -EFAULT; - s->dma_dac1.ossfragshift = val & 0xffff; - s->dma_dac1.ossmaxfrags = (val >> 16) & 0xffff; - if (s->dma_dac1.ossfragshift < 4) - s->dma_dac1.ossfragshift = 4; - if (s->dma_dac1.ossfragshift > 15) - s->dma_dac1.ossfragshift = 15; - if (s->dma_dac1.ossmaxfrags < 4) - s->dma_dac1.ossmaxfrags = 4; - return 0; - - case SNDCTL_DSP_SUBDIVIDE: - if (s->dma_dac1.subdivision) - return -EINVAL; - if (get_user(val, p)) - return -EFAULT; - if (val != 1 && val != 2 && val != 4) - return -EINVAL; - s->dma_dac1.subdivision = val; - return 0; - - case SOUND_PCM_READ_RATE: - return put_user(s->dac1rate, p); - - case SOUND_PCM_READ_CHANNELS: - return put_user((s->sctrl & SCTRL_P1SMB) ? 2 : 1, p); - - case SOUND_PCM_READ_BITS: - return put_user((s->sctrl & SCTRL_P1SEB) ? 16 : 8, p); - - case SOUND_PCM_WRITE_FILTER: - case SNDCTL_DSP_SETSYNCRO: - case SOUND_PCM_READ_FILTER: - return -EINVAL; - - } - return mixdev_ioctl(s->codec, cmd, arg); -} - -static int es1371_open_dac(struct inode *inode, struct file *file) -{ - int minor = iminor(inode); - DECLARE_WAITQUEUE(wait, current); - unsigned long flags; - struct list_head *list; - struct es1371_state *s; - - for (list = devs.next; ; list = list->next) { - if (list == &devs) - return -ENODEV; - s = list_entry(list, struct es1371_state, devs); - if (!((s->dev_dac ^ minor) & ~0xf)) - break; - } - VALIDATE_STATE(s); - /* we allow opening with O_RDWR, most programs do it although they will only write */ -#if 0 - if (file->f_mode & FMODE_READ) - return -EPERM; -#endif - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - file->private_data = s; - /* wait for device to become free */ - mutex_lock(&s->open_mutex); - while (s->open_mode & FMODE_DAC) { - if (file->f_flags & O_NONBLOCK) { - mutex_unlock(&s->open_mutex); - return -EBUSY; - } - add_wait_queue(&s->open_wait, &wait); - __set_current_state(TASK_INTERRUPTIBLE); - mutex_unlock(&s->open_mutex); - schedule(); - remove_wait_queue(&s->open_wait, &wait); - set_current_state(TASK_RUNNING); - if (signal_pending(current)) - return -ERESTARTSYS; - mutex_lock(&s->open_mutex); - } - s->dma_dac1.ossfragshift = s->dma_dac1.ossmaxfrags = s->dma_dac1.subdivision = 0; - s->dma_dac1.enabled = 1; - set_dac1_rate(s, 8000); - spin_lock_irqsave(&s->lock, flags); - s->sctrl &= ~SCTRL_P1FMT; - if ((minor & 0xf) == SND_DEV_DSP16) - s->sctrl |= ES1371_FMT_S16_MONO << SCTRL_SH_P1FMT; - else - s->sctrl |= ES1371_FMT_U8_MONO << SCTRL_SH_P1FMT; - outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL); - spin_unlock_irqrestore(&s->lock, flags); - s->open_mode |= FMODE_DAC; - mutex_unlock(&s->open_mutex); - return nonseekable_open(inode, file); -} - -static int es1371_release_dac(struct inode *inode, struct file *file) -{ - struct es1371_state *s = (struct es1371_state *)file->private_data; - - VALIDATE_STATE(s); - lock_kernel(); - drain_dac1(s, file->f_flags & O_NONBLOCK); - mutex_lock(&s->open_mutex); - stop_dac1(s); - dealloc_dmabuf(s, &s->dma_dac1); - s->open_mode &= ~FMODE_DAC; - mutex_unlock(&s->open_mutex); - wake_up(&s->open_wait); - unlock_kernel(); - return 0; -} - -static /*const*/ struct file_operations es1371_dac_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .write = es1371_write_dac, - .poll = es1371_poll_dac, - .ioctl = es1371_ioctl_dac, - .mmap = es1371_mmap_dac, - .open = es1371_open_dac, - .release = es1371_release_dac, -}; - -/* --------------------------------------------------------------------- */ - -static ssize_t es1371_midi_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) -{ - struct es1371_state *s = (struct es1371_state *)file->private_data; - DECLARE_WAITQUEUE(wait, current); - ssize_t ret; - unsigned long flags; - unsigned ptr; - int cnt; - - VALIDATE_STATE(s); - if (!access_ok(VERIFY_WRITE, buffer, count)) - return -EFAULT; - if (count == 0) - return 0; - ret = 0; - add_wait_queue(&s->midi.iwait, &wait); - while (count > 0) { - spin_lock_irqsave(&s->lock, flags); - ptr = s->midi.ird; - cnt = MIDIINBUF - ptr; - if (s->midi.icnt < cnt) - cnt = s->midi.icnt; - if (cnt <= 0) - __set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irqrestore(&s->lock, flags); - if (cnt > count) - cnt = count; - if (cnt <= 0) { - if (file->f_flags & O_NONBLOCK) { - if (!ret) - ret = -EAGAIN; - break; - } - schedule(); - if (signal_pending(current)) { - if (!ret) - ret = -ERESTARTSYS; - break; - } - continue; - } - if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt)) { - if (!ret) - ret = -EFAULT; - break; - } - ptr = (ptr + cnt) % MIDIINBUF; - spin_lock_irqsave(&s->lock, flags); - s->midi.ird = ptr; - s->midi.icnt -= cnt; - spin_unlock_irqrestore(&s->lock, flags); - count -= cnt; - buffer += cnt; - ret += cnt; - break; - } - __set_current_state(TASK_RUNNING); - remove_wait_queue(&s->midi.iwait, &wait); - return ret; -} - -static ssize_t es1371_midi_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) -{ - struct es1371_state *s = (struct es1371_state *)file->private_data; - DECLARE_WAITQUEUE(wait, current); - ssize_t ret; - unsigned long flags; - unsigned ptr; - int cnt; - - VALIDATE_STATE(s); - if (!access_ok(VERIFY_READ, buffer, count)) - return -EFAULT; - if (count == 0) - return 0; - ret = 0; - add_wait_queue(&s->midi.owait, &wait); - while (count > 0) { - spin_lock_irqsave(&s->lock, flags); - ptr = s->midi.owr; - cnt = MIDIOUTBUF - ptr; - if (s->midi.ocnt + cnt > MIDIOUTBUF) - cnt = MIDIOUTBUF - s->midi.ocnt; - if (cnt <= 0) { - __set_current_state(TASK_INTERRUPTIBLE); - es1371_handle_midi(s); - } - spin_unlock_irqrestore(&s->lock, flags); - if (cnt > count) - cnt = count; - if (cnt <= 0) { - if (file->f_flags & O_NONBLOCK) { - if (!ret) - ret = -EAGAIN; - break; - } - schedule(); - if (signal_pending(current)) { - if (!ret) - ret = -ERESTARTSYS; - break; - } - continue; - } - if (copy_from_user(s->midi.obuf + ptr, buffer, cnt)) { - if (!ret) - ret = -EFAULT; - break; - } - ptr = (ptr + cnt) % MIDIOUTBUF; - spin_lock_irqsave(&s->lock, flags); - s->midi.owr = ptr; - s->midi.ocnt += cnt; - spin_unlock_irqrestore(&s->lock, flags); - count -= cnt; - buffer += cnt; - ret += cnt; - spin_lock_irqsave(&s->lock, flags); - es1371_handle_midi(s); - spin_unlock_irqrestore(&s->lock, flags); - } - __set_current_state(TASK_RUNNING); - remove_wait_queue(&s->midi.owait, &wait); - return ret; -} - -/* No kernel lock - we have our own spinlock */ -static unsigned int es1371_midi_poll(struct file *file, struct poll_table_struct *wait) -{ - struct es1371_state *s = (struct es1371_state *)file->private_data; - unsigned long flags; - unsigned int mask = 0; - - VALIDATE_STATE(s); - if (file->f_mode & FMODE_WRITE) - poll_wait(file, &s->midi.owait, wait); - if (file->f_mode & FMODE_READ) - poll_wait(file, &s->midi.iwait, wait); - spin_lock_irqsave(&s->lock, flags); - if (file->f_mode & FMODE_READ) { - if (s->midi.icnt > 0) - mask |= POLLIN | POLLRDNORM; - } - if (file->f_mode & FMODE_WRITE) { - if (s->midi.ocnt < MIDIOUTBUF) - mask |= POLLOUT | POLLWRNORM; - } - spin_unlock_irqrestore(&s->lock, flags); - return mask; -} - -static int es1371_midi_open(struct inode *inode, struct file *file) -{ - int minor = iminor(inode); - DECLARE_WAITQUEUE(wait, current); - unsigned long flags; - struct list_head *list; - struct es1371_state *s; - - for (list = devs.next; ; list = list->next) { - if (list == &devs) - return -ENODEV; - s = list_entry(list, struct es1371_state, devs); - if (s->dev_midi == minor) - break; - } - VALIDATE_STATE(s); - file->private_data = s; - /* wait for device to become free */ - mutex_lock(&s->open_mutex); - while (s->open_mode & (file->f_mode << FMODE_MIDI_SHIFT)) { - if (file->f_flags & O_NONBLOCK) { - mutex_unlock(&s->open_mutex); - return -EBUSY; - } - add_wait_queue(&s->open_wait, &wait); - __set_current_state(TASK_INTERRUPTIBLE); - mutex_unlock(&s->open_mutex); - schedule(); - remove_wait_queue(&s->open_wait, &wait); - set_current_state(TASK_RUNNING); - if (signal_pending(current)) - return -ERESTARTSYS; - mutex_lock(&s->open_mutex); - } - spin_lock_irqsave(&s->lock, flags); - if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) { - s->midi.ird = s->midi.iwr = s->midi.icnt = 0; - s->midi.ord = s->midi.owr = s->midi.ocnt = 0; - outb(UCTRL_CNTRL_SWR, s->io+ES1371_REG_UART_CONTROL); - outb(0, s->io+ES1371_REG_UART_CONTROL); - outb(0, s->io+ES1371_REG_UART_TEST); - } - if (file->f_mode & FMODE_READ) { - s->midi.ird = s->midi.iwr = s->midi.icnt = 0; - } - if (file->f_mode & FMODE_WRITE) { - s->midi.ord = s->midi.owr = s->midi.ocnt = 0; - } - s->ctrl |= CTRL_UART_EN; - outl(s->ctrl, s->io+ES1371_REG_CONTROL); - es1371_handle_midi(s); - spin_unlock_irqrestore(&s->lock, flags); - s->open_mode |= (file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE); - mutex_unlock(&s->open_mutex); - return nonseekable_open(inode, file); -} - -static int es1371_midi_release(struct inode *inode, struct file *file) -{ - struct es1371_state *s = (struct es1371_state *)file->private_data; - DECLARE_WAITQUEUE(wait, current); - unsigned long flags; - unsigned count, tmo; - - VALIDATE_STATE(s); - lock_kernel(); - if (file->f_mode & FMODE_WRITE) { - add_wait_queue(&s->midi.owait, &wait); - for (;;) { - __set_current_state(TASK_INTERRUPTIBLE); - spin_lock_irqsave(&s->lock, flags); - count = s->midi.ocnt; - spin_unlock_irqrestore(&s->lock, flags); - if (count <= 0) - break; - if (signal_pending(current)) - break; - if (file->f_flags & O_NONBLOCK) - break; - tmo = (count * HZ) / 3100; - if (!schedule_timeout(tmo ? : 1) && tmo) - printk(KERN_DEBUG PFX "midi timed out??\n"); - } - remove_wait_queue(&s->midi.owait, &wait); - set_current_state(TASK_RUNNING); - } - mutex_lock(&s->open_mutex); - s->open_mode &= ~((file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE)); - spin_lock_irqsave(&s->lock, flags); - if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) { - s->ctrl &= ~CTRL_UART_EN; - outl(s->ctrl, s->io+ES1371_REG_CONTROL); - } - spin_unlock_irqrestore(&s->lock, flags); - mutex_unlock(&s->open_mutex); - wake_up(&s->open_wait); - unlock_kernel(); - return 0; -} - -static /*const*/ struct file_operations es1371_midi_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = es1371_midi_read, - .write = es1371_midi_write, - .poll = es1371_midi_poll, - .open = es1371_midi_open, - .release = es1371_midi_release, -}; - -/* --------------------------------------------------------------------- */ - -/* - * for debugging purposes, we'll create a proc device that dumps the - * CODEC chipstate - */ - -#ifdef ES1371_DEBUG -static int proc_es1371_dump (char *buf, char **start, off_t fpos, int length, int *eof, void *data) -{ - struct es1371_state *s; - int cnt, len = 0; - - if (list_empty(&devs)) - return 0; - s = list_entry(devs.next, struct es1371_state, devs); - /* print out header */ - len += sprintf(buf + len, "\t\tCreative ES137x Debug Dump-o-matic\n"); - - /* print out CODEC state */ - len += sprintf (buf + len, "AC97 CODEC state\n"); - for (cnt=0; cnt <= 0x7e; cnt = cnt +2) - len+= sprintf (buf + len, "reg:0x%02x val:0x%04x\n", cnt, rdcodec(s->codec, cnt)); - - if (fpos >=len){ - *start = buf; - *eof =1; - return 0; - } - *start = buf + fpos; - if ((len -= fpos) > length) - return length; - *eof =1; - return len; - -} -#endif /* ES1371_DEBUG */ - -/* --------------------------------------------------------------------- */ - -/* maximum number of devices; only used for command line params */ -#define NR_DEVICE 5 - -static int spdif[NR_DEVICE]; -static int nomix[NR_DEVICE]; -static int amplifier[NR_DEVICE]; - -static unsigned int devindex; - -module_param_array(spdif, bool, NULL, 0); -MODULE_PARM_DESC(spdif, "if 1 the output is in S/PDIF digital mode"); -module_param_array(nomix, bool, NULL, 0); -MODULE_PARM_DESC(nomix, "if 1 no analog audio is mixed to the digital output"); -module_param_array(amplifier, bool, NULL, 0); -MODULE_PARM_DESC(amplifier, "Set to 1 if the machine needs the amp control enabling (many laptops)"); - -MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"); -MODULE_DESCRIPTION("ES1371 AudioPCI97 Driver"); -MODULE_LICENSE("GPL"); - - -/* --------------------------------------------------------------------- */ - -static struct initvol { - int mixch; - int vol; -} initvol[] __devinitdata = { - { SOUND_MIXER_WRITE_LINE, 0x4040 }, - { SOUND_MIXER_WRITE_CD, 0x4040 }, - { MIXER_WRITE(SOUND_MIXER_VIDEO), 0x4040 }, - { SOUND_MIXER_WRITE_LINE1, 0x4040 }, - { SOUND_MIXER_WRITE_PCM, 0x4040 }, - { SOUND_MIXER_WRITE_VOLUME, 0x4040 }, - { MIXER_WRITE(SOUND_MIXER_PHONEOUT), 0x4040 }, - { SOUND_MIXER_WRITE_OGAIN, 0x4040 }, - { MIXER_WRITE(SOUND_MIXER_PHONEIN), 0x4040 }, - { SOUND_MIXER_WRITE_SPEAKER, 0x4040 }, - { SOUND_MIXER_WRITE_MIC, 0x4040 }, - { SOUND_MIXER_WRITE_RECLEV, 0x4040 }, - { SOUND_MIXER_WRITE_IGAIN, 0x4040 } -}; - -static struct -{ - short svid, sdid; -} amplifier_needed[] = -{ - { 0x107B, 0x2150 }, /* Gateway Solo 2150 */ - { 0x13BD, 0x100C }, /* Mebius PC-MJ100V */ - { 0x1102, 0x5938 }, /* Targa Xtender 300 */ - { 0x1102, 0x8938 }, /* IPC notebook */ - { PCI_ANY_ID, PCI_ANY_ID } -}; - -#ifdef SUPPORT_JOYSTICK - -static int __devinit es1371_register_gameport(struct es1371_state *s) -{ - struct gameport *gp; - int gpio; - - for (gpio = 0x218; gpio >= 0x200; gpio -= 0x08) - if (request_region(gpio, JOY_EXTENT, "es1371")) - break; - - if (gpio < 0x200) { - printk(KERN_ERR PFX "no free joystick address found\n"); - return -EBUSY; - } - - s->gameport = gp = gameport_allocate_port(); - if (!gp) { - printk(KERN_ERR PFX "can not allocate memory for gameport\n"); - release_region(gpio, JOY_EXTENT); - return -ENOMEM; - } - - gameport_set_name(gp, "ESS1371 Gameport"); - gameport_set_phys(gp, "isa%04x/gameport0", gpio); - gp->dev.parent = &s->dev->dev; - gp->io = gpio; - - s->ctrl |= CTRL_JYSTK_EN | (((gpio >> 3) & CTRL_JOY_MASK) << CTRL_JOY_SHIFT); - outl(s->ctrl, s->io + ES1371_REG_CONTROL); - - gameport_register_port(gp); - - return 0; -} - -static inline void es1371_unregister_gameport(struct es1371_state *s) -{ - if (s->gameport) { - int gpio = s->gameport->io; - gameport_unregister_port(s->gameport); - release_region(gpio, JOY_EXTENT); - - } -} - -#else -static inline int es1371_register_gameport(struct es1371_state *s) { return -ENOSYS; } -static inline void es1371_unregister_gameport(struct es1371_state *s) { } -#endif /* SUPPORT_JOYSTICK */ - - -static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid) -{ - struct es1371_state *s; - mm_segment_t fs; - int i, val, res = -1; - int idx; - unsigned long tmo; - signed long tmo2; - unsigned int cssr; - - if ((res=pci_enable_device(pcidev))) - return res; - - if (!(pci_resource_flags(pcidev, 0) & IORESOURCE_IO)) - return -ENODEV; - if (pcidev->irq == 0) - return -ENODEV; - i = pci_set_dma_mask(pcidev, DMA_32BIT_MASK); - if (i) { - printk(KERN_WARNING "es1371: architecture does not support 32bit PCI busmaster DMA\n"); - return i; - } - if (!(s = kzalloc(sizeof(struct es1371_state), GFP_KERNEL))) { - printk(KERN_WARNING PFX "out of memory\n"); - return -ENOMEM; - } - - s->codec = ac97_alloc_codec(); - if(s->codec == NULL) - goto err_codec; - - init_waitqueue_head(&s->dma_adc.wait); - init_waitqueue_head(&s->dma_dac1.wait); - init_waitqueue_head(&s->dma_dac2.wait); - init_waitqueue_head(&s->open_wait); - init_waitqueue_head(&s->midi.iwait); - init_waitqueue_head(&s->midi.owait); - mutex_init(&s->open_mutex); - spin_lock_init(&s->lock); - s->magic = ES1371_MAGIC; - s->dev = pcidev; - s->io = pci_resource_start(pcidev, 0); - s->irq = pcidev->irq; - s->vendor = pcidev->vendor; - s->device = pcidev->device; - s->rev = pcidev->revision; - s->codec->private_data = s; - s->codec->id = 0; - s->codec->codec_read = rdcodec; - s->codec->codec_write = wrcodec; - printk(KERN_INFO PFX "found chip, vendor id 0x%04x device id 0x%04x revision 0x%02x\n", - s->vendor, s->device, s->rev); - if (!request_region(s->io, ES1371_EXTENT, "es1371")) { - printk(KERN_ERR PFX "io ports %#lx-%#lx in use\n", s->io, s->io+ES1371_EXTENT-1); - res = -EBUSY; - goto err_region; - } - if ((res=request_irq(s->irq, es1371_interrupt, IRQF_SHARED, "es1371",s))) { - printk(KERN_ERR PFX "irq %u in use\n", s->irq); - goto err_irq; - } - printk(KERN_INFO PFX "found es1371 rev %d at io %#lx irq %u\n", - s->rev, s->io, s->irq); - /* register devices */ - if ((res=(s->dev_audio = register_sound_dsp(&es1371_audio_fops,-1)))<0) - goto err_dev1; - if ((res=(s->codec->dev_mixer = register_sound_mixer(&es1371_mixer_fops, -1))) < 0) - goto err_dev2; - if ((res=(s->dev_dac = register_sound_dsp(&es1371_dac_fops, -1))) < 0) - goto err_dev3; - if ((res=(s->dev_midi = register_sound_midi(&es1371_midi_fops, -1)))<0 ) - goto err_dev4; -#ifdef ES1371_DEBUG - /* initialize the debug proc device */ - s->ps = create_proc_read_entry("es1371",0,NULL,proc_es1371_dump,NULL); -#endif /* ES1371_DEBUG */ - - /* initialize codec registers */ - s->ctrl = 0; - - /* Check amplifier requirements */ - - if (amplifier[devindex]) - s->ctrl |= CTRL_GPIO_OUT0; - else for(idx = 0; amplifier_needed[idx].svid != PCI_ANY_ID; idx++) - { - if(pcidev->subsystem_vendor == amplifier_needed[idx].svid && - pcidev->subsystem_device == amplifier_needed[idx].sdid) - { - s->ctrl |= CTRL_GPIO_OUT0; /* turn internal amplifier on */ - printk(KERN_INFO PFX "Enabling internal amplifier.\n"); - } - } - - s->sctrl = 0; - cssr = 0; - s->spdif_volume = -1; - /* check to see if s/pdif mode is being requested */ - if (spdif[devindex]) { - if (s->rev >= 4) { - printk(KERN_INFO PFX "enabling S/PDIF output\n"); - s->spdif_volume = 0; - cssr |= STAT_EN_SPDIF; - s->ctrl |= CTRL_SPDIFEN_B; - if (nomix[devindex]) /* don't mix analog inputs to s/pdif output */ - s->ctrl |= CTRL_RECEN_B; - } else { - printk(KERN_ERR PFX "revision %d does not support S/PDIF\n", s->rev); - } - } - /* initialize the chips */ - outl(s->ctrl, s->io+ES1371_REG_CONTROL); - outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL); - outl(LEGACY_JFAST, s->io+ES1371_REG_LEGACY); - pci_set_master(pcidev); /* enable bus mastering */ - /* if we are a 5880 turn on the AC97 */ - if (s->vendor == PCI_VENDOR_ID_ENSONIQ && - ((s->device == PCI_DEVICE_ID_ENSONIQ_CT5880 && s->rev >= CT5880REV_CT5880_C) || - (s->device == PCI_DEVICE_ID_ENSONIQ_ES1371 && s->rev == ES1371REV_CT5880_A) || - (s->device == PCI_DEVICE_ID_ENSONIQ_ES1371 && s->rev == ES1371REV_ES1373_8))) { - cssr |= CSTAT_5880_AC97_RST; - outl(cssr, s->io+ES1371_REG_STATUS); - /* need to delay around 20ms(bleech) to give - some CODECs enough time to wakeup */ - tmo = jiffies + (HZ / 50) + 1; - for (;;) { - tmo2 = tmo - jiffies; - if (tmo2 <= 0) - break; - schedule_timeout(tmo2); - } - } - /* AC97 warm reset to start the bitclk */ - outl(s->ctrl | CTRL_SYNCRES, s->io+ES1371_REG_CONTROL); - udelay(2); - outl(s->ctrl, s->io+ES1371_REG_CONTROL); - /* init the sample rate converter */ - src_init(s); - /* codec init */ - if (!ac97_probe_codec(s->codec)) { - res = -ENODEV; - goto err_gp; - } - /* set default values */ - - fs = get_fs(); - set_fs(KERNEL_DS); - val = SOUND_MASK_LINE; - mixdev_ioctl(s->codec, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val); - for (i = 0; i < ARRAY_SIZE(initvol); i++) { - val = initvol[i].vol; - mixdev_ioctl(s->codec, initvol[i].mixch, (unsigned long)&val); - } - /* mute master and PCM when in S/PDIF mode */ - if (s->spdif_volume != -1) { - val = 0x0000; - s->codec->mixer_ioctl(s->codec, SOUND_MIXER_WRITE_VOLUME, (unsigned long)&val); - s->codec->mixer_ioctl(s->codec, SOUND_MIXER_WRITE_PCM, (unsigned long)&val); - } - set_fs(fs); - /* turn on S/PDIF output driver if requested */ - outl(cssr, s->io+ES1371_REG_STATUS); - - es1371_register_gameport(s); - - /* store it in the driver field */ - pci_set_drvdata(pcidev, s); - /* put it into driver list */ - list_add_tail(&s->devs, &devs); - /* increment devindex */ - if (devindex < NR_DEVICE-1) - devindex++; - return 0; - - err_gp: -#ifdef ES1371_DEBUG - if (s->ps) - remove_proc_entry("es1371", NULL); -#endif - unregister_sound_midi(s->dev_midi); - err_dev4: - unregister_sound_dsp(s->dev_dac); - err_dev3: - unregister_sound_mixer(s->codec->dev_mixer); - err_dev2: - unregister_sound_dsp(s->dev_audio); - err_dev1: - printk(KERN_ERR PFX "cannot register misc device\n"); - free_irq(s->irq, s); - err_irq: - release_region(s->io, ES1371_EXTENT); - err_region: - err_codec: - ac97_release_codec(s->codec); - kfree(s); - return res; -} - -static void __devexit es1371_remove(struct pci_dev *dev) -{ - struct es1371_state *s = pci_get_drvdata(dev); - - if (!s) - return; - list_del(&s->devs); -#ifdef ES1371_DEBUG - if (s->ps) - remove_proc_entry("es1371", NULL); -#endif /* ES1371_DEBUG */ - outl(0, s->io+ES1371_REG_CONTROL); /* switch everything off */ - outl(0, s->io+ES1371_REG_SERIAL_CONTROL); /* clear serial interrupts */ - synchronize_irq(s->irq); - free_irq(s->irq, s); - es1371_unregister_gameport(s); - release_region(s->io, ES1371_EXTENT); - unregister_sound_dsp(s->dev_audio); - unregister_sound_mixer(s->codec->dev_mixer); - unregister_sound_dsp(s->dev_dac); - unregister_sound_midi(s->dev_midi); - ac97_release_codec(s->codec); - kfree(s); - pci_set_drvdata(dev, NULL); -} - -static struct pci_device_id id_table[] = { - { PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1371, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, - { PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_CT5880, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, - { PCI_VENDOR_ID_ECTIVA, PCI_DEVICE_ID_ECTIVA_EV1938, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, - { 0, } -}; - -MODULE_DEVICE_TABLE(pci, id_table); - -static struct pci_driver es1371_driver = { - .name = "es1371", - .id_table = id_table, - .probe = es1371_probe, - .remove = __devexit_p(es1371_remove), -}; - -static int __init init_es1371(void) -{ - printk(KERN_INFO PFX "version v0.32 time " __TIME__ " " __DATE__ "\n"); - return pci_register_driver(&es1371_driver); -} - -static void __exit cleanup_es1371(void) -{ - printk(KERN_INFO PFX "unloading\n"); - pci_unregister_driver(&es1371_driver); -} - -module_init(init_es1371); -module_exit(cleanup_es1371); - -/* --------------------------------------------------------------------- */ - -#ifndef MODULE - -/* format is: es1371=[spdif,[nomix,[amplifier]]] */ - -static int __init es1371_setup(char *str) -{ - static unsigned __initdata nr_dev = 0; - - if (nr_dev >= NR_DEVICE) - return 0; - - (void) - ((get_option(&str, &spdif[nr_dev]) == 2) - && (get_option(&str, &nomix[nr_dev]) == 2) - && (get_option(&str, &lifier[nr_dev]))); - - nr_dev++; - return 1; -} - -__setup("es1371=", es1371_setup); - -#endif /* MODULE */ diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index c6b44102aa5..356bf21a150 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -170,14 +170,14 @@ config SND_CA0106 will be called snd-ca0106. config SND_CMIPCI - tristate "C-Media 8738, 8338" + tristate "C-Media 8338, 8738, 8768, 8770" depends on SND select SND_OPL3_LIB select SND_MPU401_UART select SND_PCM help - If you want to use soundcards based on C-Media CMI8338 or CMI8738 - chips, say Y here and read + If you want to use soundcards based on C-Media CMI8338, CMI8738, + CMI8768 or CMI8770 chips, say Y here and read <file:Documentation/sound/alsa/CMIPCI.txt>. To compile this driver as a module, choose M here: the module @@ -500,6 +500,103 @@ config SND_HDA_INTEL To compile this driver as a module, choose M here: the module will be called snd-hda-intel. +config SND_HDA_HWDEP + bool "Build hwdep interface for HD-audio driver" + depends on SND_HDA_INTEL + select SND_HWDEP + help + Say Y here to build a hwdep interface for HD-audio driver. + This interface can be used for out-of-band communication + with codecs for debugging purposes. + +config SND_HDA_CODEC_REALTEK + bool "Build Realtek HD-audio codec support" + depends on SND_HDA_INTEL + default y + help + Say Y here to include Realtek HD-audio codec support in + snd-hda-intel driver, such as ALC880. + +config SND_HDA_CODEC_ANALOG + bool "Build Analog Device HD-audio codec support" + depends on SND_HDA_INTEL + default y + help + Say Y here to include Analog Device HD-audio codec support in + snd-hda-intel driver, such as AD1986A. + +config SND_HDA_CODEC_SIGMATEL + bool "Build IDT/Sigmatel HD-audio codec support" + depends on SND_HDA_INTEL + default y + help + Say Y here to include IDT (Sigmatel) HD-audio codec support in + snd-hda-intel driver, such as STAC9200. + +config SND_HDA_CODEC_VIA + bool "Build VIA HD-audio codec support" + depends on SND_HDA_INTEL + default y + help + Say Y here to include VIA HD-audio codec support in + snd-hda-intel driver, such as VT1708. + +config SND_HDA_CODEC_ATIHDMI + bool "Build ATI HDMI HD-audio codec support" + depends on SND_HDA_INTEL + default y + help + Say Y here to include ATI HDMI HD-audio codec support in + snd-hda-intel driver, such as ATI RS600 HDMI. + +config SND_HDA_CODEC_CONEXANT + bool "Build Conexant HD-audio codec support" + depends on SND_HDA_INTEL + default y + help + Say Y here to include Conexant HD-audio codec support in + snd-hda-intel driver, such as CX20549. + +config SND_HDA_CODEC_CMEDIA + bool "Build C-Media HD-audio codec support" + depends on SND_HDA_INTEL + default y + help + Say Y here to include C-Media HD-audio codec support in + snd-hda-intel driver, such as CMI9880. + +config SND_HDA_CODEC_SI3054 + bool "Build Silicon Labs 3054 HD-modem codec support" + depends on SND_HDA_INTEL + default y + help + Say Y here to include Silicon Labs 3054 HD-modem codec + (and compatibles) support in snd-hda-intel driver. + +config SND_HDA_GENERIC + bool "Enable generic HD-audio codec parser" + depends on SND_HDA_INTEL + default y + help + Say Y here to enable the generic HD-audio codec parser + in snd-hda-intel driver. + +config SND_HDA_POWER_SAVE + bool "Aggressive power-saving on HD-audio" + depends on SND_HDA_INTEL && EXPERIMENTAL + help + Say Y here to enable more aggressive power-saving mode on + HD-audio driver. The power-saving timeout can be configured + via power_save option or over sysfs on-the-fly. + +config SND_HDA_POWER_SAVE_DEFAULT + int "Default time-out for HD-audio power-save mode" + depends on SND_HDA_POWER_SAVE + default 0 + help + The default time-out value in seconds for HD-audio automatic + power-save mode. 0 means to disable the power-save mode. + config SND_HDSP tristate "RME Hammerfall DSP Audio" depends on SND @@ -799,4 +896,12 @@ config SND_AC97_POWER_SAVE snd-ac97-codec driver. You can toggle it dynamically over sysfs, too. +config SND_AC97_POWER_SAVE_DEFAULT + int "Default time-out for AC97 power-save mode" + depends on SND_AC97_POWER_SAVE + default 0 + help + The default time-out value in seconds for AC97 automatic + power-save mode. 0 means to disable the power-save mode. + endmenu diff --git a/sound/pci/Makefile b/sound/pci/Makefile index cd76e0293d0..09ddc82eeca 100644 --- a/sound/pci/Makefile +++ b/sound/pci/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-ad1889-objs := ad1889.o diff --git a/sound/pci/ac97/Makefile b/sound/pci/ac97/Makefile index f5d471896b9..0be48b1a22d 100644 --- a/sound/pci/ac97/Makefile +++ b/sound/pci/ac97/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-ac97-codec-objs := ac97_codec.o ac97_pcm.o diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index bbed644bf9c..6a9966df0cc 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -1,5 +1,5 @@ /* - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * Universal interface for Audio Codec '97 * * For more details look to AC '97 component specification revision 2.2 @@ -39,7 +39,7 @@ #include "ac97_patch.c" -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("Universal interface for Audio Codec '97"); MODULE_LICENSE("GPL"); @@ -49,7 +49,7 @@ module_param(enable_loopback, bool, 0444); MODULE_PARM_DESC(enable_loopback, "Enable AC97 ADC/DAC Loopback Control"); #ifdef CONFIG_SND_AC97_POWER_SAVE -static int power_save; +static int power_save = CONFIG_SND_AC97_POWER_SAVE_DEFAULT; module_param(power_save, bool, 0644); MODULE_PARM_DESC(power_save, "Enable AC97 power-saving control"); #endif @@ -176,7 +176,7 @@ static const struct ac97_codec_id snd_ac97_codec_ids[] = { { 0x574d4C09, 0xffffffff, "WM9709", NULL, NULL}, { 0x574d4C12, 0xffffffff, "WM9711,WM9712", patch_wolfson11, NULL}, { 0x574d4c13, 0xffffffff, "WM9713,WM9714", patch_wolfson13, NULL, AC97_DEFAULT_POWER_OFF}, -{ 0x594d4800, 0xffffffff, "YMF743", NULL, NULL }, +{ 0x594d4800, 0xffffffff, "YMF743", patch_yamaha_ymf743, NULL }, { 0x594d4802, 0xffffffff, "YMF752", NULL, NULL }, { 0x594d4803, 0xffffffff, "YMF753", patch_yamaha_ymf753, NULL }, { 0x83847600, 0xffffffff, "STAC9700,83,84", patch_sigmatel_stac9700, NULL }, @@ -779,6 +779,12 @@ static int snd_ac97_spdif_default_put(struct snd_kcontrol *kcontrol, struct snd_ change |= snd_ac97_update_bits_nolock(ac97, AC97_CXR_AUDIO_MISC, AC97_CXR_SPDIF_MASK | AC97_CXR_COPYRGT, v); + } else if (ac97->id == AC97_ID_YMF743) { + change |= snd_ac97_update_bits_nolock(ac97, + AC97_YMF7X3_DIT_CTRL, + 0xff38, + ((val << 4) & 0xff00) | + ((val << 2) & 0x0038)); } else { unsigned short extst = snd_ac97_read_cache(ac97, AC97_EXTENDED_STATUS); snd_ac97_update_bits_nolock(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, 0); /* turn off */ @@ -1375,7 +1381,8 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) for (idx = 0; idx < 2; idx++) { if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_tone[idx], ac97))) < 0) return err; - if (ac97->id == AC97_ID_YMF753) { + if (ac97->id == AC97_ID_YMF743 || + ac97->id == AC97_ID_YMF753) { kctl->private_value &= ~(0xff << 16); kctl->private_value |= 7 << 16; } @@ -2036,11 +2043,12 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template, else { udelay(50); if (ac97->scaps & AC97_SCAP_SKIP_AUDIO) - err = ac97_reset_wait(ac97, HZ/2, 1); + err = ac97_reset_wait(ac97, msecs_to_jiffies(500), 1); else { - err = ac97_reset_wait(ac97, HZ/2, 0); + err = ac97_reset_wait(ac97, msecs_to_jiffies(500), 0); if (err < 0) - err = ac97_reset_wait(ac97, HZ/2, 1); + err = ac97_reset_wait(ac97, + msecs_to_jiffies(500), 1); } if (err < 0) { snd_printk(KERN_WARNING "AC'97 %d does not respond - RESET\n", ac97->num); @@ -2104,7 +2112,7 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template, } /* nothing should be in powerdown mode */ snd_ac97_write_cache(ac97, AC97_GENERAL_PURPOSE, 0); - end_time = jiffies + (HZ / 10); + end_time = jiffies + msecs_to_jiffies(100); do { if ((snd_ac97_read(ac97, AC97_POWERDOWN) & 0x0f) == 0x0f) goto __ready_ok; @@ -2136,7 +2144,7 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template, udelay(100); /* nothing should be in powerdown mode */ snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0); - end_time = jiffies + (HZ / 10); + end_time = jiffies + msecs_to_jiffies(100); do { if ((snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS) & tmp) == tmp) goto __ready_ok; @@ -2354,7 +2362,8 @@ int snd_ac97_update_power(struct snd_ac97 *ac97, int reg, int powerup) * (for avoiding loud click noises for many (OSS) apps * that open/close frequently) */ - schedule_delayed_work(&ac97->power_work, HZ*2); + schedule_delayed_work(&ac97->power_work, + msecs_to_jiffies(2000)); else { cancel_delayed_work(&ac97->power_work); update_power_regs(ac97); @@ -2436,7 +2445,7 @@ EXPORT_SYMBOL(snd_ac97_suspend); /* * restore ac97 status */ -void snd_ac97_restore_status(struct snd_ac97 *ac97) +static void snd_ac97_restore_status(struct snd_ac97 *ac97) { int i; @@ -2457,7 +2466,7 @@ void snd_ac97_restore_status(struct snd_ac97 *ac97) /* * restore IEC958 status */ -void snd_ac97_restore_iec958(struct snd_ac97 *ac97) +static void snd_ac97_restore_iec958(struct snd_ac97 *ac97) { if (ac97->ext_id & AC97_EI_SPDIF) { if (ac97->regs[AC97_EXTENDED_STATUS] & AC97_EA_SPDIF) { @@ -2494,7 +2503,10 @@ void snd_ac97_resume(struct snd_ac97 *ac97) snd_ac97_write(ac97, AC97_POWERDOWN, 0); if (! (ac97->flags & AC97_DEFAULT_POWER_OFF)) { - snd_ac97_write(ac97, AC97_RESET, 0); + if (!(ac97->scaps & AC97_SCAP_SKIP_AUDIO)) + snd_ac97_write(ac97, AC97_RESET, 0); + else if (!(ac97->scaps & AC97_SCAP_SKIP_MODEM)) + snd_ac97_write(ac97, AC97_EXTENDED_MID, 0); udelay(100); snd_ac97_write(ac97, AC97_POWERDOWN, 0); } diff --git a/sound/pci/ac97/ac97_id.h b/sound/pci/ac97/ac97_id.h index 6d73514dc49..c129492c82b 100644 --- a/sound/pci/ac97/ac97_id.h +++ b/sound/pci/ac97/ac97_id.h @@ -1,5 +1,5 @@ /* - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * Universal interface for Audio Codec '97 * * For more details look to AC '97 component specification revision 2.2 @@ -54,6 +54,7 @@ #define AC97_ID_ALC658 0x414c4780 #define AC97_ID_ALC658D 0x414c4781 #define AC97_ID_ALC850 0x414c4790 +#define AC97_ID_YMF743 0x594d4800 #define AC97_ID_YMF753 0x594d4803 #define AC97_ID_VT1616 0x49434551 #define AC97_ID_CM9738 0x434d4941 diff --git a/sound/pci/ac97/ac97_local.h b/sound/pci/ac97/ac97_local.h index 78745c5c6df..c276a5e3f7a 100644 --- a/sound/pci/ac97/ac97_local.h +++ b/sound/pci/ac97/ac97_local.h @@ -1,5 +1,5 @@ /* - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * Universal interface for Audio Codec '97 * * For more details look to AC '97 component specification revision 2.2 diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 581ebba4d1a..98c8b727b62 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -1,5 +1,5 @@ /* - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * Universal interface for Audio Codec '97 * * For more details look to AC '97 component specification revision 2.2 @@ -204,9 +204,13 @@ static inline int is_shared_micin(struct snd_ac97 *ac97) /* The following snd_ac97_ymf753_... items added by David Shust (dshust@shustring.com) */ +/* Modified for YMF743 by Keita Maehara <maehara@debian.org> */ -/* It is possible to indicate to the Yamaha YMF753 the type of speakers being used. */ -static int snd_ac97_ymf753_info_speaker(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) +/* It is possible to indicate to the Yamaha YMF7x3 the type of + speakers being used. */ + +static int snd_ac97_ymf7x3_info_speaker(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) { static char *texts[3] = { "Standard", "Small", "Smaller" @@ -221,12 +225,13 @@ static int snd_ac97_ymf753_info_speaker(struct snd_kcontrol *kcontrol, struct sn return 0; } -static int snd_ac97_ymf753_get_speaker(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +static int snd_ac97_ymf7x3_get_speaker(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); unsigned short val; - val = ac97->regs[AC97_YMF753_3D_MODE_SEL]; + val = ac97->regs[AC97_YMF7X3_3D_MODE_SEL]; val = (val >> 10) & 3; if (val > 0) /* 0 = invalid */ val--; @@ -234,7 +239,8 @@ static int snd_ac97_ymf753_get_speaker(struct snd_kcontrol *kcontrol, struct snd return 0; } -static int snd_ac97_ymf753_put_speaker(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +static int snd_ac97_ymf7x3_put_speaker(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); unsigned short val; @@ -242,20 +248,22 @@ static int snd_ac97_ymf753_put_speaker(struct snd_kcontrol *kcontrol, struct snd if (ucontrol->value.enumerated.item[0] > 2) return -EINVAL; val = (ucontrol->value.enumerated.item[0] + 1) << 10; - return snd_ac97_update(ac97, AC97_YMF753_3D_MODE_SEL, val); + return snd_ac97_update(ac97, AC97_YMF7X3_3D_MODE_SEL, val); } -static const struct snd_kcontrol_new snd_ac97_ymf753_controls_speaker = +static const struct snd_kcontrol_new snd_ac97_ymf7x3_controls_speaker = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "3D Control - Speaker", - .info = snd_ac97_ymf753_info_speaker, - .get = snd_ac97_ymf753_get_speaker, - .put = snd_ac97_ymf753_put_speaker, + .info = snd_ac97_ymf7x3_info_speaker, + .get = snd_ac97_ymf7x3_get_speaker, + .put = snd_ac97_ymf7x3_put_speaker, }; -/* It is possible to indicate to the Yamaha YMF753 the source to direct to the S/PDIF output. */ -static int snd_ac97_ymf753_spdif_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) +/* It is possible to indicate to the Yamaha YMF7x3 the source to + direct to the S/PDIF output. */ +static int snd_ac97_ymf7x3_spdif_source_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) { static char *texts[2] = { "AC-Link", "A/D Converter" }; @@ -268,17 +276,19 @@ static int snd_ac97_ymf753_spdif_source_info(struct snd_kcontrol *kcontrol, stru return 0; } -static int snd_ac97_ymf753_spdif_source_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +static int snd_ac97_ymf7x3_spdif_source_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); unsigned short val; - val = ac97->regs[AC97_YMF753_DIT_CTRL2]; + val = ac97->regs[AC97_YMF7X3_DIT_CTRL]; ucontrol->value.enumerated.item[0] = (val >> 1) & 1; return 0; } -static int snd_ac97_ymf753_spdif_source_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +static int snd_ac97_ymf7x3_spdif_source_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); unsigned short val; @@ -286,7 +296,75 @@ static int snd_ac97_ymf753_spdif_source_put(struct snd_kcontrol *kcontrol, struc if (ucontrol->value.enumerated.item[0] > 1) return -EINVAL; val = ucontrol->value.enumerated.item[0] << 1; - return snd_ac97_update_bits(ac97, AC97_YMF753_DIT_CTRL2, 0x0002, val); + return snd_ac97_update_bits(ac97, AC97_YMF7X3_DIT_CTRL, 0x0002, val); +} + +static int patch_yamaha_ymf7x3_3d(struct snd_ac97 *ac97) +{ + struct snd_kcontrol *kctl; + int err; + + kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97); + err = snd_ctl_add(ac97->bus->card, kctl); + if (err < 0) + return err; + strcpy(kctl->id.name, "3D Control - Wide"); + kctl->private_value = AC97_SINGLE_VALUE(AC97_3D_CONTROL, 9, 7, 0); + snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000); + err = snd_ctl_add(ac97->bus->card, + snd_ac97_cnew(&snd_ac97_ymf7x3_controls_speaker, + ac97)); + if (err < 0) + return err; + snd_ac97_write_cache(ac97, AC97_YMF7X3_3D_MODE_SEL, 0x0c00); + return 0; +} + +static const struct snd_kcontrol_new snd_ac97_yamaha_ymf743_controls_spdif[3] = +{ + AC97_SINGLE(SNDRV_CTL_NAME_IEC958("", PLAYBACK, SWITCH), + AC97_YMF7X3_DIT_CTRL, 0, 1, 0), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, NONE) "Source", + .info = snd_ac97_ymf7x3_spdif_source_info, + .get = snd_ac97_ymf7x3_spdif_source_get, + .put = snd_ac97_ymf7x3_spdif_source_put, + }, + AC97_SINGLE(SNDRV_CTL_NAME_IEC958("", NONE, NONE) "Mute", + AC97_YMF7X3_DIT_CTRL, 2, 1, 1) +}; + +static int patch_yamaha_ymf743_build_spdif(struct snd_ac97 *ac97) +{ + int err; + + err = patch_build_controls(ac97, &snd_ac97_controls_spdif[0], 3); + if (err < 0) + return err; + err = patch_build_controls(ac97, + snd_ac97_yamaha_ymf743_controls_spdif, 3); + if (err < 0) + return err; + /* set default PCM S/PDIF params */ + /* PCM audio,no copyright,no preemphasis,PCM coder,original */ + snd_ac97_write_cache(ac97, AC97_YMF7X3_DIT_CTRL, 0xa201); + return 0; +} + +static struct snd_ac97_build_ops patch_yamaha_ymf743_ops = { + .build_spdif = patch_yamaha_ymf743_build_spdif, + .build_3d = patch_yamaha_ymf7x3_3d, +}; + +static int patch_yamaha_ymf743(struct snd_ac97 *ac97) +{ + ac97->build_ops = &patch_yamaha_ymf743_ops; + ac97->caps |= AC97_BC_BASS_TREBLE; + ac97->caps |= 0x04 << 10; /* Yamaha 3D enhancement */ + ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_48000; /* 48k only */ + ac97->ext_id |= AC97_EI_SPDIF; /* force the detection of spdif */ + return 0; } /* The AC'97 spec states that the S/PDIF signal is to be output at pin 48. @@ -311,7 +389,7 @@ static int snd_ac97_ymf753_spdif_output_pin_get(struct snd_kcontrol *kcontrol, s struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); unsigned short val; - val = ac97->regs[AC97_YMF753_DIT_CTRL2]; + val = ac97->regs[AC97_YMF7X3_DIT_CTRL]; ucontrol->value.enumerated.item[0] = (val & 0x0008) ? 2 : (val & 0x0020) ? 1 : 0; return 0; } @@ -325,7 +403,7 @@ static int snd_ac97_ymf753_spdif_output_pin_put(struct snd_kcontrol *kcontrol, s return -EINVAL; val = (ucontrol->value.enumerated.item[0] == 2) ? 0x0008 : (ucontrol->value.enumerated.item[0] == 1) ? 0x0020 : 0; - return snd_ac97_update_bits(ac97, AC97_YMF753_DIT_CTRL2, 0x0028, val); + return snd_ac97_update_bits(ac97, AC97_YMF7X3_DIT_CTRL, 0x0028, val); /* The following can be used to direct S/PDIF output to pin 47 (EAPD). snd_ac97_write_cache(ac97, 0x62, snd_ac97_read(ac97, 0x62) | 0x0008); */ } @@ -334,9 +412,9 @@ static const struct snd_kcontrol_new snd_ac97_ymf753_controls_spdif[3] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", - .info = snd_ac97_ymf753_spdif_source_info, - .get = snd_ac97_ymf753_spdif_source_get, - .put = snd_ac97_ymf753_spdif_source_put, + .info = snd_ac97_ymf7x3_spdif_source_info, + .get = snd_ac97_ymf7x3_spdif_source_get, + .put = snd_ac97_ymf7x3_spdif_source_put, }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -345,25 +423,10 @@ static const struct snd_kcontrol_new snd_ac97_ymf753_controls_spdif[3] = { .get = snd_ac97_ymf753_spdif_output_pin_get, .put = snd_ac97_ymf753_spdif_output_pin_put, }, - AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",NONE,NONE) "Mute", AC97_YMF753_DIT_CTRL2, 2, 1, 1) + AC97_SINGLE(SNDRV_CTL_NAME_IEC958("", NONE, NONE) "Mute", + AC97_YMF7X3_DIT_CTRL, 2, 1, 1) }; -static int patch_yamaha_ymf753_3d(struct snd_ac97 * ac97) -{ - struct snd_kcontrol *kctl; - int err; - - if ((err = snd_ctl_add(ac97->bus->card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0) - return err; - strcpy(kctl->id.name, "3D Control - Wide"); - kctl->private_value = AC97_SINGLE_VALUE(AC97_3D_CONTROL, 9, 7, 0); - snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000); - if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&snd_ac97_ymf753_controls_speaker, ac97))) < 0) - return err; - snd_ac97_write_cache(ac97, AC97_YMF753_3D_MODE_SEL, 0x0c00); - return 0; -} - static int patch_yamaha_ymf753_post_spdif(struct snd_ac97 * ac97) { int err; @@ -374,7 +437,7 @@ static int patch_yamaha_ymf753_post_spdif(struct snd_ac97 * ac97) } static struct snd_ac97_build_ops patch_yamaha_ymf753_ops = { - .build_3d = patch_yamaha_ymf753_3d, + .build_3d = patch_yamaha_ymf7x3_3d, .build_post_spdif = patch_yamaha_ymf753_post_spdif }; @@ -1880,14 +1943,7 @@ static int patch_ad1981b(struct snd_ac97 *ac97) return 0; } -static int snd_ac97_ad1888_lohpsel_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_ac97_ad1888_lohpsel_info snd_ctl_boolean_mono_info static int snd_ac97_ad1888_lohpsel_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -2186,15 +2242,7 @@ static int patch_ad1985(struct snd_ac97 * ac97) return 0; } -static int snd_ac97_ad1986_bool_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_ac97_ad1986_bool_info snd_ctl_boolean_mono_info static int snd_ac97_ad1986_lososel_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/pci/ac97/ac97_patch.h b/sound/pci/ac97/ac97_patch.h index fd341ce6376..9cccc27ea1b 100644 --- a/sound/pci/ac97/ac97_patch.h +++ b/sound/pci/ac97/ac97_patch.h @@ -1,5 +1,5 @@ /* - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * Universal interface for Audio Codec '97 * * For more details look to AC '97 component specification revision 2.2 diff --git a/sound/pci/ac97/ac97_pcm.c b/sound/pci/ac97/ac97_pcm.c index 4281e6d0c5b..8cbc03332b0 100644 --- a/sound/pci/ac97/ac97_pcm.c +++ b/sound/pci/ac97/ac97_pcm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * Universal interface for Audio Codec '97 * * For more details look to AC '97 component specification revision 2.2 diff --git a/sound/pci/ac97/ac97_proc.c b/sound/pci/ac97/ac97_proc.c index a3fdd7da911..fed4a2c3d8a 100644 --- a/sound/pci/ac97/ac97_proc.c +++ b/sound/pci/ac97/ac97_proc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * Universal interface for Audio Codec '97 * * For more details look to AC '97 component specification revision 2.2 @@ -236,10 +236,14 @@ static void snd_ac97_proc_read_main(struct snd_ac97 *ac97, struct snd_info_buffe val = snd_ac97_read(ac97, AC97_PCM_MIC_ADC_RATE); snd_iprintf(buffer, "PCM MIC ADC : %iHz\n", val); } - if ((ext & AC97_EI_SPDIF) || (ac97->flags & AC97_CS_SPDIF)) { + if ((ext & AC97_EI_SPDIF) || (ac97->flags & AC97_CS_SPDIF) || + (ac97->id == AC97_ID_YMF743)) { if (ac97->flags & AC97_CS_SPDIF) val = snd_ac97_read(ac97, AC97_CSR_SPDIF); - else + else if (ac97->id == AC97_ID_YMF743) { + val = snd_ac97_read(ac97, AC97_YMF7X3_DIT_CTRL); + val = 0x2000 | (val & 0xff00) >> 4 | (val & 0x38) >> 2; + } else val = snd_ac97_read(ac97, AC97_SPDIF); snd_iprintf(buffer, "SPDIF Control :%s%s%s%s Category=0x%x Generation=%i%s%s%s\n", diff --git a/sound/pci/ac97/ak4531_codec.c b/sound/pci/ac97/ak4531_codec.c index dc26820a03a..722de451d15 100644 --- a/sound/pci/ac97/ak4531_codec.c +++ b/sound/pci/ac97/ak4531_codec.c @@ -1,5 +1,5 @@ /* - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * Universal routines for AK4531 codec * * @@ -29,7 +29,7 @@ #include <sound/ak4531_codec.h> #include <sound/tlv.h> -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("Universal routines for AK4531 codec"); MODULE_LICENSE("GPL"); diff --git a/sound/pci/ali5451/Makefile b/sound/pci/ali5451/Makefile index 2e183159747..713459c12d2 100644 --- a/sound/pci/ali5451/Makefile +++ b/sound/pci/ali5451/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-ali5451-objs := ali5451.o diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c index 05b4c869694..4c2bd7adf67 100644 --- a/sound/pci/ali5451/ali5451.c +++ b/sound/pci/ali5451/ali5451.c @@ -1804,15 +1804,7 @@ static int __devinit snd_ali_build_pcms(struct snd_ali *codec) .info = snd_ali5451_spdif_info, .get = snd_ali5451_spdif_get, \ .put = snd_ali5451_spdif_put, .private_value = value} -static int snd_ali5451_spdif_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_ali5451_spdif_info snd_ctl_boolean_mono_info static int snd_ali5451_spdif_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c index 8fb55d3b454..1190ef366a4 100644 --- a/sound/pci/als4000.c +++ b/sound/pci/als4000.c @@ -1,7 +1,7 @@ /* * card-als4000.c - driver for Avance Logic ALS4000 based soundcards. * Copyright (C) 2000 by Bart Hartgers <bart@etpmod.phys.tue.nl>, - * Jaroslav Kysela <perex@suse.cz> + * Jaroslav Kysela <perex@perex.cz> * Copyright (C) 2002 by Andreas Mohr <hw7oshyuv3001@sneakemail.com> * * Framework borrowed from Massimo Piccioni's card-als100.c. diff --git a/sound/pci/au88x0/au88x0.c b/sound/pci/au88x0/au88x0.c index 5ec1b6fcd54..f70286a7364 100644 --- a/sound/pci/au88x0/au88x0.c +++ b/sound/pci/au88x0/au88x0.c @@ -232,6 +232,7 @@ snd_vortex_create(struct snd_card *card, struct pci_dev *pci, vortex_t ** rchip) pci_disable_device(chip->pci_dev); //FIXME: this not the right place to unregister the gameport vortex_gameport_unregister(chip); + kfree(chip); return err; } diff --git a/sound/pci/au88x0/au88x0_eq.c b/sound/pci/au88x0/au88x0_eq.c index 0c86a31c433..38602b85874 100644 --- a/sound/pci/au88x0/au88x0_eq.c +++ b/sound/pci/au88x0/au88x0_eq.c @@ -728,15 +728,7 @@ static void vortex_Eqlzr_shutdown(vortex_t * vortex) /* ALSA interface */ /* Control interface */ -static int -snd_vortex_eqtoggle_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_vortex_eqtoggle_info snd_ctl_boolean_mono_info static int snd_vortex_eqtoggle_get(struct snd_kcontrol *kcontrol, diff --git a/sound/pci/au88x0/au88x0_mpu401.c b/sound/pci/au88x0/au88x0_mpu401.c index c75d368ea08..8db3d3e6f7b 100644 --- a/sound/pci/au88x0/au88x0_mpu401.c +++ b/sound/pci/au88x0/au88x0_mpu401.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 MPU-401 in UART mode * * Modified for the Aureal Vortex based Soundcards diff --git a/sound/pci/au88x0/au88x0_synth.c b/sound/pci/au88x0/au88x0_synth.c index d3e662a1285..978b856f562 100644 --- a/sound/pci/au88x0/au88x0_synth.c +++ b/sound/pci/au88x0/au88x0_synth.c @@ -370,8 +370,8 @@ static void vortex_wt_SetFrequency(vortex_t * vortex, int wt, unsigned int sr) while ((edx & 0x80000000) == 0) { edx <<= 1; eax--; - if (eax == 0) ; - break; + if (eax == 0) + break; } if (eax) edx <<= 1; diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c index 188c7cf21b8..91f9e6a112f 100644 --- a/sound/pci/bt87x.c +++ b/sound/pci/bt87x.c @@ -147,17 +147,58 @@ MODULE_PARM_DESC(load_all, "Allow to load the non-whitelisted cards"); /* SYNC, one WRITE per line, one extra WRITE per page boundary, SYNC, JUMP */ #define MAX_RISC_SIZE ((1 + 255 + (PAGE_ALIGN(255 * 4092) / PAGE_SIZE - 1) + 1 + 1) * 8) +/* Cards with configuration information */ +enum snd_bt87x_boardid { + SND_BT87X_BOARD_UNKNOWN, + SND_BT87X_BOARD_GENERIC, /* both an & dig interfaces, 32kHz */ + SND_BT87X_BOARD_ANALOG, /* board with no external A/D */ + SND_BT87X_BOARD_OSPREY2x0, + SND_BT87X_BOARD_OSPREY440, + SND_BT87X_BOARD_AVPHONE98, +}; + +/* Card configuration */ +struct snd_bt87x_board { + int dig_rate; /* Digital input sampling rate */ + u32 digital_fmt; /* Register settings for digital input */ + unsigned no_analog:1; /* No analog input */ + unsigned no_digital:1; /* No digital input */ +}; + +static const __devinitdata struct snd_bt87x_board snd_bt87x_boards[] = { + [SND_BT87X_BOARD_UNKNOWN] = { + .dig_rate = 32000, /* just a guess */ + }, + [SND_BT87X_BOARD_GENERIC] = { + .dig_rate = 32000, + }, + [SND_BT87X_BOARD_ANALOG] = { + .no_digital = 1, + }, + [SND_BT87X_BOARD_OSPREY2x0] = { + .dig_rate = 44100, + .digital_fmt = CTL_DA_LRI | (1 << CTL_DA_LRD_SHIFT), + }, + [SND_BT87X_BOARD_OSPREY440] = { + .dig_rate = 32000, + .digital_fmt = CTL_DA_LRI | (1 << CTL_DA_LRD_SHIFT), + .no_analog = 1, + }, + [SND_BT87X_BOARD_AVPHONE98] = { + .dig_rate = 48000, + }, +}; + struct snd_bt87x { struct snd_card *card; struct pci_dev *pci; + struct snd_bt87x_board board; void __iomem *mmio; int irq; - int dig_rate; - spinlock_t reg_lock; - long opened; + unsigned long opened; struct snd_pcm_substream *substream; struct snd_dma_buffer dma_risc; @@ -340,30 +381,11 @@ static struct snd_pcm_hardware snd_bt87x_analog_hw = { static int snd_bt87x_set_digital_hw(struct snd_bt87x *chip, struct snd_pcm_runtime *runtime) { - static struct { - int rate; - unsigned int bit; - } ratebits[] = { - {8000, SNDRV_PCM_RATE_8000}, - {11025, SNDRV_PCM_RATE_11025}, - {16000, SNDRV_PCM_RATE_16000}, - {22050, SNDRV_PCM_RATE_22050}, - {32000, SNDRV_PCM_RATE_32000}, - {44100, SNDRV_PCM_RATE_44100}, - {48000, SNDRV_PCM_RATE_48000} - }; - int i; - - chip->reg_control |= CTL_DA_IOM_DA; + chip->reg_control |= CTL_DA_IOM_DA | CTL_A_PWRDN; runtime->hw = snd_bt87x_digital_hw; - runtime->hw.rates = SNDRV_PCM_RATE_KNOT; - for (i = 0; i < ARRAY_SIZE(ratebits); ++i) - if (chip->dig_rate == ratebits[i].rate) { - runtime->hw.rates = ratebits[i].bit; - break; - } - runtime->hw.rate_min = chip->dig_rate; - runtime->hw.rate_max = chip->dig_rate; + runtime->hw.rates = snd_pcm_rate_to_rate_bit(chip->board.dig_rate); + runtime->hw.rate_min = chip->board.dig_rate; + runtime->hw.rate_max = chip->board.dig_rate; return 0; } @@ -380,7 +402,7 @@ static int snd_bt87x_set_analog_hw(struct snd_bt87x *chip, struct snd_pcm_runtim .rats = &analog_clock }; - chip->reg_control &= ~CTL_DA_IOM_DA; + chip->reg_control &= ~(CTL_DA_IOM_DA | CTL_A_PWRDN); runtime->hw = snd_bt87x_analog_hw; return snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &constraint_rates); @@ -419,6 +441,11 @@ static int snd_bt87x_close(struct snd_pcm_substream *substream) { struct snd_bt87x *chip = snd_pcm_substream_chip(substream); + spin_lock_irq(&chip->reg_lock); + chip->reg_control |= CTL_A_PWRDN; + snd_bt87x_writel(chip, REG_GPIO_DMA_CTL, chip->reg_control); + spin_unlock_irq(&chip->reg_lock); + chip->substream = NULL; clear_bit(0, &chip->opened); smp_mb__after_clear_bit(); @@ -569,15 +596,7 @@ static struct snd_kcontrol_new snd_bt87x_capture_volume = { .put = snd_bt87x_capture_volume_put, }; -static int snd_bt87x_capture_boost_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *info) -{ - info->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - info->count = 1; - info->value.integer.min = 0; - info->value.integer.max = 1; - return 0; -} +#define snd_bt87x_capture_boost_info snd_ctl_boolean_mono_info static int snd_bt87x_capture_boost_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *value) @@ -736,61 +755,69 @@ static int __devinit snd_bt87x_create(struct snd_card *card, chip->mmio = ioremap_nocache(pci_resource_start(pci, 0), pci_resource_len(pci, 0)); if (!chip->mmio) { - snd_bt87x_free(chip); snd_printk(KERN_ERR "cannot remap io memory\n"); - return -ENOMEM; + err = -ENOMEM; + goto fail; } - chip->reg_control = CTL_DA_ES2 | CTL_PKTP_16 | (15 << CTL_DA_SDR_SHIFT); + chip->reg_control = CTL_A_PWRDN | CTL_DA_ES2 | + CTL_PKTP_16 | (15 << CTL_DA_SDR_SHIFT); chip->interrupt_mask = MY_INTERRUPTS; snd_bt87x_writel(chip, REG_GPIO_DMA_CTL, chip->reg_control); snd_bt87x_writel(chip, REG_INT_MASK, 0); snd_bt87x_writel(chip, REG_INT_STAT, MY_INTERRUPTS); - if (request_irq(pci->irq, snd_bt87x_interrupt, IRQF_SHARED, - "Bt87x audio", chip)) { - snd_bt87x_free(chip); - snd_printk(KERN_ERR "cannot grab irq\n"); - return -EBUSY; + err = request_irq(pci->irq, snd_bt87x_interrupt, IRQF_SHARED, + "Bt87x audio", chip); + if (err < 0) { + snd_printk(KERN_ERR "cannot grab irq %d\n", pci->irq); + goto fail; } chip->irq = pci->irq; pci_set_master(pci); synchronize_irq(chip->irq); err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); - if (err < 0) { - snd_bt87x_free(chip); - return err; - } + if (err < 0) + goto fail; + snd_card_set_dev(card, &pci->dev); *rchip = chip; return 0; + +fail: + snd_bt87x_free(chip); + return err; } -#define BT_DEVICE(chip, subvend, subdev, rate) \ +#define BT_DEVICE(chip, subvend, subdev, id) \ { .vendor = PCI_VENDOR_ID_BROOKTREE, \ .device = chip, \ .subvendor = subvend, .subdevice = subdev, \ - .driver_data = rate } + .driver_data = SND_BT87X_BOARD_ ## id } +/* driver_data is the card id for that device */ -/* driver_data is the default digital_rate value for that device */ static struct pci_device_id snd_bt87x_ids[] = { /* Hauppauge WinTV series */ - BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x0070, 0x13eb, 32000), + BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x0070, 0x13eb, GENERIC), /* Hauppauge WinTV series */ - BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_879, 0x0070, 0x13eb, 32000), + BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_879, 0x0070, 0x13eb, GENERIC), /* Viewcast Osprey 200 */ - BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x0070, 0xff01, 44100), + BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x0070, 0xff01, OSPREY2x0), /* Viewcast Osprey 440 (rate is configurable via gpio) */ - BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x0070, 0xff07, 32000), + BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x0070, 0xff07, OSPREY440), /* ATI TV-Wonder */ - BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x1002, 0x0001, 32000), + BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x1002, 0x0001, GENERIC), /* Leadtek Winfast tv 2000xp delux */ - BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x107d, 0x6606, 32000), + BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x107d, 0x6606, GENERIC), /* Voodoo TV 200 */ - BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x121a, 0x3000, 32000), + BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x121a, 0x3000, GENERIC), /* AVerMedia Studio No. 103, 203, ...? */ - BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x1461, 0x0003, 48000), + BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x1461, 0x0003, AVPHONE98), + /* Prolink PixelView PV-M4900 */ + BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x1554, 0x4011, GENERIC), + /* Pinnacle Studio PCTV rave */ + BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0xbd11, 0x1200, GENERIC), { } }; MODULE_DEVICE_TABLE(pci, snd_bt87x_ids); @@ -815,7 +842,7 @@ static struct { static struct pci_driver driver; -/* return the rate of the card, or a negative value if it's blacklisted */ +/* return the id of the card, or a negative value if it's blacklisted */ static int __devinit snd_bt87x_detect_card(struct pci_dev *pci) { int i; @@ -833,12 +860,12 @@ static int __devinit snd_bt87x_detect_card(struct pci_dev *pci) return -EBUSY; } - snd_printk(KERN_INFO "unknown card %#04x-%#04x:%#04x, using default rate 32000\n", - pci->device, pci->subsystem_vendor, pci->subsystem_device); + snd_printk(KERN_INFO "unknown card %#04x-%#04x:%#04x\n", + pci->device, pci->subsystem_vendor, pci->subsystem_device); snd_printk(KERN_DEBUG "please mail id, board name, and, " "if it works, the correct digital_rate option to " "<alsa-devel@alsa-project.org>\n"); - return 32000; /* default rate */ + return SND_BT87X_BOARD_UNKNOWN; } static int __devinit snd_bt87x_probe(struct pci_dev *pci, @@ -847,12 +874,16 @@ static int __devinit snd_bt87x_probe(struct pci_dev *pci, static int dev; struct snd_card *card; struct snd_bt87x *chip; - int err, rate; + int err; + enum snd_bt87x_boardid boardid; - rate = pci_id->driver_data; - if (! rate) - if ((rate = snd_bt87x_detect_card(pci)) <= 0) + if (!pci_id->driver_data) { + err = snd_bt87x_detect_card(pci); + if (err < 0) return -ENODEV; + boardid = err; + } else + boardid = pci_id->driver_data; if (dev >= SNDRV_CARDS) return -ENODEV; @@ -869,27 +900,39 @@ static int __devinit snd_bt87x_probe(struct pci_dev *pci, if (err < 0) goto _error; - if (digital_rate[dev] > 0) - chip->dig_rate = digital_rate[dev]; - else - chip->dig_rate = rate; + memcpy(&chip->board, &snd_bt87x_boards[boardid], sizeof(chip->board)); - err = snd_bt87x_pcm(chip, DEVICE_DIGITAL, "Bt87x Digital"); - if (err < 0) - goto _error; - err = snd_bt87x_pcm(chip, DEVICE_ANALOG, "Bt87x Analog"); - if (err < 0) - goto _error; + if (!chip->board.no_digital) { + if (digital_rate[dev] > 0) + chip->board.dig_rate = digital_rate[dev]; - err = snd_ctl_add(card, snd_ctl_new1(&snd_bt87x_capture_volume, chip)); - if (err < 0) - goto _error; - err = snd_ctl_add(card, snd_ctl_new1(&snd_bt87x_capture_boost, chip)); - if (err < 0) - goto _error; - err = snd_ctl_add(card, snd_ctl_new1(&snd_bt87x_capture_source, chip)); - if (err < 0) - goto _error; + chip->reg_control |= chip->board.digital_fmt; + + err = snd_bt87x_pcm(chip, DEVICE_DIGITAL, "Bt87x Digital"); + if (err < 0) + goto _error; + } + if (!chip->board.no_analog) { + err = snd_bt87x_pcm(chip, DEVICE_ANALOG, "Bt87x Analog"); + if (err < 0) + goto _error; + err = snd_ctl_add(card, snd_ctl_new1( + &snd_bt87x_capture_volume, chip)); + if (err < 0) + goto _error; + err = snd_ctl_add(card, snd_ctl_new1( + &snd_bt87x_capture_boost, chip)); + if (err < 0) + goto _error; + err = snd_ctl_add(card, snd_ctl_new1( + &snd_bt87x_capture_source, chip)); + if (err < 0) + goto _error; + } + snd_printk(KERN_INFO "bt87x%d: Using board %d, %sanalog, %sdigital " + "(rate %d Hz)\n", dev, boardid, + chip->board.no_analog ? "no " : "", + chip->board.no_digital ? "no " : "", chip->board.dig_rate); strcpy(card->driver, "Bt87x"); sprintf(card->shortname, "Brooktree Bt%x", pci->device); @@ -920,8 +963,8 @@ static void __devexit snd_bt87x_remove(struct pci_dev *pci) /* default entries for all Bt87x cards - it's not exported */ /* driver_data is set to 0 to call detection */ static struct pci_device_id snd_bt87x_default_ids[] __devinitdata = { - BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, PCI_ANY_ID, PCI_ANY_ID, 0), - BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_879, PCI_ANY_ID, PCI_ANY_ID, 0), + BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, PCI_ANY_ID, PCI_ANY_ID, UNKNOWN), + BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_879, PCI_ANY_ID, PCI_ANY_ID, UNKNOWN), { } }; diff --git a/sound/pci/ca0106/ca0106.h b/sound/pci/ca0106/ca0106.h index a0420bc63f0..75da1746e75 100644 --- a/sound/pci/ca0106/ca0106.h +++ b/sound/pci/ca0106/ca0106.h @@ -1,7 +1,7 @@ /* * Copyright (c) 2004 James Courtier-Dutton <James@superbug.demon.co.uk> * Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit - * Version: 0.0.21 + * Version: 0.0.22 * * FEATURES currently supported: * See ca0106_main.c for features. @@ -47,6 +47,8 @@ * Added GPIO info for SB Live 24bit. * 0.0.21 * Implement support for Line-in capture on SB Live 24bit. + * 0.0.22 + * Add support for mute control on SB Live 24bit (cards w/ SPI DAC) * * * This code was initally based on code from ALSA's emu10k1x.c which is: @@ -552,6 +554,95 @@ #define CONTROL_CENTER_LFE_CHANNEL 1 #define CONTROL_UNKNOWN_CHANNEL 2 + +/* Based on WM8768 Datasheet Rev 4.2 page 32 */ +#define SPI_REG_MASK 0x1ff /* 16-bit SPI writes have a 7-bit address */ +#define SPI_REG_SHIFT 9 /* followed by 9 bits of data */ + +#define SPI_LDA1_REG 0 /* digital attenuation */ +#define SPI_RDA1_REG 1 +#define SPI_LDA2_REG 4 +#define SPI_RDA2_REG 5 +#define SPI_LDA3_REG 6 +#define SPI_RDA3_REG 7 +#define SPI_LDA4_REG 13 +#define SPI_RDA4_REG 14 +#define SPI_MASTDA_REG 8 + +#define SPI_DA_BIT_UPDATE (1<<8) /* update attenuation values */ +#define SPI_DA_BIT_0dB 0xff /* 0 dB */ +#define SPI_DA_BIT_infdB 0x00 /* inf dB attenuation (mute) */ + +#define SPI_PL_REG 2 +#define SPI_PL_BIT_L_M (0<<5) /* left channel = mute */ +#define SPI_PL_BIT_L_L (1<<5) /* left channel = left */ +#define SPI_PL_BIT_L_R (2<<5) /* left channel = right */ +#define SPI_PL_BIT_L_C (3<<5) /* left channel = (L+R)/2 */ +#define SPI_PL_BIT_R_M (0<<7) /* right channel = mute */ +#define SPI_PL_BIT_R_L (1<<7) /* right channel = left */ +#define SPI_PL_BIT_R_R (2<<7) /* right channel = right */ +#define SPI_PL_BIT_R_C (3<<7) /* right channel = (L+R)/2 */ +#define SPI_IZD_REG 2 +#define SPI_IZD_BIT (1<<4) /* infinite zero detect */ + +#define SPI_FMT_REG 3 +#define SPI_FMT_BIT_RJ (0<<0) /* right justified mode */ +#define SPI_FMT_BIT_LJ (1<<0) /* left justified mode */ +#define SPI_FMT_BIT_I2S (2<<0) /* I2S mode */ +#define SPI_FMT_BIT_DSP (3<<0) /* DSP Modes A or B */ +#define SPI_LRP_REG 3 +#define SPI_LRP_BIT (1<<2) /* invert LRCLK polarity */ +#define SPI_BCP_REG 3 +#define SPI_BCP_BIT (1<<3) /* invert BCLK polarity */ +#define SPI_IWL_REG 3 +#define SPI_IWL_BIT_16 (0<<4) /* 16-bit world length */ +#define SPI_IWL_BIT_20 (1<<4) /* 20-bit world length */ +#define SPI_IWL_BIT_24 (2<<4) /* 24-bit world length */ +#define SPI_IWL_BIT_32 (3<<4) /* 32-bit world length */ + +#define SPI_MS_REG 10 +#define SPI_MS_BIT (1<<5) /* master mode */ +#define SPI_RATE_REG 10 /* only applies in master mode */ +#define SPI_RATE_BIT_128 (0<<6) /* MCLK = LRCLK * 128 */ +#define SPI_RATE_BIT_192 (1<<6) +#define SPI_RATE_BIT_256 (2<<6) +#define SPI_RATE_BIT_384 (3<<6) +#define SPI_RATE_BIT_512 (4<<6) +#define SPI_RATE_BIT_768 (5<<6) + +/* They really do label the bit for the 4th channel "4" and not "3" */ +#define SPI_DMUTE0_REG 9 +#define SPI_DMUTE1_REG 9 +#define SPI_DMUTE2_REG 9 +#define SPI_DMUTE4_REG 15 +#define SPI_DMUTE0_BIT (1<<3) +#define SPI_DMUTE1_BIT (1<<4) +#define SPI_DMUTE2_BIT (1<<5) +#define SPI_DMUTE4_BIT (1<<2) + +#define SPI_PHASE0_REG 3 +#define SPI_PHASE1_REG 3 +#define SPI_PHASE2_REG 3 +#define SPI_PHASE4_REG 15 +#define SPI_PHASE0_BIT (1<<6) +#define SPI_PHASE1_BIT (1<<7) +#define SPI_PHASE2_BIT (1<<8) +#define SPI_PHASE4_BIT (1<<3) + +#define SPI_PDWN_REG 2 /* power down all DACs */ +#define SPI_PDWN_BIT (1<<2) +#define SPI_DACD0_REG 10 /* power down individual DACs */ +#define SPI_DACD1_REG 10 +#define SPI_DACD2_REG 10 +#define SPI_DACD4_REG 15 +#define SPI_DACD0_BIT (1<<1) +#define SPI_DACD1_BIT (1<<2) +#define SPI_DACD2_BIT (1<<3) +#define SPI_DACD4_BIT (1<<0) /* datasheet error says it's 1 */ + +#define SPI_PWRDNALL_REG 10 /* power down everything */ +#define SPI_PWRDNALL_BIT (1<<4) + #include "ca_midi.h" struct snd_ca0106; @@ -611,6 +702,8 @@ struct snd_ca0106 { struct snd_ca_midi midi; struct snd_ca_midi midi2; + + u16 spi_dac_reg[16]; }; int snd_ca0106_mixer(struct snd_ca0106 *emu); @@ -627,4 +720,5 @@ void snd_ca0106_ptr_write(struct snd_ca0106 *emu, int snd_ca0106_i2c_write(struct snd_ca0106 *emu, u32 reg, u32 value); - +int snd_ca0106_spi_write(struct snd_ca0106 * emu, + unsigned int data); diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index fcab8fb97e3..31d8db9f7a4 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -1,7 +1,7 @@ /* * Copyright (c) 2004 James Courtier-Dutton <James@superbug.demon.co.uk> * Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit - * Version: 0.0.23 + * Version: 0.0.25 * * FEATURES currently supported: * Front, Rear and Center/LFE. @@ -79,6 +79,10 @@ * Add support for MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97. From kiksen, bug #901 * 0.0.23 * Implement support for Line-in capture on SB Live 24bit. + * 0.0.24 + * Add support for mute control on SB Live 24bit (cards w/ SPI DAC) + * 0.0.25 + * Powerdown SPI DAC channels when not in use * * BUGS: * Some stability problems when unloading the snd-ca0106 kernel module. @@ -170,6 +174,15 @@ MODULE_PARM_DESC(subsystem, "Force card subsystem model."); static struct snd_ca0106_details ca0106_chip_details[] = { /* Sound Blaster X-Fi Extreme Audio. This does not have an AC97. 53SB079000000 */ /* It is really just a normal SB Live 24bit. */ + /* Tested: + * See ALSA bug#3251 + */ + { .serial = 0x10131102, + .name = "X-Fi Extreme Audio [SBxxxx]", + .gpio_type = 1, + .i2c_adc = 1 } , + /* Sound Blaster X-Fi Extreme Audio. This does not have an AC97. 53SB079000000 */ + /* It is really just a normal SB Live 24bit. */ /* * CTRL:CA0111-WTLF * ADC: WM8775SEDS @@ -261,10 +274,11 @@ static struct snd_ca0106_details ca0106_chip_details[] = { /* hardware definition */ static struct snd_pcm_hardware snd_ca0106_playback_hw = { - .info = (SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP_VALID), + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_SYNC_START, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, .rates = (SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000), @@ -447,6 +461,19 @@ static void snd_ca0106_pcm_free_substream(struct snd_pcm_runtime *runtime) kfree(runtime->private_data); } +static const int spi_dacd_reg[] = { + [PCM_FRONT_CHANNEL] = SPI_DACD4_REG, + [PCM_REAR_CHANNEL] = SPI_DACD0_REG, + [PCM_CENTER_LFE_CHANNEL]= SPI_DACD2_REG, + [PCM_UNKNOWN_CHANNEL] = SPI_DACD1_REG, +}; +static const int spi_dacd_bit[] = { + [PCM_FRONT_CHANNEL] = SPI_DACD4_BIT, + [PCM_REAR_CHANNEL] = SPI_DACD0_BIT, + [PCM_CENTER_LFE_CHANNEL]= SPI_DACD2_BIT, + [PCM_UNKNOWN_CHANNEL] = SPI_DACD1_BIT, +}; + /* open_playback callback */ static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substream, int channel_id) @@ -481,6 +508,17 @@ static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substr return err; if ((err = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64)) < 0) return err; + snd_pcm_set_sync(substream); + + if (chip->details->spi_dac && channel_id != PCM_FRONT_CHANNEL) { + const int reg = spi_dacd_reg[channel_id]; + + /* Power up dac */ + chip->spi_dac_reg[reg] &= ~spi_dacd_bit[channel_id]; + err = snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]); + if (err < 0) + return err; + } return 0; } @@ -491,6 +529,14 @@ static int snd_ca0106_pcm_close_playback(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; struct snd_ca0106_pcm *epcm = runtime->private_data; chip->playback_channels[epcm->channel_id].use = 0; + + if (chip->details->spi_dac && epcm->channel_id != PCM_FRONT_CHANNEL) { + const int reg = spi_dacd_reg[epcm->channel_id]; + + /* Power down DAC */ + chip->spi_dac_reg[reg] |= spi_dacd_bit[epcm->channel_id]; + snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]); + } /* FIXME: maybe zero others */ return 0; } @@ -809,6 +855,9 @@ static int snd_ca0106_pcm_trigger_playback(struct snd_pcm_substream *substream, break; } snd_pcm_group_for_each_entry(s, substream) { + if (snd_pcm_substream_chip(s) != emu || + s->stream != SNDRV_PCM_STREAM_PLAYBACK) + continue; runtime = s->runtime; epcm = runtime->private_data; channel = epcm->channel_id; @@ -1214,28 +1263,23 @@ static int __devinit snd_ca0106_pcm(struct snd_ca0106 *emu, int device, struct s return 0; } +#define SPI_REG(reg, value) (((reg) << SPI_REG_SHIFT) | (value)) static unsigned int spi_dac_init[] = { - 0x00ff, - 0x02ff, - 0x0400, - 0x0520, - 0x0620, /* Set 24 bit. Was 0x0600 */ - 0x08ff, - 0x0aff, - 0x0cff, - 0x0eff, - 0x10ff, - 0x1200, - 0x1400, - 0x1480, - 0x1800, - 0x1aff, - 0x1cff, - 0x1e00, - 0x0530, - 0x0602, - 0x0622, - 0x1400, + SPI_REG(SPI_LDA1_REG, SPI_DA_BIT_0dB), /* 0dB dig. attenuation */ + SPI_REG(SPI_RDA1_REG, SPI_DA_BIT_0dB), + SPI_REG(SPI_PL_REG, SPI_PL_BIT_L_L | SPI_PL_BIT_R_R | SPI_IZD_BIT), + SPI_REG(SPI_FMT_REG, SPI_FMT_BIT_I2S | SPI_IWL_BIT_24), + SPI_REG(SPI_LDA2_REG, SPI_DA_BIT_0dB), + SPI_REG(SPI_RDA2_REG, SPI_DA_BIT_0dB), + SPI_REG(SPI_LDA3_REG, SPI_DA_BIT_0dB), + SPI_REG(SPI_RDA3_REG, SPI_DA_BIT_0dB), + SPI_REG(SPI_MASTDA_REG, SPI_DA_BIT_0dB), + SPI_REG(9, 0x00), + SPI_REG(SPI_MS_REG, SPI_DACD0_BIT | SPI_DACD1_BIT | SPI_DACD2_BIT), + SPI_REG(12, 0x00), + SPI_REG(SPI_LDA4_REG, SPI_DA_BIT_0dB), + SPI_REG(SPI_RDA4_REG, SPI_DA_BIT_0dB | SPI_DA_BIT_UPDATE), + SPI_REG(SPI_DACD4_REG, 0x00), }; static unsigned int i2c_adc_init[][2] = { @@ -1475,8 +1519,13 @@ static int __devinit snd_ca0106_create(int dev, struct snd_card *card, int size, n; size = ARRAY_SIZE(spi_dac_init); - for (n=0; n < size; n++) + for (n = 0; n < size; n++) { + int reg = spi_dac_init[n] >> SPI_REG_SHIFT; + snd_ca0106_spi_write(chip, spi_dac_init[n]); + if (reg < ARRAY_SIZE(chip->spi_dac_reg)) + chip->spi_dac_reg[reg] = spi_dac_init[n]; + } } if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index 9c3a9c8d1dc..be519a17dfa 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c @@ -1,7 +1,7 @@ /* * Copyright (c) 2004 James Courtier-Dutton <James@superbug.demon.co.uk> * Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit - * Version: 0.0.17 + * Version: 0.0.18 * * FEATURES currently supported: * See ca0106_main.c for features. @@ -39,6 +39,8 @@ * Modified Copyright message. * 0.0.17 * Implement Mic and Line in Capture. + * 0.0.18 + * Add support for mute control on SB Live 24bit (cards w/ SPI DAC) * * This code was initally based on code from ALSA's emu10k1x.c which is: * Copyright (c) by Francisco Moraes <fmoraes@nc.rr.com> @@ -77,15 +79,7 @@ static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale1, -5175, 25, 1); static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale2, -10350, 50, 1); -static int snd_ca0106_shared_spdif_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_ca0106_shared_spdif_info snd_ctl_boolean_mono_info static int snd_ca0106_shared_spdif_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -470,6 +464,42 @@ static int snd_ca0106_i2c_volume_put(struct snd_kcontrol *kcontrol, return change; } +#define spi_mute_info snd_ctl_boolean_mono_info + +static int spi_mute_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); + unsigned int reg = kcontrol->private_value >> SPI_REG_SHIFT; + unsigned int bit = kcontrol->private_value & SPI_REG_MASK; + + ucontrol->value.integer.value[0] = !(emu->spi_dac_reg[reg] & bit); + return 0; +} + +static int spi_mute_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); + unsigned int reg = kcontrol->private_value >> SPI_REG_SHIFT; + unsigned int bit = kcontrol->private_value & SPI_REG_MASK; + int ret; + + ret = emu->spi_dac_reg[reg] & bit; + if (ucontrol->value.integer.value[0]) { + if (!ret) /* bit already cleared, do nothing */ + return 0; + emu->spi_dac_reg[reg] &= ~bit; + } else { + if (ret) /* bit already set, do nothing */ + return 0; + emu->spi_dac_reg[reg] |= bit; + } + + ret = snd_ca0106_spi_write(emu, emu->spi_dac_reg[reg]); + return ret ? -1 : 1; +} + #define CA_VOLUME(xname,chid,reg) \ { \ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ @@ -562,6 +592,28 @@ static struct snd_kcontrol_new snd_ca0106_volume_i2c_adc_ctls[] __devinitdata = I2C_VOLUME("Aux Capture Volume", 3), }; +#define SPI_SWITCH(xname,reg,bit) \ +{ \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ + .info = spi_mute_info, \ + .get = spi_mute_get, \ + .put = spi_mute_put, \ + .private_value = (reg<<SPI_REG_SHIFT) | (bit) \ +} + +static struct snd_kcontrol_new snd_ca0106_volume_spi_dac_ctls[] +__devinitdata = { + SPI_SWITCH("Analog Front Playback Switch", + SPI_DMUTE4_REG, SPI_DMUTE4_BIT), + SPI_SWITCH("Analog Rear Playback Switch", + SPI_DMUTE0_REG, SPI_DMUTE0_BIT), + SPI_SWITCH("Analog Center/LFE Playback Switch", + SPI_DMUTE2_REG, SPI_DMUTE2_BIT), + SPI_SWITCH("Analog Side Playback Switch", + SPI_DMUTE1_REG, SPI_DMUTE1_BIT), +}; + static int __devinit remove_ctl(struct snd_card *card, const char *name) { struct snd_ctl_elem_id id; @@ -591,9 +643,19 @@ static int __devinit rename_ctl(struct snd_card *card, const char *src, const ch return -ENOENT; } +#define ADD_CTLS(emu, ctls) \ + do { \ + int i, err; \ + for (i = 0; i < ARRAY_SIZE(ctls); i++) { \ + err = snd_ctl_add(card, snd_ctl_new1(&ctls[i], emu)); \ + if (err < 0) \ + return err; \ + } \ + } while (0) + int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu) { - int i, err; + int err; struct snd_card *card = emu->card; char **c; static char *ca0106_remove_ctls[] = { @@ -640,17 +702,9 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu) rename_ctl(card, c[0], c[1]); #endif - for (i = 0; i < ARRAY_SIZE(snd_ca0106_volume_ctls); i++) { - err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_volume_ctls[i], emu)); - if (err < 0) - return err; - } + ADD_CTLS(emu, snd_ca0106_volume_ctls); if (emu->details->i2c_adc == 1) { - for (i = 0; i < ARRAY_SIZE(snd_ca0106_volume_i2c_adc_ctls); i++) { - err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_volume_i2c_adc_ctls[i], emu)); - if (err < 0) - return err; - } + ADD_CTLS(emu, snd_ca0106_volume_i2c_adc_ctls); if (emu->details->gpio_type == 1) err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_capture_mic_line_in, emu)); else /* gpio_type == 2 */ @@ -658,6 +712,8 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu) if (err < 0) return err; } + if (emu->details->spi_dac == 1) + ADD_CTLS(emu, snd_ca0106_volume_spi_dac_ctls); return 0; } diff --git a/sound/pci/ca0106/ca_midi.c b/sound/pci/ca0106/ca_midi.c index 2e6eab1f118..ad32eff2713 100644 --- a/sound/pci/ca0106/ca_midi.c +++ b/sound/pci/ca0106/ca_midi.c @@ -6,7 +6,7 @@ * Changelog: * Implementation is based on mpu401 and emu10k1x and * tested with ca0106. - * mpu401: Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * mpu401: Copyright (c) by Jaroslav Kysela <perex@perex.cz> * emu10k1x: Copyright (c) by Francisco Moraes <fmoraes@nc.rr.com> * * This program is free software; you can redistribute it and/or modify diff --git a/sound/pci/ca0106/ca_midi.h b/sound/pci/ca0106/ca_midi.h index b72c0933bd2..922ed3e3731 100644 --- a/sound/pci/ca0106/ca_midi.h +++ b/sound/pci/ca0106/ca_midi.h @@ -22,9 +22,9 @@ * */ -#include<linux/spinlock.h> -#include<sound/rawmidi.h> -#include<sound/mpu401.h> +#include <linux/spinlock.h> +#include <sound/rawmidi.h> +#include <sound/mpu401.h> #define CA_MIDI_MODE_INPUT MPU401_MODE_INPUT #define CA_MIDI_MODE_OUTPUT MPU401_MODE_OUTPUT diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index 7d3c5ee0005..6832649879c 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c @@ -95,30 +95,34 @@ MODULE_PARM_DESC(joystick_port, "Joystick port address."); #define CM_CHADC0 0x00000001 /* ch0, 0:playback, 1:record */ #define CM_REG_FUNCTRL1 0x04 -#define CM_ASFC_MASK 0x0000E000 /* ADC sampling frequency */ -#define CM_ASFC_SHIFT 13 -#define CM_DSFC_MASK 0x00001C00 /* DAC sampling frequency */ -#define CM_DSFC_SHIFT 10 +#define CM_DSFC_MASK 0x0000E000 /* channel 1 (DAC?) sampling frequency */ +#define CM_DSFC_SHIFT 13 +#define CM_ASFC_MASK 0x00001C00 /* channel 0 (ADC?) sampling frequency */ +#define CM_ASFC_SHIFT 10 #define CM_SPDF_1 0x00000200 /* SPDIF IN/OUT at channel B */ #define CM_SPDF_0 0x00000100 /* SPDIF OUT only channel A */ -#define CM_SPDFLOOP 0x00000080 /* ext. SPDIIF/OUT -> IN loopback */ +#define CM_SPDFLOOP 0x00000080 /* ext. SPDIIF/IN -> OUT loopback */ #define CM_SPDO2DAC 0x00000040 /* SPDIF/OUT can be heard from internal DAC */ #define CM_INTRM 0x00000020 /* master control block (MCB) interrupt enabled */ #define CM_BREQ 0x00000010 /* bus master enabled */ #define CM_VOICE_EN 0x00000008 /* legacy voice (SB16,FM) */ -#define CM_UART_EN 0x00000004 /* UART */ -#define CM_JYSTK_EN 0x00000002 /* joy stick */ +#define CM_UART_EN 0x00000004 /* legacy UART */ +#define CM_JYSTK_EN 0x00000002 /* legacy joystick */ +#define CM_ZVPORT 0x00000001 /* ZVPORT */ #define CM_REG_CHFORMAT 0x08 #define CM_CHB3D5C 0x80000000 /* 5,6 channels */ +#define CM_FMOFFSET2 0x40000000 /* initial FM PCM offset 2 when Fmute=1 */ #define CM_CHB3D 0x20000000 /* 4 channels */ #define CM_CHIP_MASK1 0x1f000000 #define CM_CHIP_037 0x01000000 - -#define CM_SPDIF_SELECT1 0x00080000 /* for model <= 037 ? */ +#define CM_SETLAT48 0x00800000 /* set latency timer 48h */ +#define CM_EDGEIRQ 0x00400000 /* emulated edge trigger legacy IRQ */ +#define CM_SPD24SEL39 0x00200000 /* 24-bit spdif: model 039 */ #define CM_AC3EN1 0x00100000 /* enable AC3: model 037 */ +#define CM_SPDIF_SELECT1 0x00080000 /* for model <= 037 ? */ #define CM_SPD24SEL 0x00020000 /* 24bit spdif: model 037 */ /* #define CM_SPDIF_INVERSE 0x00010000 */ /* ??? */ @@ -128,35 +132,45 @@ MODULE_PARM_DESC(joystick_port, "Joystick port address."); #define CM_ADCBITLEN_14 0x00008000 #define CM_ADCBITLEN_13 0x0000C000 -#define CM_ADCDACLEN_MASK 0x00003000 +#define CM_ADCDACLEN_MASK 0x00003000 /* model 037 */ #define CM_ADCDACLEN_060 0x00000000 #define CM_ADCDACLEN_066 0x00001000 #define CM_ADCDACLEN_130 0x00002000 #define CM_ADCDACLEN_280 0x00003000 +#define CM_ADCDLEN_MASK 0x00003000 /* model 039 */ +#define CM_ADCDLEN_ORIGINAL 0x00000000 +#define CM_ADCDLEN_EXTRA 0x00001000 +#define CM_ADCDLEN_24K 0x00002000 +#define CM_ADCDLEN_WEIGHT 0x00003000 + #define CM_CH1_SRATE_176K 0x00000800 +#define CM_CH1_SRATE_96K 0x00000800 /* model 055? */ #define CM_CH1_SRATE_88K 0x00000400 #define CM_CH0_SRATE_176K 0x00000200 +#define CM_CH0_SRATE_96K 0x00000200 /* model 055? */ #define CM_CH0_SRATE_88K 0x00000100 #define CM_SPDIF_INVERSE2 0x00000080 /* model 055? */ +#define CM_DBLSPDS 0x00000040 /* double SPDIF sample rate 88.2/96 */ +#define CM_POLVALID 0x00000020 /* inverse SPDIF/IN valid bit */ +#define CM_SPDLOCKED 0x00000010 -#define CM_CH1FMT_MASK 0x0000000C +#define CM_CH1FMT_MASK 0x0000000C /* bit 3: 16 bits, bit 2: stereo */ #define CM_CH1FMT_SHIFT 2 -#define CM_CH0FMT_MASK 0x00000003 +#define CM_CH0FMT_MASK 0x00000003 /* bit 1: 16 bits, bit 0: stereo */ #define CM_CH0FMT_SHIFT 0 #define CM_REG_INT_HLDCLR 0x0C #define CM_CHIP_MASK2 0xff000000 +#define CM_CHIP_8768 0x20000000 +#define CM_CHIP_055 0x08000000 #define CM_CHIP_039 0x04000000 #define CM_CHIP_039_6CH 0x01000000 -#define CM_CHIP_055 0x08000000 -#define CM_CHIP_8768 0x20000000 +#define CM_UNKNOWN_INT_EN 0x00080000 /* ? */ #define CM_TDMA_INT_EN 0x00040000 #define CM_CH1_INT_EN 0x00020000 #define CM_CH0_INT_EN 0x00010000 -#define CM_INT_HOLD 0x00000002 -#define CM_INT_CLEAR 0x00000001 #define CM_REG_INT_STATUS 0x10 #define CM_INTR 0x80000000 @@ -175,12 +189,13 @@ MODULE_PARM_DESC(joystick_port, "Joystick port address."); #define CM_CHINT0 0x00000001 #define CM_REG_LEGACY_CTRL 0x14 -#define CM_NXCHG 0x80000000 /* h/w multi channels? */ +#define CM_NXCHG 0x80000000 /* don't map base reg dword->sample */ #define CM_VMPU_MASK 0x60000000 /* MPU401 i/o port address */ #define CM_VMPU_330 0x00000000 #define CM_VMPU_320 0x20000000 #define CM_VMPU_310 0x40000000 #define CM_VMPU_300 0x60000000 +#define CM_ENWR8237 0x10000000 /* enable bus master to write 8237 base reg */ #define CM_VSBSEL_MASK 0x0C000000 /* SB16 base address */ #define CM_VSBSEL_220 0x00000000 #define CM_VSBSEL_240 0x04000000 @@ -191,44 +206,74 @@ MODULE_PARM_DESC(joystick_port, "Joystick port address."); #define CM_FMSEL_3C8 0x01000000 #define CM_FMSEL_3E0 0x02000000 #define CM_FMSEL_3E8 0x03000000 -#define CM_ENSPDOUT 0x00800000 /* enable XPDIF/OUT to I/O interface */ -#define CM_SPDCOPYRHT 0x00400000 /* set copyright spdif in/out */ +#define CM_ENSPDOUT 0x00800000 /* enable XSPDIF/OUT to I/O interface */ +#define CM_SPDCOPYRHT 0x00400000 /* spdif in/out copyright bit */ #define CM_DAC2SPDO 0x00200000 /* enable wave+fm_midi -> SPDIF/OUT */ -#define CM_SETRETRY 0x00010000 /* 0: legacy i/o wait (default), 1: legacy i/o bus retry */ +#define CM_INVIDWEN 0x00100000 /* internal vendor ID write enable, model 039? */ +#define CM_SETRETRY 0x00100000 /* 0: legacy i/o wait (default), 1: legacy i/o bus retry */ +#define CM_C_EEACCESS 0x00080000 /* direct programming eeprom regs */ +#define CM_C_EECS 0x00040000 +#define CM_C_EEDI46 0x00020000 +#define CM_C_EECK46 0x00010000 #define CM_CHB3D6C 0x00008000 /* 5.1 channels support */ -#define CM_LINE_AS_BASS 0x00006000 /* use line-in as bass */ +#define CM_CENTR2LIN 0x00004000 /* line-in as center out */ +#define CM_BASE2LIN 0x00002000 /* line-in as bass out */ +#define CM_EXBASEN 0x00001000 /* external bass input enable */ #define CM_REG_MISC_CTRL 0x18 -#define CM_PWD 0x80000000 +#define CM_PWD 0x80000000 /* power down */ #define CM_RESET 0x40000000 -#define CM_SFIL_MASK 0x30000000 -#define CM_TXVX 0x08000000 -#define CM_N4SPK3D 0x04000000 /* 4ch output */ +#define CM_SFIL_MASK 0x30000000 /* filter control at front end DAC, model 037? */ +#define CM_VMGAIN 0x10000000 /* analog master amp +6dB, model 039? */ +#define CM_TXVX 0x08000000 /* model 037? */ +#define CM_N4SPK3D 0x04000000 /* copy front to rear */ #define CM_SPDO5V 0x02000000 /* 5V spdif output (1 = 0.5v (coax)) */ #define CM_SPDIF48K 0x01000000 /* write */ #define CM_SPATUS48K 0x01000000 /* read */ -#define CM_ENDBDAC 0x00800000 /* enable dual dac */ +#define CM_ENDBDAC 0x00800000 /* enable double dac */ #define CM_XCHGDAC 0x00400000 /* 0: front=ch0, 1: front=ch1 */ #define CM_SPD32SEL 0x00200000 /* 0: 16bit SPDIF, 1: 32bit */ -#define CM_SPDFLOOPI 0x00100000 /* int. SPDIF-IN -> int. OUT */ -#define CM_FM_EN 0x00080000 /* enalbe FM */ +#define CM_SPDFLOOPI 0x00100000 /* int. SPDIF-OUT -> int. IN */ +#define CM_FM_EN 0x00080000 /* enable legacy FM */ #define CM_AC3EN2 0x00040000 /* enable AC3: model 039 */ -#define CM_VIDWPDSB 0x00010000 +#define CM_ENWRASID 0x00010000 /* choose writable internal SUBID (audio) */ +#define CM_VIDWPDSB 0x00010000 /* model 037? */ #define CM_SPDF_AC97 0x00008000 /* 0: SPDIF/OUT 44.1K, 1: 48K */ -#define CM_MASK_EN 0x00004000 -#define CM_VIDWPPRT 0x00002000 -#define CM_SFILENB 0x00001000 -#define CM_MMODE_MASK 0x00000E00 +#define CM_MASK_EN 0x00004000 /* activate channel mask on legacy DMA */ +#define CM_ENWRMSID 0x00002000 /* choose writable internal SUBID (modem) */ +#define CM_VIDWPPRT 0x00002000 /* model 037? */ +#define CM_SFILENB 0x00001000 /* filter stepping at front end DAC, model 037? */ +#define CM_MMODE_MASK 0x00000E00 /* model DAA interface mode */ #define CM_SPDIF_SELECT2 0x00000100 /* for model > 039 ? */ #define CM_ENCENTER 0x00000080 -#define CM_FLINKON 0x00000040 -#define CM_FLINKOFF 0x00000020 -#define CM_MIDSMP 0x00000010 -#define CM_UPDDMA_MASK 0x0000000C -#define CM_TWAIT_MASK 0x00000003 +#define CM_FLINKON 0x00000080 /* force modem link detection on, model 037 */ +#define CM_MUTECH1 0x00000040 /* mute PCI ch1 to DAC */ +#define CM_FLINKOFF 0x00000040 /* force modem link detection off, model 037 */ +#define CM_UNKNOWN_18_5 0x00000020 /* ? */ +#define CM_MIDSMP 0x00000010 /* 1/2 interpolation at front end DAC */ +#define CM_UPDDMA_MASK 0x0000000C /* TDMA position update notification */ +#define CM_UPDDMA_2048 0x00000000 +#define CM_UPDDMA_1024 0x00000004 +#define CM_UPDDMA_512 0x00000008 +#define CM_UPDDMA_256 0x0000000C +#define CM_TWAIT_MASK 0x00000003 /* model 037 */ +#define CM_TWAIT1 0x00000002 /* FM i/o cycle, 0: 48, 1: 64 PCICLKs */ +#define CM_TWAIT0 0x00000001 /* i/o cycle, 0: 4, 1: 6 PCICLKs */ + +#define CM_REG_TDMA_POSITION 0x1C +#define CM_TDMA_CNT_MASK 0xFFFF0000 /* current byte/word count */ +#define CM_TDMA_ADR_MASK 0x0000FFFF /* current address */ /* byte */ #define CM_REG_MIXER0 0x20 +#define CM_REG_SBVR 0x20 /* write: sb16 version */ +#define CM_REG_DEV 0x20 /* read: hardware device version */ + +#define CM_REG_MIXER21 0x21 +#define CM_UNKNOWN_21_MASK 0x78 /* ? */ +#define CM_X_ADPCM 0x04 /* SB16 ADPCM enable */ +#define CM_PROINV 0x02 /* SBPro left/right channel switching */ +#define CM_X_SB16 0x01 /* SB16 compatible */ #define CM_REG_SB16_DATA 0x22 #define CM_REG_SB16_ADDR 0x23 @@ -243,8 +288,8 @@ MODULE_PARM_DESC(joystick_port, "Joystick port address."); #define CM_FMMUTE_SHIFT 7 #define CM_WSMUTE 0x40 /* mute PCM */ #define CM_WSMUTE_SHIFT 6 -#define CM_SPK4 0x20 /* lin-in -> rear line out */ -#define CM_SPK4_SHIFT 5 +#define CM_REAR2LIN 0x20 /* lin-in -> rear line out */ +#define CM_REAR2LIN_SHIFT 5 #define CM_REAR2FRONT 0x10 /* exchange rear/front */ #define CM_REAR2FRONT_SHIFT 4 #define CM_WAVEINL 0x08 /* digital wave rec. left chan */ @@ -276,12 +321,13 @@ MODULE_PARM_DESC(joystick_port, "Joystick port address."); #define CM_VAUXR_MASK 0x0f #define CM_REG_MISC 0x27 +#define CM_UNKNOWN_27_MASK 0xd8 /* ? */ #define CM_XGPO1 0x20 // #define CM_XGPBIO 0x04 #define CM_MIC_CENTER_LFE 0x04 /* mic as center/lfe out? (model 039 or later?) */ #define CM_SPDIF_INVERSE 0x04 /* spdif input phase inverse (model 037) */ #define CM_SPDVALID 0x02 /* spdif input valid check */ -#define CM_DMAUTO 0x01 +#define CM_DMAUTO 0x01 /* SB16 DMA auto detect */ #define CM_REG_AC97 0x28 /* hmmm.. do we have ac97 link? */ /* @@ -322,18 +368,20 @@ MODULE_PARM_DESC(joystick_port, "Joystick port address."); /* * extended registers */ -#define CM_REG_CH0_FRAME1 0x80 /* base address */ -#define CM_REG_CH0_FRAME2 0x84 +#define CM_REG_CH0_FRAME1 0x80 /* write: base address */ +#define CM_REG_CH0_FRAME2 0x84 /* read: current address */ #define CM_REG_CH1_FRAME1 0x88 /* 0-15: count of samples at bus master; buffer size */ #define CM_REG_CH1_FRAME2 0x8C /* 16-31: count of samples at codec; fragment size */ + #define CM_REG_EXT_MISC 0x90 -#define CM_REG_MISC_CTRL_8768 0x92 /* reg. name the same as 0x18 */ -#define CM_CHB3D8C 0x20 /* 7.1 channels support */ -#define CM_SPD32FMT 0x10 /* SPDIF/IN 32k */ -#define CM_ADC2SPDIF 0x08 /* ADC output to SPDIF/OUT */ -#define CM_SHAREADC 0x04 /* DAC in ADC as Center/LFE */ -#define CM_REALTCMP 0x02 /* monitor the CMPL/CMPR of ADC */ -#define CM_INVLRCK 0x01 /* invert ZVPORT's LRCK */ +#define CM_ADC48K44K 0x10000000 /* ADC parameters group, 0: 44k, 1: 48k */ +#define CM_CHB3D8C 0x00200000 /* 7.1 channels support */ +#define CM_SPD32FMT 0x00100000 /* SPDIF/IN 32k sample rate */ +#define CM_ADC2SPDIF 0x00080000 /* ADC output to SPDIF/OUT */ +#define CM_SHAREADC 0x00040000 /* DAC in ADC as Center/LFE */ +#define CM_REALTCMP 0x00020000 /* monitor the CMPL/CMPR of ADC */ +#define CM_INVLRCK 0x00010000 /* invert ZVPORT's LRCK */ +#define CM_UNKNOWN_90_MASK 0x0000FFFF /* ? */ /* * size of i/o region @@ -383,15 +431,14 @@ MODULE_PARM_DESC(joystick_port, "Joystick port address."); struct cmipci_pcm { struct snd_pcm_substream *substream; - int running; /* dac/adc running? */ + u8 running; /* dac/adc running? */ + u8 fmt; /* format bits */ + u8 is_dac; + u8 needs_silencing; unsigned int dma_size; /* in frames */ - unsigned int period_size; /* in frames */ + unsigned int shift; + unsigned int ch; /* channel (0/1) */ unsigned int offset; /* physical address of the buffer */ - unsigned int fmt; /* format bits */ - int ch; /* channel (0/1) */ - unsigned int is_dac; /* is dac? */ - int bytes_per_frame; - int shift; }; /* mixer elements toggled/resumed during ac3 playback */ @@ -424,7 +471,6 @@ struct cmipci { int chip_version; int max_channels; - unsigned int has_dual_dac: 1; unsigned int can_ac3_sw: 1; unsigned int can_ac3_hw: 1; unsigned int can_multi_ch: 1; @@ -557,6 +603,9 @@ static unsigned int rates[] = { 5512, 11025, 22050, 44100, 8000, 16000, 32000, 4 static unsigned int snd_cmipci_rate_freq(unsigned int rate) { unsigned int i; + + if (rate > 48000) + rate /= 2; for (i = 0; i < ARRAY_SIZE(rates); i++) { if (rates[i] == rate) return i; @@ -671,19 +720,19 @@ static int snd_cmipci_hw_free(struct snd_pcm_substream *substream) /* */ -static unsigned int hw_channels[] = {1, 2, 4, 5, 6, 8}; +static unsigned int hw_channels[] = {1, 2, 4, 6, 8}; static struct snd_pcm_hw_constraint_list hw_constraints_channels_4 = { .count = 3, .list = hw_channels, .mask = 0, }; static struct snd_pcm_hw_constraint_list hw_constraints_channels_6 = { - .count = 5, + .count = 4, .list = hw_channels, .mask = 0, }; static struct snd_pcm_hw_constraint_list hw_constraints_channels_8 = { - .count = 6, + .count = 5, .list = hw_channels, .mask = 0, }; @@ -691,48 +740,37 @@ static struct snd_pcm_hw_constraint_list hw_constraints_channels_8 = { static int set_dac_channels(struct cmipci *cm, struct cmipci_pcm *rec, int channels) { if (channels > 2) { - if (! cm->can_multi_ch) + if (!cm->can_multi_ch || !rec->ch) return -EINVAL; if (rec->fmt != 0x03) /* stereo 16bit only */ return -EINVAL; + } + if (cm->can_multi_ch) { spin_lock_irq(&cm->reg_lock); - snd_cmipci_set_bit(cm, CM_REG_LEGACY_CTRL, CM_NXCHG); - snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL, CM_XCHGDAC); - if (channels > 4) { - snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_CHB3D); - snd_cmipci_set_bit(cm, CM_REG_CHFORMAT, CM_CHB3D5C); + if (channels > 2) { + snd_cmipci_set_bit(cm, CM_REG_LEGACY_CTRL, CM_NXCHG); + snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL, CM_XCHGDAC); } else { - snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_CHB3D5C); - snd_cmipci_set_bit(cm, CM_REG_CHFORMAT, CM_CHB3D); + snd_cmipci_clear_bit(cm, CM_REG_LEGACY_CTRL, CM_NXCHG); + snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_XCHGDAC); } - if (channels >= 6) { + if (channels == 8) + snd_cmipci_set_bit(cm, CM_REG_EXT_MISC, CM_CHB3D8C); + else + snd_cmipci_clear_bit(cm, CM_REG_EXT_MISC, CM_CHB3D8C); + if (channels == 6) { + snd_cmipci_set_bit(cm, CM_REG_CHFORMAT, CM_CHB3D5C); snd_cmipci_set_bit(cm, CM_REG_LEGACY_CTRL, CM_CHB3D6C); - snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL, CM_ENCENTER); } else { - snd_cmipci_clear_bit(cm, CM_REG_LEGACY_CTRL, CM_CHB3D6C); - snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_ENCENTER); - } - if (cm->chip_version == 68) { - if (channels == 8) { - snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL_8768, CM_CHB3D8C); - } else { - snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL_8768, CM_CHB3D8C); - } - } - spin_unlock_irq(&cm->reg_lock); - - } else { - if (cm->can_multi_ch) { - spin_lock_irq(&cm->reg_lock); - snd_cmipci_clear_bit(cm, CM_REG_LEGACY_CTRL, CM_NXCHG); - snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_CHB3D); snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_CHB3D5C); snd_cmipci_clear_bit(cm, CM_REG_LEGACY_CTRL, CM_CHB3D6C); - snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_ENCENTER); - snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_XCHGDAC); - spin_unlock_irq(&cm->reg_lock); } + if (channels == 4) + snd_cmipci_set_bit(cm, CM_REG_CHFORMAT, CM_CHB3D); + else + snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_CHB3D); + spin_unlock_irq(&cm->reg_lock); } return 0; } @@ -746,6 +784,7 @@ static int snd_cmipci_pcm_prepare(struct cmipci *cm, struct cmipci_pcm *rec, struct snd_pcm_substream *substream) { unsigned int reg, freq, val; + unsigned int period_size; struct snd_pcm_runtime *runtime = substream->runtime; rec->fmt = 0; @@ -765,11 +804,11 @@ static int snd_cmipci_pcm_prepare(struct cmipci *cm, struct cmipci_pcm *rec, rec->offset = runtime->dma_addr; /* buffer and period sizes in frame */ rec->dma_size = runtime->buffer_size << rec->shift; - rec->period_size = runtime->period_size << rec->shift; + period_size = runtime->period_size << rec->shift; if (runtime->channels > 2) { /* multi-channels */ rec->dma_size = (rec->dma_size * runtime->channels) / 2; - rec->period_size = (rec->period_size * runtime->channels) / 2; + period_size = (period_size * runtime->channels) / 2; } spin_lock_irq(&cm->reg_lock); @@ -780,7 +819,7 @@ static int snd_cmipci_pcm_prepare(struct cmipci *cm, struct cmipci_pcm *rec, /* program sample counts */ reg = rec->ch ? CM_REG_CH1_FRAME2 : CM_REG_CH0_FRAME2; snd_cmipci_write_w(cm, reg, rec->dma_size - 1); - snd_cmipci_write_w(cm, reg + 2, rec->period_size - 1); + snd_cmipci_write_w(cm, reg + 2, period_size - 1); /* set adc/dac flag */ val = rec->ch ? CM_CHADC1 : CM_CHADC0; @@ -795,11 +834,11 @@ static int snd_cmipci_pcm_prepare(struct cmipci *cm, struct cmipci_pcm *rec, freq = snd_cmipci_rate_freq(runtime->rate); val = snd_cmipci_read(cm, CM_REG_FUNCTRL1); if (rec->ch) { - val &= ~CM_ASFC_MASK; - val |= (freq << CM_ASFC_SHIFT) & CM_ASFC_MASK; - } else { val &= ~CM_DSFC_MASK; val |= (freq << CM_DSFC_SHIFT) & CM_DSFC_MASK; + } else { + val &= ~CM_ASFC_MASK; + val |= (freq << CM_ASFC_SHIFT) & CM_ASFC_MASK; } snd_cmipci_write(cm, CM_REG_FUNCTRL1, val); //snd_printd("cmipci: functrl1 = %08x\n", val); @@ -813,6 +852,16 @@ static int snd_cmipci_pcm_prepare(struct cmipci *cm, struct cmipci_pcm *rec, val &= ~CM_CH0FMT_MASK; val |= rec->fmt << CM_CH0FMT_SHIFT; } + if (cm->chip_version == 68) { + if (runtime->rate == 88200) + val |= CM_CH0_SRATE_88K << (rec->ch * 2); + else + val &= ~(CM_CH0_SRATE_88K << (rec->ch * 2)); + if (runtime->rate == 96000) + val |= CM_CH0_SRATE_96K << (rec->ch * 2); + else + val &= ~(CM_CH0_SRATE_96K << (rec->ch * 2)); + } snd_cmipci_write(cm, CM_REG_CHFORMAT, val); //snd_printd("cmipci: chformat = %08x\n", val); @@ -826,7 +875,7 @@ static int snd_cmipci_pcm_prepare(struct cmipci *cm, struct cmipci_pcm *rec, * PCM trigger/stop */ static int snd_cmipci_pcm_trigger(struct cmipci *cm, struct cmipci_pcm *rec, - struct snd_pcm_substream *substream, int cmd) + int cmd) { unsigned int inthld, chen, reset, pause; int result = 0; @@ -855,6 +904,7 @@ static int snd_cmipci_pcm_trigger(struct cmipci *cm, struct cmipci_pcm *rec, cm->ctrl &= ~chen; snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl | reset); snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl & ~reset); + rec->needs_silencing = rec->is_dac; break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_SUSPEND: @@ -906,7 +956,7 @@ static int snd_cmipci_playback_trigger(struct snd_pcm_substream *substream, int cmd) { struct cmipci *cm = snd_pcm_substream_chip(substream); - return snd_cmipci_pcm_trigger(cm, &cm->channel[CM_CH_PLAY], substream, cmd); + return snd_cmipci_pcm_trigger(cm, &cm->channel[CM_CH_PLAY], cmd); } static snd_pcm_uframes_t snd_cmipci_playback_pointer(struct snd_pcm_substream *substream) @@ -925,7 +975,7 @@ static int snd_cmipci_capture_trigger(struct snd_pcm_substream *substream, int cmd) { struct cmipci *cm = snd_pcm_substream_chip(substream); - return snd_cmipci_pcm_trigger(cm, &cm->channel[CM_CH_CAPT], substream, cmd); + return snd_cmipci_pcm_trigger(cm, &cm->channel[CM_CH_CAPT], cmd); } static snd_pcm_uframes_t snd_cmipci_capture_pointer(struct snd_pcm_substream *substream) @@ -1199,15 +1249,19 @@ static int setup_spdif_playback(struct cmipci *cm, struct snd_pcm_substream *sub snd_cmipci_set_bit(cm, CM_REG_FUNCTRL1, CM_PLAYBACK_SPDF); setup_ac3(cm, subs, do_ac3, rate); - if (rate == 48000) + if (rate == 48000 || rate == 96000) snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL, CM_SPDIF48K | CM_SPDF_AC97); else snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_SPDIF48K | CM_SPDF_AC97); - + if (rate > 48000) + snd_cmipci_set_bit(cm, CM_REG_CHFORMAT, CM_DBLSPDS); + else + snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_DBLSPDS); } else { /* they are controlled via "IEC958 Output Switch" */ /* snd_cmipci_clear_bit(cm, CM_REG_LEGACY_CTRL, CM_ENSPDOUT); */ /* snd_cmipci_clear_bit(cm, CM_REG_FUNCTRL1, CM_SPDO2DAC); */ + snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_DBLSPDS); snd_cmipci_clear_bit(cm, CM_REG_FUNCTRL1, CM_PLAYBACK_SPDF); setup_ac3(cm, subs, 0, 0); } @@ -1227,7 +1281,7 @@ static int snd_cmipci_playback_prepare(struct snd_pcm_substream *substream) int rate = substream->runtime->rate; int err, do_spdif, do_ac3 = 0; - do_spdif = ((rate == 44100 || rate == 48000) && + do_spdif = (rate >= 44100 && substream->runtime->format == SNDRV_PCM_FORMAT_S16_LE && substream->runtime->channels == 2); if (do_spdif && cm->can_ac3_hw) @@ -1252,11 +1306,75 @@ static int snd_cmipci_playback_spdif_prepare(struct snd_pcm_substream *substream return snd_cmipci_pcm_prepare(cm, &cm->channel[CM_CH_PLAY], substream); } +/* + * Apparently, the samples last played on channel A stay in some buffer, even + * after the channel is reset, and get added to the data for the rear DACs when + * playing a multichannel stream on channel B. This is likely to generate + * wraparounds and thus distortions. + * To avoid this, we play at least one zero sample after the actual stream has + * stopped. + */ +static void snd_cmipci_silence_hack(struct cmipci *cm, struct cmipci_pcm *rec) +{ + struct snd_pcm_runtime *runtime = rec->substream->runtime; + unsigned int reg, val; + + if (rec->needs_silencing && runtime && runtime->dma_area) { + /* set up a small silence buffer */ + memset(runtime->dma_area, 0, PAGE_SIZE); + reg = rec->ch ? CM_REG_CH1_FRAME2 : CM_REG_CH0_FRAME2; + val = ((PAGE_SIZE / 4) - 1) | (((PAGE_SIZE / 4) / 2 - 1) << 16); + snd_cmipci_write(cm, reg, val); + + /* configure for 16 bits, 2 channels, 8 kHz */ + if (runtime->channels > 2) + set_dac_channels(cm, rec, 2); + spin_lock_irq(&cm->reg_lock); + val = snd_cmipci_read(cm, CM_REG_FUNCTRL1); + val &= ~(CM_ASFC_MASK << (rec->ch * 3)); + val |= (4 << CM_ASFC_SHIFT) << (rec->ch * 3); + snd_cmipci_write(cm, CM_REG_FUNCTRL1, val); + val = snd_cmipci_read(cm, CM_REG_CHFORMAT); + val &= ~(CM_CH0FMT_MASK << (rec->ch * 2)); + val |= (3 << CM_CH0FMT_SHIFT) << (rec->ch * 2); + if (cm->chip_version == 68) { + val &= ~(CM_CH0_SRATE_88K << (rec->ch * 2)); + val &= ~(CM_CH0_SRATE_96K << (rec->ch * 2)); + } + snd_cmipci_write(cm, CM_REG_CHFORMAT, val); + + /* start stream (we don't need interrupts) */ + cm->ctrl |= CM_CHEN0 << rec->ch; + snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl); + spin_unlock_irq(&cm->reg_lock); + + msleep(1); + + /* stop and reset stream */ + spin_lock_irq(&cm->reg_lock); + cm->ctrl &= ~(CM_CHEN0 << rec->ch); + val = CM_RST_CH0 << rec->ch; + snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl | val); + snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl & ~val); + spin_unlock_irq(&cm->reg_lock); + + rec->needs_silencing = 0; + } +} + static int snd_cmipci_playback_hw_free(struct snd_pcm_substream *substream) { struct cmipci *cm = snd_pcm_substream_chip(substream); setup_spdif_playback(cm, substream, 0, 0); restore_mixer_state(cm); + snd_cmipci_silence_hack(cm, &cm->channel[0]); + return snd_cmipci_hw_free(substream); +} + +static int snd_cmipci_playback2_hw_free(struct snd_pcm_substream *substream) +{ + struct cmipci *cm = snd_pcm_substream_chip(substream); + snd_cmipci_silence_hack(cm, &cm->channel[1]); return snd_cmipci_hw_free(substream); } @@ -1515,7 +1633,11 @@ static int snd_cmipci_playback_open(struct snd_pcm_substream *substream) if ((err = open_device_check(cm, CM_OPEN_PLAYBACK, substream)) < 0) return err; runtime->hw = snd_cmipci_playback; - runtime->hw.channels_max = cm->max_channels; + if (cm->chip_version == 68) { + runtime->hw.rates |= SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000; + runtime->hw.rate_max = 96000; + } snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x10000); cm->dig_pcm_status = cm->dig_status; return 0; @@ -1558,9 +1680,14 @@ static int snd_cmipci_playback2_open(struct snd_pcm_substream *substream) else if (cm->max_channels == 8) snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &hw_constraints_channels_8); } - snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x10000); } mutex_unlock(&cm->open_mutex); + if (cm->chip_version == 68) { + runtime->hw.rates |= SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000; + runtime->hw.rate_max = 96000; + } + snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x10000); return 0; } @@ -1574,8 +1701,15 @@ static int snd_cmipci_playback_spdif_open(struct snd_pcm_substream *substream) return err; if (cm->can_ac3_hw) { runtime->hw = snd_cmipci_playback_spdif; - if (cm->chip_version >= 37) + if (cm->chip_version >= 37) { runtime->hw.formats |= SNDRV_PCM_FMTBIT_S32_LE; + snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); + } + if (cm->chip_version == 68) { + runtime->hw.rates |= SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000; + runtime->hw.rate_max = 96000; + } } else { runtime->hw = snd_cmipci_playback_iec958_subframe; } @@ -1668,7 +1802,7 @@ static struct snd_pcm_ops snd_cmipci_playback2_ops = { .close = snd_cmipci_playback2_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_cmipci_playback2_hw_params, - .hw_free = snd_cmipci_hw_free, + .hw_free = snd_cmipci_playback2_hw_free, .prepare = snd_cmipci_capture_prepare, /* channel B */ .trigger = snd_cmipci_capture_trigger, /* channel B */ .pointer = snd_cmipci_capture_pointer, /* channel B */ @@ -2139,15 +2273,7 @@ struct cmipci_switch_args { */ }; -static int snd_cmipci_uswitch_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_cmipci_uswitch_info snd_ctl_boolean_mono_info static int _snd_cmipci_uswitch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol, @@ -2260,8 +2386,8 @@ DEFINE_SWITCH_ARG(exchange_dac, CM_REG_MISC_CTRL, CM_XCHGDAC, 0, 0, 0); /* rever DEFINE_SWITCH_ARG(exchange_dac, CM_REG_MISC_CTRL, CM_XCHGDAC, CM_XCHGDAC, 0, 0); #endif DEFINE_BIT_SWITCH_ARG(fourch, CM_REG_MISC_CTRL, CM_N4SPK3D, 0, 0); -// DEFINE_BIT_SWITCH_ARG(line_rear, CM_REG_MIXER1, CM_SPK4, 1, 0); -// DEFINE_BIT_SWITCH_ARG(line_bass, CM_REG_LEGACY_CTRL, CM_LINE_AS_BASS, 0, 0); +// DEFINE_BIT_SWITCH_ARG(line_rear, CM_REG_MIXER1, CM_REAR2LIN, 1, 0); +// DEFINE_BIT_SWITCH_ARG(line_bass, CM_REG_LEGACY_CTRL, CM_CENTR2LIN|CM_BASE2LIN, 0, 0); // DEFINE_BIT_SWITCH_ARG(joystick, CM_REG_FUNCTRL1, CM_JYSTK_EN, 0, 0); /* now module option */ DEFINE_SWITCH_ARG(modem, CM_REG_MISC_CTRL, CM_FLINKON|CM_FLINKOFF, CM_FLINKON, 0, 0); @@ -2331,11 +2457,11 @@ static inline unsigned int get_line_in_mode(struct cmipci *cm) unsigned int val; if (cm->chip_version >= 39) { val = snd_cmipci_read(cm, CM_REG_LEGACY_CTRL); - if (val & CM_LINE_AS_BASS) + if (val & (CM_CENTR2LIN | CM_BASE2LIN)) return 2; } val = snd_cmipci_read_b(cm, CM_REG_MIXER1); - if (val & CM_SPK4) + if (val & CM_REAR2LIN) return 1; return 0; } @@ -2359,13 +2485,13 @@ static int snd_cmipci_line_in_mode_put(struct snd_kcontrol *kcontrol, spin_lock_irq(&cm->reg_lock); if (ucontrol->value.enumerated.item[0] == 2) - change = snd_cmipci_set_bit(cm, CM_REG_LEGACY_CTRL, CM_LINE_AS_BASS); + change = snd_cmipci_set_bit(cm, CM_REG_LEGACY_CTRL, CM_CENTR2LIN | CM_BASE2LIN); else - change = snd_cmipci_clear_bit(cm, CM_REG_LEGACY_CTRL, CM_LINE_AS_BASS); + change = snd_cmipci_clear_bit(cm, CM_REG_LEGACY_CTRL, CM_CENTR2LIN | CM_BASE2LIN); if (ucontrol->value.enumerated.item[0] == 1) - change |= snd_cmipci_set_bit_b(cm, CM_REG_MIXER1, CM_SPK4); + change |= snd_cmipci_set_bit_b(cm, CM_REG_MIXER1, CM_REAR2LIN); else - change |= snd_cmipci_clear_bit_b(cm, CM_REG_MIXER1, CM_SPK4); + change |= snd_cmipci_clear_bit_b(cm, CM_REG_MIXER1, CM_REAR2LIN); spin_unlock_irq(&cm->reg_lock); return change; } @@ -2583,19 +2709,18 @@ static void snd_cmipci_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { struct cmipci *cm = entry->private_data; - int i; + int i, v; - snd_iprintf(buffer, "%s\n\n", cm->card->longname); - for (i = 0; i < 0x40; i++) { - int v = inb(cm->iobase + i); + snd_iprintf(buffer, "%s\n", cm->card->longname); + for (i = 0; i < 0x94; i++) { + if (i == 0x28) + i = 0x90; + v = inb(cm->iobase + i); if (i % 4 == 0) - snd_iprintf(buffer, "%02x: ", i); - snd_iprintf(buffer, "%02x", v); - if (i % 4 == 3) - snd_iprintf(buffer, "\n"); - else - snd_iprintf(buffer, " "); + snd_iprintf(buffer, "\n%02x:", i); + snd_iprintf(buffer, " %02x", v); } + snd_iprintf(buffer, "\n"); } static void __devinit snd_cmipci_proc_init(struct cmipci *cm) @@ -2633,46 +2758,40 @@ static void __devinit query_chip(struct cmipci *cm) if (! detect) { /* check reg 08h, bit 24-28 */ detect = snd_cmipci_read(cm, CM_REG_CHFORMAT) & CM_CHIP_MASK1; - if (! detect) { + switch (detect) { + case 0: cm->chip_version = 33; - cm->max_channels = 2; if (cm->do_soft_ac3) cm->can_ac3_sw = 1; else cm->can_ac3_hw = 1; - cm->has_dual_dac = 1; - } else { + break; + case CM_CHIP_037: cm->chip_version = 37; - cm->max_channels = 2; cm->can_ac3_hw = 1; - cm->has_dual_dac = 1; + break; + default: + cm->chip_version = 39; + cm->can_ac3_hw = 1; + break; } + cm->max_channels = 2; } else { - /* check reg 0Ch, bit 26 */ - if (detect & CM_CHIP_8768) { - cm->chip_version = 68; - cm->max_channels = 8; - cm->can_ac3_hw = 1; - cm->has_dual_dac = 1; - cm->can_multi_ch = 1; - } else if (detect & CM_CHIP_055) { - cm->chip_version = 55; - cm->max_channels = 6; - cm->can_ac3_hw = 1; - cm->has_dual_dac = 1; - cm->can_multi_ch = 1; - } else if (detect & CM_CHIP_039) { + if (detect & CM_CHIP_039) { cm->chip_version = 39; if (detect & CM_CHIP_039_6CH) /* 4 or 6 channels */ cm->max_channels = 6; else cm->max_channels = 4; - cm->can_ac3_hw = 1; - cm->has_dual_dac = 1; - cm->can_multi_ch = 1; + } else if (detect & CM_CHIP_8768) { + cm->chip_version = 68; + cm->max_channels = 8; } else { - printk(KERN_ERR "chip %x version not supported\n", detect); + cm->chip_version = 55; + cm->max_channels = 6; } + cm->can_ac3_hw = 1; + cm->can_multi_ch = 1; } } @@ -2782,10 +2901,14 @@ static int __devinit snd_cmipci_create_fm(struct cmipci *cm, long fm_port) if (!fm_port) goto disable_fm; - /* first try FM regs in PCI port range */ - iosynth = cm->iobase + CM_REG_FM_PCI; - err = snd_opl3_create(cm->card, iosynth, iosynth + 2, - OPL3_HW_OPL3, 1, &opl3); + if (cm->chip_version >= 39) { + /* first try FM regs in PCI port range */ + iosynth = cm->iobase + CM_REG_FM_PCI; + err = snd_opl3_create(cm->card, iosynth, iosynth + 2, + OPL3_HW_OPL3, 1, &opl3); + } else { + err = -EIO; + } if (err < 0) { /* then try legacy ports */ val = snd_cmipci_read(cm, CM_REG_LEGACY_CTRL) & ~CM_FMSEL_MASK; @@ -2829,9 +2952,10 @@ static int __devinit snd_cmipci_create(struct snd_card *card, struct pci_dev *pc static struct snd_device_ops ops = { .dev_free = snd_cmipci_dev_free, }; - unsigned int val = 0; + unsigned int val; long iomidi; - int integrated_midi; + int integrated_midi = 0; + char modelstr[16]; int pcm_index, pcm_spdif_index; static struct pci_device_id intel_82437vx[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437VX) }, @@ -2904,6 +3028,8 @@ static int __devinit snd_cmipci_create(struct snd_card *card, struct pci_dev *pc #endif /* initialize codec registers */ + snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL, CM_RESET); + snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_RESET); snd_cmipci_write(cm, CM_REG_INT_HLDCLR, 0); /* disable ints */ snd_cmipci_ch_reset(cm, CM_CH_PLAY); snd_cmipci_ch_reset(cm, CM_CH_CAPT); @@ -2917,6 +3043,10 @@ static int __devinit snd_cmipci_create(struct snd_card *card, struct pci_dev *pc #else snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_XCHGDAC); #endif + if (cm->chip_version) { + snd_cmipci_write_b(cm, CM_REG_EXT_MISC, 0x20); /* magic */ + snd_cmipci_write_b(cm, CM_REG_EXT_MISC + 1, 0x09); /* more magic */ + } /* Set Bus Master Request */ snd_cmipci_set_bit(cm, CM_REG_FUNCTRL1, CM_BREQ); @@ -2931,15 +3061,55 @@ static int __devinit snd_cmipci_create(struct snd_card *card, struct pci_dev *pc break; } + if (cm->chip_version < 68) { + val = pci->device < 0x110 ? 8338 : 8738; + } else { + switch (snd_cmipci_read_b(cm, CM_REG_INT_HLDCLR + 3) & 0x03) { + case 0: + val = 8769; + break; + case 2: + val = 8762; + break; + default: + switch ((pci->subsystem_vendor << 16) | + pci->subsystem_device) { + case 0x13f69761: + case 0x584d3741: + case 0x584d3751: + case 0x584d3761: + case 0x584d3771: + case 0x72848384: + val = 8770; + break; + default: + val = 8768; + break; + } + } + } + sprintf(card->shortname, "C-Media CMI%d", val); + if (cm->chip_version < 68) + sprintf(modelstr, " (model %d)", cm->chip_version); + else + modelstr[0] = '\0'; + sprintf(card->longname, "%s%s at %#lx, irq %i", + card->shortname, modelstr, cm->iobase, cm->irq); + if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, cm, &ops)) < 0) { snd_cmipci_free(cm); return err; } - integrated_midi = snd_cmipci_read_b(cm, CM_REG_MPU_PCI) != 0xff; - if (integrated_midi && mpu_port[dev] == 1) - iomidi = cm->iobase + CM_REG_MPU_PCI; - else { + if (cm->chip_version >= 39) { + val = snd_cmipci_read_b(cm, CM_REG_MPU_PCI + 1); + if (val != 0x00 && val != 0xff) { + iomidi = cm->iobase + CM_REG_MPU_PCI; + integrated_midi = 1; + } + } + if (!integrated_midi) { + val = 0; iomidi = mpu_port[dev]; switch (iomidi) { case 0x320: val = CM_VMPU_320; break; @@ -2953,11 +3123,21 @@ static int __devinit snd_cmipci_create(struct snd_card *card, struct pci_dev *pc snd_cmipci_write(cm, CM_REG_LEGACY_CTRL, val); /* enable UART */ snd_cmipci_set_bit(cm, CM_REG_FUNCTRL1, CM_UART_EN); + if (inb(iomidi + 1) == 0xff) { + snd_printk(KERN_ERR "cannot enable MPU-401 port" + " at %#lx\n", iomidi); + snd_cmipci_clear_bit(cm, CM_REG_FUNCTRL1, + CM_UART_EN); + iomidi = 0; + } } } - if ((err = snd_cmipci_create_fm(cm, fm_port[dev])) < 0) - return err; + if (cm->chip_version < 68) { + err = snd_cmipci_create_fm(cm, fm_port[dev]); + if (err < 0) + return err; + } /* reset mixer */ snd_cmipci_mixer_write(cm, 0, 0); @@ -2969,11 +3149,9 @@ static int __devinit snd_cmipci_create(struct snd_card *card, struct pci_dev *pc if ((err = snd_cmipci_pcm_new(cm, pcm_index)) < 0) return err; pcm_index++; - if (cm->has_dual_dac) { - if ((err = snd_cmipci_pcm2_new(cm, pcm_index)) < 0) - return err; - pcm_index++; - } + if ((err = snd_cmipci_pcm2_new(cm, pcm_index)) < 0) + return err; + pcm_index++; if (cm->can_ac3_hw || cm->can_ac3_sw) { pcm_spdif_index = pcm_index; if ((err = snd_cmipci_pcm_spdif_new(cm, pcm_index)) < 0) @@ -3057,15 +3235,6 @@ static int __devinit snd_cmipci_probe(struct pci_dev *pci, } card->private_data = cm; - sprintf(card->shortname, "C-Media PCI %s", card->driver); - sprintf(card->longname, "%s (model %d) at 0x%lx, irq %i", - card->shortname, - cm->chip_version, - cm->iobase, - cm->irq); - - //snd_printd("%s is detected\n", card->longname); - if ((err = snd_card_register(card)) < 0) { snd_card_free(card); return err; diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index 44cf5460764..9a55f4a9739 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c @@ -1,6 +1,6 @@ /* * Driver for Cirrus Logic CS4281 based PCI 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 @@ -38,7 +38,7 @@ #include <sound/initval.h> -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("Cirrus Logic CS4281"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Cirrus Logic,CS4281}}"); @@ -842,12 +842,11 @@ static snd_pcm_uframes_t snd_cs4281_pointer(struct snd_pcm_substream *substream) static struct snd_pcm_hardware snd_cs4281_playback = { - .info = (SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_RESUME | - SNDRV_PCM_INFO_SYNC_START), + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_RESUME, .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_BE | SNDRV_PCM_FMTBIT_S16_BE | @@ -868,12 +867,11 @@ static struct snd_pcm_hardware snd_cs4281_playback = static struct snd_pcm_hardware snd_cs4281_capture = { - .info = (SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_RESUME | - SNDRV_PCM_INFO_SYNC_START), + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_RESUME, .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_BE | SNDRV_PCM_FMTBIT_S16_BE | @@ -904,7 +902,6 @@ static int snd_cs4281_playback_open(struct snd_pcm_substream *substream) dma->right_slot = 1; runtime->private_data = dma; runtime->hw = snd_cs4281_playback; - snd_pcm_set_sync(substream); /* should be detected from the AC'97 layer, but it seems that although CS4297A rev B reports 18-bit ADC resolution, samples are 20-bit */ @@ -924,7 +921,6 @@ static int snd_cs4281_capture_open(struct snd_pcm_substream *substream) dma->right_slot = 11; runtime->private_data = dma; runtime->hw = snd_cs4281_capture; - snd_pcm_set_sync(substream); /* should be detected from the AC'97 layer, but it seems that although CS4297A rev B reports 18-bit ADC resolution, samples are 20-bit */ diff --git a/sound/pci/cs46xx/Makefile b/sound/pci/cs46xx/Makefile index d8b77b89aec..67e811ec853 100644 --- a/sound/pci/cs46xx/Makefile +++ b/sound/pci/cs46xx/Makefile @@ -1,12 +1,10 @@ # # Makefile for ALSA -# Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz> +# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz> # -snd-cs46xx-objs := cs46xx.o cs46xx_lib.o -ifeq ($(CONFIG_SND_CS46XX_NEW_DSP),y) - snd-cs46xx-objs += dsp_spos.o dsp_spos_scb_lib.o -endif +snd-cs46xx-y := cs46xx.o cs46xx_lib.o +snd-cs46xx-$(CONFIG_SND_CS46XX_NEW_DSP) += dsp_spos.o dsp_spos_scb_lib.o # Toplevel Module Dependency obj-$(CONFIG_SND_CS46XX) += snd-cs46xx.o diff --git a/sound/pci/cs46xx/cs46xx.c b/sound/pci/cs46xx/cs46xx.c index 8b6cd144d10..2699cb6c2cd 100644 --- a/sound/pci/cs46xx/cs46xx.c +++ b/sound/pci/cs46xx/cs46xx.c @@ -1,6 +1,6 @@ /* * The driver for the Cirrus Logic's Sound Fusion CS46XX based 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 @@ -34,7 +34,7 @@ #include <sound/cs46xx.h> #include <sound/initval.h> -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("Cirrus Logic Sound Fusion CS46XX"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Cirrus Logic,Sound Fusion (CS4280)}," diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index 71d7aab9d86..2c7bfc9fef6 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c @@ -1,5 +1,5 @@ /* - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * Abramo Bagnara <abramo@alsa-project.org> * Cirrus Logic, Inc. * Routines for control of Cirrus Logic CS461x chips @@ -1818,15 +1818,7 @@ static int snd_cs46xx_vol_iec958_put(struct snd_kcontrol *kcontrol, struct snd_c } #endif -static int snd_mixer_boolean_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_mixer_boolean_info snd_ctl_boolean_mono_info static int snd_cs46xx_iec958_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/pci/cs46xx/cs46xx_lib.h b/sound/pci/cs46xx/cs46xx_lib.h index 20dcd72f06c..018a7de5601 100644 --- a/sound/pci/cs46xx/cs46xx_lib.h +++ b/sound/pci/cs46xx/cs46xx_lib.h @@ -1,6 +1,6 @@ /* * The driver for the Cirrus Logic's Sound Fusion CS46XX based 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 diff --git a/sound/pci/cs46xx/dsp_spos.h b/sound/pci/cs46xx/dsp_spos.h index 0d246bca418..f9e169d33c0 100644 --- a/sound/pci/cs46xx/dsp_spos.h +++ b/sound/pci/cs46xx/dsp_spos.h @@ -1,6 +1,6 @@ /* * The driver for the Cirrus Logic's Sound Fusion CS46XX based 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 diff --git a/sound/pci/cs46xx/dsp_spos_scb_lib.c b/sound/pci/cs46xx/dsp_spos_scb_lib.c index 57e357de150..eded4dfeba1 100644 --- a/sound/pci/cs46xx/dsp_spos_scb_lib.c +++ b/sound/pci/cs46xx/dsp_spos_scb_lib.c @@ -1480,7 +1480,7 @@ void cs46xx_dsp_destroy_pcm_channel (struct snd_cs46xx * chip, if (!pcm_channel->src_scb->ref_count) { cs46xx_dsp_remove_scb(chip,pcm_channel->src_scb); - snd_assert (pcm_channel->src_slot >= 0 && pcm_channel->src_slot <= DSP_MAX_SRC_NR, + snd_assert (pcm_channel->src_slot >= 0 && pcm_channel->src_slot < DSP_MAX_SRC_NR, return ); ins->src_scb_slots[pcm_channel->src_slot] = 0; diff --git a/sound/pci/cs5535audio/Makefile b/sound/pci/cs5535audio/Makefile index ad947b4c04c..bb3d57e6a3c 100644 --- a/sound/pci/cs5535audio/Makefile +++ b/sound/pci/cs5535audio/Makefile @@ -2,11 +2,8 @@ # Makefile for cs5535audio # -snd-cs5535audio-objs := cs5535audio.o cs5535audio_pcm.o - -ifeq ($(CONFIG_PM),y) -snd-cs5535audio-objs += cs5535audio_pm.o -endif +snd-cs5535audio-y := cs5535audio.o cs5535audio_pcm.o +snd-cs5535audio-$(CONFIG_PM) += cs5535audio_pm.o # Toplevel Module Dependency obj-$(CONFIG_SND_CS5535AUDIO) += snd-cs5535audio.o diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c index b8e75ef9c1e..2b35889787b 100644 --- a/sound/pci/cs5535audio/cs5535audio.c +++ b/sound/pci/cs5535audio/cs5535audio.c @@ -206,7 +206,6 @@ static void process_bm1_irq(struct cs5535audio *cs5535au) static irqreturn_t snd_cs5535audio_interrupt(int irq, void *dev_id) { u16 acc_irq_stat; - u8 bm_stat; unsigned char count; struct cs5535audio *cs5535au = dev_id; @@ -217,7 +216,7 @@ static irqreturn_t snd_cs5535audio_interrupt(int irq, void *dev_id) if (!acc_irq_stat) return IRQ_NONE; - for (count = 0; count < 10; count++) { + for (count = 0; count < 4; count++) { if (acc_irq_stat & (1 << count)) { switch (count) { case IRQ_STS: @@ -232,26 +231,9 @@ static irqreturn_t snd_cs5535audio_interrupt(int irq, void *dev_id) case BM1_IRQ_STS: process_bm1_irq(cs5535au); break; - case BM2_IRQ_STS: - bm_stat = cs_readb(cs5535au, ACC_BM2_STATUS); - break; - case BM3_IRQ_STS: - bm_stat = cs_readb(cs5535au, ACC_BM3_STATUS); - break; - case BM4_IRQ_STS: - bm_stat = cs_readb(cs5535au, ACC_BM4_STATUS); - break; - case BM5_IRQ_STS: - bm_stat = cs_readb(cs5535au, ACC_BM5_STATUS); - break; - case BM6_IRQ_STS: - bm_stat = cs_readb(cs5535au, ACC_BM6_STATUS); - break; - case BM7_IRQ_STS: - bm_stat = cs_readb(cs5535au, ACC_BM7_STATUS); - break; default: - snd_printk(KERN_ERR "Unexpected irq src\n"); + snd_printk(KERN_ERR "Unexpected irq src: " + "0x%x\n", acc_irq_stat); break; } } diff --git a/sound/pci/cs5535audio/cs5535audio.h b/sound/pci/cs5535audio/cs5535audio.h index 4fd1f31a6cf..66bae766419 100644 --- a/sound/pci/cs5535audio/cs5535audio.h +++ b/sound/pci/cs5535audio/cs5535audio.h @@ -16,57 +16,28 @@ #define ACC_IRQ_STATUS 0x12 #define ACC_BM0_CMD 0x20 #define ACC_BM1_CMD 0x28 -#define ACC_BM2_CMD 0x30 -#define ACC_BM3_CMD 0x38 -#define ACC_BM4_CMD 0x40 -#define ACC_BM5_CMD 0x48 -#define ACC_BM6_CMD 0x50 -#define ACC_BM7_CMD 0x58 #define ACC_BM0_PRD 0x24 #define ACC_BM1_PRD 0x2C -#define ACC_BM2_PRD 0x34 -#define ACC_BM3_PRD 0x3C -#define ACC_BM4_PRD 0x44 -#define ACC_BM5_PRD 0x4C -#define ACC_BM6_PRD 0x54 -#define ACC_BM7_PRD 0x5C #define ACC_BM0_STATUS 0x21 #define ACC_BM1_STATUS 0x29 -#define ACC_BM2_STATUS 0x31 -#define ACC_BM3_STATUS 0x39 -#define ACC_BM4_STATUS 0x41 -#define ACC_BM5_STATUS 0x49 -#define ACC_BM6_STATUS 0x51 -#define ACC_BM7_STATUS 0x59 #define ACC_BM0_PNTR 0x60 #define ACC_BM1_PNTR 0x64 -#define ACC_BM2_PNTR 0x68 -#define ACC_BM3_PNTR 0x6C -#define ACC_BM4_PNTR 0x70 -#define ACC_BM5_PNTR 0x74 -#define ACC_BM6_PNTR 0x78 -#define ACC_BM7_PNTR 0x7C + /* acc_codec bar0 reg bits */ /* ACC_IRQ_STATUS */ #define IRQ_STS 0 #define WU_IRQ_STS 1 #define BM0_IRQ_STS 2 #define BM1_IRQ_STS 3 -#define BM2_IRQ_STS 4 -#define BM3_IRQ_STS 5 -#define BM4_IRQ_STS 6 -#define BM5_IRQ_STS 7 -#define BM6_IRQ_STS 8 -#define BM7_IRQ_STS 9 /* ACC_BMX_STATUS */ #define EOP (1<<0) #define BM_EOP_ERR (1<<1) /* ACC_BMX_CTL */ -#define BM_CTL_EN 0x00000001 -#define BM_CTL_PAUSE 0x00000011 -#define BM_CTL_DIS 0x00000000 -#define BM_CTL_BYTE_ORD_LE 0x00000000 -#define BM_CTL_BYTE_ORD_BE 0x00000100 +#define BM_CTL_EN 0x01 +#define BM_CTL_PAUSE 0x03 +#define BM_CTL_DIS 0x00 +#define BM_CTL_BYTE_ORD_LE 0x00 +#define BM_CTL_BYTE_ORD_BE 0x04 /* cs5535 specific ac97 codec register defines */ #define CMD_MASK 0xFF00FFFF #define CMD_NEW 0x00010000 @@ -106,7 +77,6 @@ struct cs5535audio_dma { struct snd_pcm_substream *substream; unsigned int buf_addr, buf_bytes; unsigned int period_bytes, periods; - int suspended; u32 saved_prd; }; diff --git a/sound/pci/cs5535audio/cs5535audio_pcm.c b/sound/pci/cs5535audio/cs5535audio_pcm.c index 5450a9e8f13..21df0634af3 100644 --- a/sound/pci/cs5535audio/cs5535audio_pcm.c +++ b/sound/pci/cs5535audio/cs5535audio_pcm.c @@ -43,7 +43,6 @@ static struct snd_pcm_hardware snd_cs5535audio_playback = SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_SYNC_START | SNDRV_PCM_INFO_RESUME ), .formats = ( @@ -71,8 +70,7 @@ static struct snd_pcm_hardware snd_cs5535audio_capture = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_SYNC_START + SNDRV_PCM_INFO_MMAP_VALID ), .formats = ( SNDRV_PCM_FMTBIT_S16_LE @@ -102,7 +100,6 @@ static int snd_cs5535audio_playback_open(struct snd_pcm_substream *substream) runtime->hw = snd_cs5535audio_playback; cs5535au->playback_substream = substream; runtime->private_data = &(cs5535au->dmas[CS5535AUDIO_DMA_PLAYBACK]); - snd_pcm_set_sync(substream); if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) return err; @@ -164,6 +161,7 @@ static int cs5535audio_build_dma_packets(struct cs5535audio *cs5535au, jmpprd_addr = cpu_to_le32(lastdesc->addr + (sizeof(struct cs5535audio_dma_desc)*periods)); + dma->substream = substream; dma->period_bytes = period_bytes; dma->periods = periods; spin_lock_irq(&cs5535au->reg_lock); @@ -241,6 +239,7 @@ static void cs5535audio_clear_dma_packets(struct cs5535audio *cs5535au, { snd_dma_free_pages(&dma->desc_buf); dma->desc_buf.area = NULL; + dma->substream = NULL; } static int snd_cs5535audio_hw_params(struct snd_pcm_substream *substream, @@ -298,14 +297,12 @@ static int snd_cs5535audio_trigger(struct snd_pcm_substream *substream, int cmd) break; case SNDRV_PCM_TRIGGER_RESUME: dma->ops->enable_dma(cs5535au); - dma->suspended = 0; break; case SNDRV_PCM_TRIGGER_STOP: dma->ops->disable_dma(cs5535au); break; case SNDRV_PCM_TRIGGER_SUSPEND: dma->ops->disable_dma(cs5535au); - dma->suspended = 1; break; default: snd_printk(KERN_ERR "unhandled trigger\n"); @@ -348,7 +345,6 @@ static int snd_cs5535audio_capture_open(struct snd_pcm_substream *substream) runtime->hw = snd_cs5535audio_capture; cs5535au->capture_substream = substream; runtime->private_data = &(cs5535au->dmas[CS5535AUDIO_DMA_CAPTURE]); - snd_pcm_set_sync(substream); if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) return err; diff --git a/sound/pci/cs5535audio/cs5535audio_pm.c b/sound/pci/cs5535audio/cs5535audio_pm.c index 3e4d198a450..838708f6d45 100644 --- a/sound/pci/cs5535audio/cs5535audio_pm.c +++ b/sound/pci/cs5535audio/cs5535audio_pm.c @@ -64,18 +64,21 @@ int snd_cs5535audio_suspend(struct pci_dev *pci, pm_message_t state) int i; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); + snd_pcm_suspend_all(cs5535au->pcm); + snd_ac97_suspend(cs5535au->ac97); for (i = 0; i < NUM_CS5535AUDIO_DMAS; i++) { struct cs5535audio_dma *dma = &cs5535au->dmas[i]; - if (dma && dma->substream && !dma->suspended) + if (dma && dma->substream) dma->saved_prd = dma->ops->read_prd(cs5535au); } - snd_pcm_suspend_all(cs5535au->pcm); - snd_ac97_suspend(cs5535au->ac97); /* save important regs, then disable aclink in hw */ snd_cs5535audio_stop_hardware(cs5535au); + if (pci_save_state(pci)) { + printk(KERN_ERR "cs5535audio: pci_save_state failed!\n"); + return -EIO; + } pci_disable_device(pci); - pci_save_state(pci); pci_set_power_state(pci, pci_choose_state(pci, state)); return 0; } @@ -89,7 +92,12 @@ int snd_cs5535audio_resume(struct pci_dev *pci) int i; pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); + if (pci_restore_state(pci) < 0) { + printk(KERN_ERR "cs5535audio: pci_restore_state failed, " + "disabling device\n"); + snd_card_disconnect(card); + return -EIO; + } if (pci_enable_device(pci) < 0) { printk(KERN_ERR "cs5535audio: pci_enable_device failed, " "disabling device\n"); @@ -112,17 +120,17 @@ int snd_cs5535audio_resume(struct pci_dev *pci) if (!timeout) snd_printk(KERN_ERR "Failure getting AC Link ready\n"); - /* we depend on ac97 to perform the codec power up */ - snd_ac97_resume(cs5535au->ac97); /* set up rate regs, dma. actual initiation is done in trig */ for (i = 0; i < NUM_CS5535AUDIO_DMAS; i++) { struct cs5535audio_dma *dma = &cs5535au->dmas[i]; - if (dma && dma->substream && dma->suspended) { + if (dma && dma->substream) { dma->substream->ops->prepare(dma->substream); dma->ops->setup_prd(cs5535au, dma->saved_prd); } } - + + /* we depend on ac97 to perform the codec power up */ + snd_ac97_resume(cs5535au->ac97); snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0; diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index f27b6a733b9..499ee1a5319 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c @@ -1595,15 +1595,7 @@ static struct snd_kcontrol_new snd_echo_clock_source_switch __devinitdata = { #ifdef ECHOCARD_HAS_PHANTOM_POWER /******************* Phantom power switch *******************/ -static int snd_echo_phantom_power_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_echo_phantom_power_info snd_ctl_boolean_mono_info static int snd_echo_phantom_power_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1646,15 +1638,7 @@ static struct snd_kcontrol_new snd_echo_phantom_power_switch __devinitdata = { #ifdef ECHOCARD_HAS_DIGITAL_IN_AUTOMUTE /******************* Digital input automute switch *******************/ -static int snd_echo_automute_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_echo_automute_info snd_ctl_boolean_mono_info static int snd_echo_automute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1695,18 +1679,7 @@ static struct snd_kcontrol_new snd_echo_automute_switch __devinitdata = { /******************* VU-meters switch *******************/ -static int snd_echo_vumeters_switch_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct echoaudio *chip; - - chip = snd_kcontrol_chip(kcontrol); - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_echo_vumeters_switch_info snd_ctl_boolean_mono_info static int snd_echo_vumeters_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/pci/echoaudio/echoaudio_dsp.c b/sound/pci/echoaudio/echoaudio_dsp.c index 42afa837d9b..e6c10077039 100644 --- a/sound/pci/echoaudio/echoaudio_dsp.c +++ b/sound/pci/echoaudio/echoaudio_dsp.c @@ -43,11 +43,11 @@ static int wait_handshake(struct echoaudio *chip) { int i; - /* Wait up to 10ms for the handshake from the DSP */ + /* Wait up to 20ms for the handshake from the DSP */ for (i = 0; i < HANDSHAKE_TIMEOUT; i++) { /* Look for the handshake value */ + barrier(); if (chip->comm_page->handshake) { - /*if (i) DE_ACT(("Handshake time: %d\n", i));*/ return 0; } udelay(1); diff --git a/sound/pci/echoaudio/echoaudio_dsp.h b/sound/pci/echoaudio/echoaudio_dsp.h index e55ee00991a..e352f3ae292 100644 --- a/sound/pci/echoaudio/echoaudio_dsp.h +++ b/sound/pci/echoaudio/echoaudio_dsp.h @@ -642,18 +642,18 @@ struct comm_page { /* Base Length*/ u32 flags; /* See Appendix A below 0x004 4 */ u32 unused; /* Unused entry 0x008 4 */ u32 sample_rate; /* Card sample rate in Hz 0x00c 4 */ - volatile u32 handshake; /* DSP command handshake 0x010 4 */ + u32 handshake; /* DSP command handshake 0x010 4 */ u32 cmd_start; /* Chs. to start mask 0x014 4 */ u32 cmd_stop; /* Chs. to stop mask 0x018 4 */ u32 cmd_reset; /* Chs. to reset mask 0x01c 4 */ u16 audio_format[DSP_MAXPIPES]; /* Chs. audio format 0x020 32*2 */ struct sg_entry sglist_addr[DSP_MAXPIPES]; /* Chs. Physical sglist addrs 0x060 32*8 */ - volatile u32 position[DSP_MAXPIPES]; + u32 position[DSP_MAXPIPES]; /* Positions for ea. ch. 0x160 32*4 */ - volatile s8 vu_meter[DSP_MAXPIPES]; + s8 vu_meter[DSP_MAXPIPES]; /* VU meters 0x1e0 32*1 */ - volatile s8 peak_meter[DSP_MAXPIPES]; + s8 peak_meter[DSP_MAXPIPES]; /* Peak meters 0x200 32*1 */ s8 line_out_level[DSP_MAXAUDIOOUTPUTS]; /* Output gain 0x220 16*1 */ @@ -665,7 +665,7 @@ struct comm_page { /* Base Length*/ /* Gina/Darla play filters - obsolete 0x3c0 168*4 */ u32 rec_coeff[MAX_REC_TAPS]; /* Gina/Darla record filters - obsolete 0x660 192*4 */ - volatile u16 midi_input[MIDI_IN_BUFFER_SIZE]; + u16 midi_input[MIDI_IN_BUFFER_SIZE]; /* MIDI input data transfer buffer 0x960 256*2 */ u8 gd_clock_state; /* Chg Gina/Darla clock state 0xb60 1 */ u8 gd_spdif_status; /* Chg. Gina/Darla S/PDIF state 0xb61 1 */ @@ -674,11 +674,10 @@ struct comm_page { /* Base Length*/ u32 nominal_level_mask; /* -10 level enable mask 0xb64 4 */ u16 input_clock; /* Chg. Input clock state 0xb68 2 */ u16 output_clock; /* Chg. Output clock state 0xb6a 2 */ - volatile u32 status_clocks; - /* Current Input clock state 0xb6c 4 */ + u32 status_clocks; /* Current Input clock state 0xb6c 4 */ u32 ext_box_status; /* External box status 0xb70 4 */ u32 cmd_add_buffer; /* Pipes to add (obsolete) 0xb74 4 */ - volatile u32 midi_out_free_count; + u32 midi_out_free_count; /* # of bytes free in MIDI output FIFO 0xb78 4 */ u32 unused2; /* Cyclic pipes 0xb7c 4 */ u32 control_register; diff --git a/sound/pci/emu10k1/Makefile b/sound/pci/emu10k1/Makefile index e521c38cef4..cf2d5636d8b 100644 --- a/sound/pci/emu10k1/Makefile +++ b/sound/pci/emu10k1/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-emu10k1-objs := emu10k1.o emu10k1_main.o \ diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c index 55caf341933..9680caff90c 100644 --- a/sound/pci/emu10k1/emu10k1.c +++ b/sound/pci/emu10k1/emu10k1.c @@ -1,6 +1,6 @@ /* * The driver for the EMU10K1 (SB Live!) based soundcards - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * * Copyright (c) by James Courtier-Dutton <James@superbug.demon.co.uk> * Added support for Audigy 2 Value. @@ -32,7 +32,7 @@ #include <sound/emu10k1.h> #include <sound/initval.h> -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("EMU10K1"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Creative Labs,SB Live!/PCI512/E-mu APS}," diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 404ae1be0a4..97c41d72a25 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * Creative Labs, Inc. * Routines for control of EMU10K1 chips * @@ -31,6 +31,8 @@ * */ +#include <linux/sched.h> +#include <linux/kthread.h> #include <sound/driver.h> #include <linux/delay.h> #include <linux/init.h> @@ -702,6 +704,65 @@ static int snd_emu1010_load_firmware(struct snd_emu10k1 * emu, const char * file return 0; } +int emu1010_firmware_thread(void *data) { + struct snd_emu10k1 * emu = data; + int tmp,tmp2; + int reg; + int err; + + for (;;) { + /* Delay to allow Audio Dock to settle */ + msleep(1000); + if (kthread_should_stop()) + break; + snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &tmp ); /* IRQ Status */ + snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ® ); /* OPTIONS: Which cards are attached to the EMU */ + if (reg & EMU_HANA_OPTION_DOCK_OFFLINE) { + /* Audio Dock attached */ + /* Return to Audio Dock programming mode */ + snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware\n"); + snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, EMU_HANA_FPGA_CONFIG_AUDIODOCK ); + if (emu->card_capabilities->emu1010 == 1) { + if ((err = snd_emu1010_load_firmware(emu, DOCK_FILENAME)) != 0) { + return err; + } + } else if (emu->card_capabilities->emu1010 == 2) { + if ((err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME)) != 0) { + return err; + } + } else if (emu->card_capabilities->emu1010 == 3) { + if ((err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME)) != 0) { + return err; + } + } + + snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0 ); + snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, ® ); + snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_IRQ_STATUS=0x%x\n",reg); + /* ID, should read & 0x7f = 0x55 when FPGA programmed. */ + snd_emu1010_fpga_read(emu, EMU_HANA_ID, ® ); + snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_ID=0x%x\n",reg); + if ((reg & 0x1f) != 0x15) { + /* FPGA failed to be programmed */ + snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware file failed, reg=0x%x\n", reg); + return 0; + return -ENODEV; + } + snd_printk(KERN_INFO "emu1010: Audio Dock Firmware loaded\n"); + snd_emu1010_fpga_read(emu, EMU_DOCK_MAJOR_REV, &tmp ); + snd_emu1010_fpga_read(emu, EMU_DOCK_MINOR_REV, &tmp2 ); + snd_printk("Audio Dock ver:%d.%d\n",tmp ,tmp2); + /* Sync clocking between 1010 and Dock */ + /* Allow DLL to settle */ + msleep(10); + /* Unmute all. Default is muted after a firmware load */ + snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); + break; + } + } + return 0; +} + /* * EMU-1010 - details found out from this driver, official MS Win drivers, * testing the card: @@ -817,8 +878,16 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu) snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ® ); snd_printk(KERN_INFO "emu1010: Card options=0x%x\n",reg); snd_emu1010_fpga_read(emu, EMU_HANA_OPTICAL_TYPE, &tmp ); - /* ADAT input. */ - snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, 0x01 ); + /* Optical -> ADAT I/O */ + /* 0 : SPDIF + * 1 : ADAT + */ + emu->emu1010.optical_in = 1; /* IN_ADAT */ + emu->emu1010.optical_out = 1; /* IN_ADAT */ + tmp = 0; + tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : 0) | + (emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : 0); + snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp ); snd_emu1010_fpga_read(emu, EMU_HANA_ADC_PADS, &tmp ); /* Set no attenuation on Audio Dock pads. */ snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, 0x00 ); @@ -1004,49 +1073,12 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu) snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &tmp ); snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, 0x10 ); /* SPDIF Format spdif (or 0x11 for aes/ebu) */ - /* Delay to allow Audio Dock to settle */ - msleep(100); - snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &tmp ); /* IRQ Status */ - snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ® ); /* OPTIONS: Which cards are attached to the EMU */ - /* FIXME: The loading of this should be able to happen any time, - * as the user can plug/unplug it at any time - */ - if (reg & (EMU_HANA_OPTION_DOCK_ONLINE | EMU_HANA_OPTION_DOCK_OFFLINE) ) { - /* Audio Dock attached */ - /* Return to Audio Dock programming mode */ - snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware\n"); - snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, EMU_HANA_FPGA_CONFIG_AUDIODOCK ); - if (emu->card_capabilities->emu1010 == 1) { - if ((err = snd_emu1010_load_firmware(emu, DOCK_FILENAME)) != 0) { - return err; - } - } else if (emu->card_capabilities->emu1010 == 2) { - if ((err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME)) != 0) { - return err; - } - } else if (emu->card_capabilities->emu1010 == 3) { - if ((err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME)) != 0) { - return err; - } - } + /* Start Micro/Audio Dock firmware loader thread */ + emu->emu1010.firmware_thread = kthread_create(&emu1010_firmware_thread, + emu, + "emu1010_firmware"); + wake_up_process(emu->emu1010.firmware_thread); - snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0 ); - snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, ® ); - snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_IRQ_STATUS=0x%x\n",reg); - /* ID, should read & 0x7f = 0x55 when FPGA programmed. */ - snd_emu1010_fpga_read(emu, EMU_HANA_ID, ® ); - snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_ID=0x%x\n",reg); - if ((reg & 0x3f) != 0x15) { - /* FPGA failed to be programmed */ - snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware file failed, reg=0x%x\n", reg); - return 0; - return -ENODEV; - } - snd_printk(KERN_INFO "emu1010: Audio Dock Firmware loaded\n"); - snd_emu1010_fpga_read(emu, EMU_DOCK_MAJOR_REV, &tmp ); - snd_emu1010_fpga_read(emu, EMU_DOCK_MINOR_REV, &tmp2 ); - snd_printk("Audio Dock ver:%d.%d\n",tmp ,tmp2); - } #if 0 snd_emu1010_fpga_link_dst_src_write(emu, EMU_DST_HAMOA_DAC_LEFT1, EMU_SRC_ALICE_EMU32B + 2); /* ALICE2 bus 0xa2 */ @@ -1132,7 +1164,7 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu) emu->emu1010.output_source[23] = 28; /* TEMP: Select SPDIF in/out */ - snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, 0x0); /* Output spdif */ + //snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, 0x0); /* Output spdif */ /* TEMP: Select 48kHz SPDIF out */ snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, 0x0); /* Mute all */ @@ -1173,6 +1205,7 @@ static int snd_emu10k1_free(struct snd_emu10k1 *emu) if (emu->card_capabilities->emu1010) { /* Disable 48Volt power to Audio Dock */ snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0 ); + kthread_stop(emu->emu1010.firmware_thread); } if (emu->memhdr) snd_util_memhdr_free(emu->memhdr); @@ -1722,8 +1755,9 @@ int __devinit snd_emu10k1_create(struct snd_card *card, goto error; } - emu->page_ptr_table = (void **)vmalloc(emu->max_cache_pages * sizeof(void*)); - emu->page_addr_table = (unsigned long*)vmalloc(emu->max_cache_pages * sizeof(unsigned long)); + emu->page_ptr_table = vmalloc(emu->max_cache_pages * sizeof(void *)); + emu->page_addr_table = vmalloc(emu->max_cache_pages * + sizeof(unsigned long)); if (emu->page_ptr_table == NULL || emu->page_addr_table == NULL) { err = -ENOMEM; goto error; diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index e4af7a9b808..1ec7ebaff9e 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c @@ -1062,14 +1062,7 @@ static int __devinit snd_emu10k1x_proc_init(struct emu10k1x * emu) return 0; } -static int snd_emu10k1x_shared_spdif_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_emu10k1x_shared_spdif_info snd_ctl_boolean_mono_info static int snd_emu10k1x_shared_spdif_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c index 7206c0fa06f..9bf1cd59219 100644 --- a/sound/pci/emu10k1/emufx.c +++ b/sound/pci/emu10k1/emufx.c @@ -1,5 +1,5 @@ /* - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * Creative Labs, Inc. * Routines for effect processor FX8010 * @@ -642,10 +642,8 @@ snd_emu10k1_look_for_ctl(struct snd_emu10k1 *emu, struct snd_ctl_elem_id *id) { struct snd_emu10k1_fx8010_ctl *ctl; struct snd_kcontrol *kcontrol; - struct list_head *list; - - list_for_each(list, &emu->fx8010.gpr_ctl) { - ctl = emu10k1_gpr_ctl(list); + + list_for_each_entry(ctl, &emu->fx8010.gpr_ctl, list) { kcontrol = ctl->kcontrol; if (kcontrol->id.iface == id->iface && !strcmp(kcontrol->id.name, id->name) && @@ -895,14 +893,12 @@ static int snd_emu10k1_list_controls(struct snd_emu10k1 *emu, struct snd_emu10k1_fx8010_control_gpr *gctl; struct snd_emu10k1_fx8010_ctl *ctl; struct snd_ctl_elem_id *id; - struct list_head *list; gctl = kmalloc(sizeof(*gctl), GFP_KERNEL); if (! gctl) return -ENOMEM; - list_for_each(list, &emu->fx8010.gpr_ctl) { - ctl = emu10k1_gpr_ctl(list); + list_for_each_entry(ctl, &emu->fx8010.gpr_ctl, list) { total++; if (icode->gpr_list_controls && i < icode->gpr_list_control_count) { @@ -1207,7 +1203,7 @@ static int __devinit _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu) A_OP(icode, &ptr, iMAC0, A_GPR(playback+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_FRONT)); snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Front Playback Volume", gpr, 100); gpr += 2; - + /* PCM Surround Playback (independent from stereo mix) */ A_OP(icode, &ptr, iMAC0, A_GPR(playback+2), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_REAR)); A_OP(icode, &ptr, iMAC0, A_GPR(playback+3), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_REAR)); @@ -1267,8 +1263,16 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) /* emu1212 DSP 0 and DSP 1 Capture */ if (emu->card_capabilities->emu1010) { - A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_GPR(capture+0), A_GPR(gpr), A_P16VIN(0x0)); - A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+1), A_P16VIN(0x1)); + if (emu->card_capabilities->ca0108_chip) { + /* Note:JCD:No longer bit shift lower 16bits to upper 16bits of 32bit value. */ + A_OP(icode, &ptr, iMACINT0, A_GPR(tmp), A_C_00000000, A3_EMU32IN(0x0), A_C_00000001); + A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_GPR(capture+0), A_GPR(gpr), A_GPR(tmp)); + A_OP(icode, &ptr, iMACINT0, A_GPR(tmp), A_C_00000000, A3_EMU32IN(0x1), A_C_00000001); + A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr), A_GPR(tmp)); + } else { + A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_GPR(capture+0), A_GPR(gpr), A_P16VIN(0x0)); + A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+1), A_P16VIN(0x1)); + } snd_emu10k1_init_stereo_control(&controls[nctl++], "EMU Capture Volume", gpr, 0); gpr += 2; } @@ -1516,7 +1520,11 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) /* EMU1010 Outputs from PCM Front, Rear, Center, LFE, Side */ snd_printk("EMU outputs on\n"); for (z = 0; z < 8; z++) { - A_OP(icode, &ptr, iACC3, A_EMU32OUTL(z), A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), A_C_00000000, A_C_00000000); + if (emu->card_capabilities->ca0108_chip) { + A_OP(icode, &ptr, iACC3, A3_EMU32OUT(z), A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), A_C_00000000, A_C_00000000); + } else { + A_OP(icode, &ptr, iACC3, A_EMU32OUTL(z), A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), A_C_00000000, A_C_00000000); + } } } @@ -1557,106 +1565,116 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) #endif if (emu->card_capabilities->emu1010) { - snd_printk("EMU inputs on\n"); - /* Capture 16 (originally 8) channels of S32_LE sound */ - - /* printk("emufx.c: gpr=0x%x, tmp=0x%x\n",gpr, tmp); */ - /* For the EMU1010: How to get 32bit values from the DSP. High 16bits into L, low 16bits into R. */ - /* A_P16VIN(0) is delayed by one sample, - * so all other A_P16VIN channels will need to also be delayed - */ - /* Left ADC in. 1 of 2 */ - snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_P16VIN(0x0), A_FXBUS2(0) ); - /* Right ADC in 1 of 2 */ - gpr_map[gpr++] = 0x00000000; - /* Delaying by one sample: instead of copying the input - * value A_P16VIN to output A_FXBUS2 as in the first channel, - * we use an auxiliary register, delaying the value by one - * sample - */ - snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(2) ); - A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x1), A_C_00000000, A_C_00000000); - gpr_map[gpr++] = 0x00000000; - snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(4) ); - A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x2), A_C_00000000, A_C_00000000); - gpr_map[gpr++] = 0x00000000; - snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(6) ); - A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x3), A_C_00000000, A_C_00000000); - /* For 96kHz mode */ - /* Left ADC in. 2 of 2 */ - gpr_map[gpr++] = 0x00000000; - snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0x8) ); - A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x4), A_C_00000000, A_C_00000000); - /* Right ADC in 2 of 2 */ - gpr_map[gpr++] = 0x00000000; - snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xa) ); - A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x5), A_C_00000000, A_C_00000000); - gpr_map[gpr++] = 0x00000000; - snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xc) ); - A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x6), A_C_00000000, A_C_00000000); - gpr_map[gpr++] = 0x00000000; - snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xe) ); - A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x7), A_C_00000000, A_C_00000000); - /* Pavel Hofman - we still have voices, A_FXBUS2s, and - * A_P16VINs available - - * let's add 8 more capture channels - total of 16 - */ - gpr_map[gpr++] = 0x00000000; - snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp, - bit_shifter16, - A_GPR(gpr - 1), - A_FXBUS2(0x10)); - A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x8), - A_C_00000000, A_C_00000000); - gpr_map[gpr++] = 0x00000000; - snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp, - bit_shifter16, - A_GPR(gpr - 1), - A_FXBUS2(0x12)); - A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x9), - A_C_00000000, A_C_00000000); - gpr_map[gpr++] = 0x00000000; - snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp, - bit_shifter16, - A_GPR(gpr - 1), - A_FXBUS2(0x14)); - A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xa), - A_C_00000000, A_C_00000000); - gpr_map[gpr++] = 0x00000000; - snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp, - bit_shifter16, - A_GPR(gpr - 1), - A_FXBUS2(0x16)); - A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xb), - A_C_00000000, A_C_00000000); - gpr_map[gpr++] = 0x00000000; - snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp, - bit_shifter16, - A_GPR(gpr - 1), - A_FXBUS2(0x18)); - A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xc), - A_C_00000000, A_C_00000000); - gpr_map[gpr++] = 0x00000000; - snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp, - bit_shifter16, - A_GPR(gpr - 1), - A_FXBUS2(0x1a)); - A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xd), - A_C_00000000, A_C_00000000); - gpr_map[gpr++] = 0x00000000; - snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp, - bit_shifter16, - A_GPR(gpr - 1), - A_FXBUS2(0x1c)); - A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xe), - A_C_00000000, A_C_00000000); - gpr_map[gpr++] = 0x00000000; - snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp, - bit_shifter16, - A_GPR(gpr - 1), - A_FXBUS2(0x1e)); - A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xf), - A_C_00000000, A_C_00000000); + if (emu->card_capabilities->ca0108_chip) { + snd_printk("EMU2 inputs on\n"); + for (z = 0; z < 0x10; z++) { + snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, + bit_shifter16, + A3_EMU32IN(z), + A_FXBUS2(z*2) ); + } + } else { + snd_printk("EMU inputs on\n"); + /* Capture 16 (originally 8) channels of S32_LE sound */ + + /* printk("emufx.c: gpr=0x%x, tmp=0x%x\n",gpr, tmp); */ + /* For the EMU1010: How to get 32bit values from the DSP. High 16bits into L, low 16bits into R. */ + /* A_P16VIN(0) is delayed by one sample, + * so all other A_P16VIN channels will need to also be delayed + */ + /* Left ADC in. 1 of 2 */ + snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_P16VIN(0x0), A_FXBUS2(0) ); + /* Right ADC in 1 of 2 */ + gpr_map[gpr++] = 0x00000000; + /* Delaying by one sample: instead of copying the input + * value A_P16VIN to output A_FXBUS2 as in the first channel, + * we use an auxiliary register, delaying the value by one + * sample + */ + snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(2) ); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x1), A_C_00000000, A_C_00000000); + gpr_map[gpr++] = 0x00000000; + snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(4) ); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x2), A_C_00000000, A_C_00000000); + gpr_map[gpr++] = 0x00000000; + snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(6) ); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x3), A_C_00000000, A_C_00000000); + /* For 96kHz mode */ + /* Left ADC in. 2 of 2 */ + gpr_map[gpr++] = 0x00000000; + snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0x8) ); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x4), A_C_00000000, A_C_00000000); + /* Right ADC in 2 of 2 */ + gpr_map[gpr++] = 0x00000000; + snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xa) ); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x5), A_C_00000000, A_C_00000000); + gpr_map[gpr++] = 0x00000000; + snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xc) ); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x6), A_C_00000000, A_C_00000000); + gpr_map[gpr++] = 0x00000000; + snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xe) ); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x7), A_C_00000000, A_C_00000000); + /* Pavel Hofman - we still have voices, A_FXBUS2s, and + * A_P16VINs available - + * let's add 8 more capture channels - total of 16 + */ + gpr_map[gpr++] = 0x00000000; + snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp, + bit_shifter16, + A_GPR(gpr - 1), + A_FXBUS2(0x10)); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x8), + A_C_00000000, A_C_00000000); + gpr_map[gpr++] = 0x00000000; + snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp, + bit_shifter16, + A_GPR(gpr - 1), + A_FXBUS2(0x12)); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x9), + A_C_00000000, A_C_00000000); + gpr_map[gpr++] = 0x00000000; + snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp, + bit_shifter16, + A_GPR(gpr - 1), + A_FXBUS2(0x14)); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xa), + A_C_00000000, A_C_00000000); + gpr_map[gpr++] = 0x00000000; + snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp, + bit_shifter16, + A_GPR(gpr - 1), + A_FXBUS2(0x16)); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xb), + A_C_00000000, A_C_00000000); + gpr_map[gpr++] = 0x00000000; + snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp, + bit_shifter16, + A_GPR(gpr - 1), + A_FXBUS2(0x18)); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xc), + A_C_00000000, A_C_00000000); + gpr_map[gpr++] = 0x00000000; + snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp, + bit_shifter16, + A_GPR(gpr - 1), + A_FXBUS2(0x1a)); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xd), + A_C_00000000, A_C_00000000); + gpr_map[gpr++] = 0x00000000; + snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp, + bit_shifter16, + A_GPR(gpr - 1), + A_FXBUS2(0x1c)); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xe), + A_C_00000000, A_C_00000000); + gpr_map[gpr++] = 0x00000000; + snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp, + bit_shifter16, + A_GPR(gpr - 1), + A_FXBUS2(0x1e)); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xf), + A_C_00000000, A_C_00000000); + } #if 0 for (z = 4; z < 8; z++) { @@ -2418,14 +2436,13 @@ static void copy_string(char *dst, char *src, char *null, int idx) strcpy(dst, src); } -static int snd_emu10k1_fx8010_info(struct snd_emu10k1 *emu, +static void snd_emu10k1_fx8010_info(struct snd_emu10k1 *emu, struct snd_emu10k1_fx8010_info *info) { char **fxbus, **extin, **extout; unsigned short fxbus_mask, extin_mask, extout_mask; int res; - memset(info, 0, sizeof(info)); info->internal_tram_size = emu->fx8010.itram_size; info->external_tram_size = emu->fx8010.etram_pages.bytes / 2; fxbus = fxbuses; @@ -2442,7 +2459,6 @@ static int snd_emu10k1_fx8010_info(struct snd_emu10k1 *emu, for (res = 16; res < 32; res++, extout++) copy_string(info->extout_names[res], extout_mask & (1 << res) ? *extout : NULL, "Unused", res); info->gpr_controls = emu->fx8010.gpr_count; - return 0; } static int snd_emu10k1_fx8010_ioctl(struct snd_hwdep * hw, struct file *file, unsigned int cmd, unsigned long arg) @@ -2463,10 +2479,7 @@ static int snd_emu10k1_fx8010_ioctl(struct snd_hwdep * hw, struct file *file, un info = kmalloc(sizeof(*info), GFP_KERNEL); if (!info) return -ENOMEM; - if ((res = snd_emu10k1_fx8010_info(emu, info)) < 0) { - kfree(info); - return res; - } + snd_emu10k1_fx8010_info(emu, info); if (copy_to_user(argp, info, sizeof(*info))) { kfree(info); return -EFAULT; diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index 7b2c1dcc533..54a2034d8ed 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -1,5 +1,5 @@ /* - * Copyright (c) by Jaroslav Kysela <perex@suse.cz>, + * Copyright (c) by Jaroslav Kysela <perex@perex.cz>, * Takashi Iwai <tiwai@suse.de> * Creative Labs, Inc. * Routines for control of EMU10K1 chips / mixer routines @@ -400,15 +400,7 @@ static struct snd_kcontrol_new snd_emu1010_input_enum_ctls[] __devinitdata = { - -static int snd_emu1010_adc_pads_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_emu1010_adc_pads_info snd_ctl_boolean_mono_info static int snd_emu1010_adc_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -456,14 +448,7 @@ static struct snd_kcontrol_new snd_emu1010_adc_pads[] __devinitdata = { EMU1010_ADC_PADS("ADC1 14dB PAD 0202 Capture Switch", EMU_HANA_0202_ADC_PAD1), }; -static int snd_emu1010_dac_pads_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_emu1010_dac_pads_info snd_ctl_boolean_mono_info static int snd_emu1010_dac_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -516,17 +501,19 @@ static struct snd_kcontrol_new snd_emu1010_dac_pads[] __devinitdata = { static int snd_emu1010_internal_clock_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[2] = { - "44100", "48000" + static char *texts[4] = { + "44100", "48000", "SPDIF", "ADAT" }; - + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; - uinfo->value.enumerated.items = 2; - if (uinfo->value.enumerated.item > 1) - uinfo->value.enumerated.item = 1; + uinfo->value.enumerated.items = 4; + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); return 0; + + } static int snd_emu1010_internal_clock_get(struct snd_kcontrol *kcontrol, @@ -584,6 +571,44 @@ static int snd_emu1010_internal_clock_put(struct snd_kcontrol *kcontrol, /* Unmute all */ snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); break; + + case 2: /* Take clock from S/PDIF IN */ + /* Mute all */ + snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); + /* Default fallback clock 48kHz */ + snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K ); + /* Word Clock source, sync to S/PDIF input */ + snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, + EMU_HANA_WCLOCK_HANA_SPDIF_IN | EMU_HANA_WCLOCK_1X ); + /* Set LEDs on Audio Dock */ + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, + EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK ); + /* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */ + /* Allow DLL to settle */ + msleep(10); + /* Unmute all */ + snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); + break; + + case 3: + /* Take clock from ADAT IN */ + /* Mute all */ + snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); + /* Default fallback clock 48kHz */ + snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K ); + /* Word Clock source, sync to ADAT input */ + snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, + EMU_HANA_WCLOCK_HANA_ADAT_IN | EMU_HANA_WCLOCK_1X ); + /* Set LEDs on Audio Dock */ + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK ); + /* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */ + /* Allow DLL to settle */ + msleep(10); + /* Unmute all */ + snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); + + + break; } } return change; @@ -871,7 +896,7 @@ static struct snd_kcontrol_new snd_emu10k1_spdif_mask_control = .access = SNDRV_CTL_ELEM_ACCESS_READ, .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK), - .count = 4, + .count = 3, .info = snd_emu10k1_spdif_info, .get = snd_emu10k1_spdif_get_mask }; @@ -880,7 +905,7 @@ static struct snd_kcontrol_new snd_emu10k1_spdif_control = { .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), - .count = 4, + .count = 3, .info = snd_emu10k1_spdif_info, .get = snd_emu10k1_spdif_get, .put = snd_emu10k1_spdif_put @@ -1326,14 +1351,7 @@ static struct snd_kcontrol_new snd_emu10k1_efx_attn_control = .put = snd_emu10k1_efx_attn_put }; -static int snd_emu10k1_shared_spdif_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_emu10k1_shared_spdif_info snd_ctl_boolean_mono_info static int snd_emu10k1_shared_spdif_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/pci/emu10k1/emumpu401.c b/sound/pci/emu10k1/emumpu401.c index 950c6bcd6b7..04c7cf70353 100644 --- a/sound/pci/emu10k1/emumpu401.c +++ b/sound/pci/emu10k1/emumpu401.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 EMU10K1 MPU-401 in UART mode * * diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index eda5cb373de..5ce5befc701 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * Creative Labs, Inc. * Routines for control of EMU10K1 chips / PCM routines * Multichannel PCM support Copyright (c) Lee Revell <rlrevell@joe-job.com> diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c index 2c1585991bc..c3fb10e81c9 100644 --- a/sound/pci/emu10k1/emuproc.c +++ b/sound/pci/emu10k1/emuproc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * Creative Labs, Inc. * Routines for control of EMU10K1 chips / proc interface routines * @@ -240,8 +240,42 @@ static void snd_emu10k1_proc_spdif_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { struct snd_emu10k1 *emu = entry->private_data; - snd_emu10k1_proc_spdif_status(emu, buffer, "CD-ROM S/PDIF In", CDCS, CDSRCS); - snd_emu10k1_proc_spdif_status(emu, buffer, "Optical or Coax S/PDIF In", GPSCS, GPSRCS); + u32 value; + u32 value2; + unsigned long flags; + u32 rate; + + if (emu->card_capabilities->emu1010) { + spin_lock_irqsave(&emu->emu_lock, flags); + snd_emu1010_fpga_read(emu, 0x38, &value); + spin_unlock_irqrestore(&emu->emu_lock, flags); + if ((value & 0x1) == 0) { + spin_lock_irqsave(&emu->emu_lock, flags); + snd_emu1010_fpga_read(emu, 0x2a, &value); + snd_emu1010_fpga_read(emu, 0x2b, &value2); + spin_unlock_irqrestore(&emu->emu_lock, flags); + rate = 0x1770000 / (((value << 5) | value2)+1); + snd_iprintf(buffer, "ADAT Locked : %u\n", rate); + } else { + snd_iprintf(buffer, "ADAT Unlocked\n"); + } + spin_lock_irqsave(&emu->emu_lock, flags); + snd_emu1010_fpga_read(emu, 0x20, &value); + spin_unlock_irqrestore(&emu->emu_lock, flags); + if ((value & 0x4) == 0) { + spin_lock_irqsave(&emu->emu_lock, flags); + snd_emu1010_fpga_read(emu, 0x28, &value); + snd_emu1010_fpga_read(emu, 0x29, &value2); + spin_unlock_irqrestore(&emu->emu_lock, flags); + rate = 0x1770000 / (((value << 5) | value2)+1); + snd_iprintf(buffer, "SPDIF Locked : %d\n", rate); + } else { + snd_iprintf(buffer, "SPDIF Unlocked\n"); + } + } else { + snd_emu10k1_proc_spdif_status(emu, buffer, "CD-ROM S/PDIF In", CDCS, CDSRCS); + snd_emu10k1_proc_spdif_status(emu, buffer, "Optical or Coax S/PDIF In", GPSCS, GPSRCS); + } #if 0 val = snd_emu10k1_ptr_read(emu, ZVSRCS, 0); snd_iprintf(buffer, "\nZoomed Video\n"); @@ -379,20 +413,16 @@ static void snd_emu_proc_emu1010_reg_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { struct snd_emu10k1 *emu = entry->private_data; - unsigned long value; + int value; unsigned long flags; - unsigned long regs; int i; snd_iprintf(buffer, "EMU1010 Registers:\n\n"); - for(i = 0; i < 0x30; i+=1) { + for(i = 0; i < 0x40; i+=1) { spin_lock_irqsave(&emu->emu_lock, flags); - regs=i+0x40; /* 0x40 upwards are registers. */ - outl(regs, emu->port + A_IOCFG); - outl(regs | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ - value = inl(emu->port + A_IOCFG); + snd_emu1010_fpga_read(emu, i, &value); spin_unlock_irqrestore(&emu->emu_lock, flags); - snd_iprintf(buffer, "%02X: %08lX, %02lX\n", i, value, (value >> 8) & 0x7f); + snd_iprintf(buffer, "%02X: %08X, %02X\n", i, value, (value >> 8) & 0x7f); } } @@ -555,9 +585,9 @@ int __devinit snd_emu10k1_proc_init(struct snd_emu10k1 * emu) { struct snd_info_entry *entry; #ifdef CONFIG_SND_DEBUG - if ((emu->card_capabilities->emu1010) && - snd_card_proc_new(emu->card, "emu1010_regs", &entry)) { - snd_info_set_text_ops(entry, emu, snd_emu_proc_emu1010_reg_read); + if (emu->card_capabilities->emu1010) { + if (! snd_card_proc_new(emu->card, "emu1010_regs", &entry)) + snd_info_set_text_ops(entry, emu, snd_emu_proc_emu1010_reg_read); } if (! snd_card_proc_new(emu->card, "io_regs", &entry)) { snd_info_set_text_ops(entry, emu, snd_emu_proc_io_reg_read); diff --git a/sound/pci/emu10k1/io.c b/sound/pci/emu10k1/io.c index 116e1c8d936..6702c15fefa 100644 --- a/sound/pci/emu10k1/io.c +++ b/sound/pci/emu10k1/io.c @@ -1,5 +1,5 @@ /* - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * Creative Labs, Inc. * Routines for control of EMU10K1 chips * @@ -226,9 +226,9 @@ int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu, return 0; } -int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, int reg, int value) +int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, u32 reg, u32 value) { - if (reg < 0 || reg > 0x3f) + if (reg > 0x3f) return 1; reg += 0x40; /* 0x40 upwards are registers. */ if (value < 0 || value > 0x3f) /* 0 to 0x3f are values */ @@ -244,9 +244,9 @@ int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, int reg, int value) return 0; } -int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, int reg, int *value) +int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, u32 reg, u32 *value) { - if (reg < 0 || reg > 0x3f) + if (reg > 0x3f) return 1; reg += 0x40; /* 0x40 upwards are registers. */ outl(reg, emu->port + A_IOCFG); @@ -261,7 +261,7 @@ int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, int reg, int *value) /* Each Destination has one and only one Source, * but one Source can feed any number of Destinations simultaneously. */ -int snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 * emu, int dst, int src) +int snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 * emu, u32 dst, u32 src) { snd_emu1010_fpga_write(emu, 0x00, ((dst >> 8) & 0x3f) ); snd_emu1010_fpga_write(emu, 0x01, (dst & 0x3f) ); diff --git a/sound/pci/emu10k1/irq.c b/sound/pci/emu10k1/irq.c index 4f18f7e8bcf..3c114b45e0b 100644 --- a/sound/pci/emu10k1/irq.c +++ b/sound/pci/emu10k1/irq.c @@ -1,5 +1,5 @@ /* - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * Creative Labs, Inc. * Routines for IRQ control of EMU10K1 chips * diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c index 4fcaefe5a3c..48097c6bb15 100644 --- a/sound/pci/emu10k1/memory.c +++ b/sound/pci/emu10k1/memory.c @@ -1,5 +1,5 @@ /* - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * Copyright (c) by Takashi Iwai <tiwai@suse.de> * * EMU10K1 memory page allocation (PTB area) diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index 7ee19c63c2c..d619a3842cd 100644 --- a/sound/pci/emu10k1/p16v.c +++ b/sound/pci/emu10k1/p16v.c @@ -124,11 +124,12 @@ /* hardware definition */ static struct snd_pcm_hardware snd_p16v_playback_hw = { - .info = (SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_RESUME | - SNDRV_PCM_INFO_MMAP_VALID), + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_RESUME | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_SYNC_START, .formats = SNDRV_PCM_FMTBIT_S32_LE, /* Only supports 24-bit samples padded to 32 bits. */ .rates = SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_44100, .rate_min = 44100, @@ -207,6 +208,11 @@ static int snd_p16v_pcm_open_playback_channel(struct snd_pcm_substream *substrea if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) return err; + runtime->sync.id32[0] = substream->pcm->card->number; + runtime->sync.id32[1] = 'P'; + runtime->sync.id32[2] = 16; + runtime->sync.id32[3] = 'V'; + return 0; } /* open_capture callback */ @@ -448,6 +454,9 @@ static int snd_p16v_pcm_trigger_playback(struct snd_pcm_substream *substream, break; } snd_pcm_group_for_each_entry(s, substream) { + if (snd_pcm_substream_chip(s) != emu || + s->stream != SNDRV_PCM_STREAM_PLAYBACK) + continue; runtime = s->runtime; epcm = runtime->private_data; channel = substream->pcm->device-emu->p16v_device_offset; diff --git a/sound/pci/emu10k1/voice.c b/sound/pci/emu10k1/voice.c index 1db50fe6147..04fa8492abb 100644 --- a/sound/pci/emu10k1/voice.c +++ b/sound/pci/emu10k1/voice.c @@ -1,5 +1,5 @@ /* - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * Creative Labs, Inc. * Lee Revell <rlrevell@joe-job.com> * Routines for control of EMU10K1 chips - voice manager diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index 21cb4268a59..b958f869cb1 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c @@ -1,6 +1,6 @@ /* * Driver for Ensoniq ES1370/ES1371 AudioPCI soundcard - * Copyright (c) by Jaroslav Kysela <perex@suse.cz>, + * Copyright (c) by Jaroslav Kysela <perex@perex.cz>, * Thomas Sailer <sailer@ife.ee.ethz.ch> * * This program is free software; you can redistribute it and/or modify @@ -61,7 +61,7 @@ #endif -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Thomas Sailer <sailer@ife.ee.ethz.ch>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Thomas Sailer <sailer@ife.ee.ethz.ch>"); MODULE_LICENSE("GPL"); #ifdef CHIP1370 MODULE_DESCRIPTION("Ensoniq AudioPCI ES1370"); @@ -1419,15 +1419,7 @@ static int snd_ens1373_spdif_stream_put(struct snd_kcontrol *kcontrol, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_es1371_spdif_info, \ .get = snd_es1371_spdif_get, .put = snd_es1371_spdif_put } -static int snd_es1371_spdif_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_es1371_spdif_info snd_ctl_boolean_mono_info static int snd_es1371_spdif_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1489,15 +1481,7 @@ static struct snd_kcontrol_new snd_es1371_mixer_spdif[] __devinitdata = { }; -static int snd_es1373_rear_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_es1373_rear_info snd_ctl_boolean_mono_info static int snd_es1373_rear_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1542,15 +1526,7 @@ static struct snd_kcontrol_new snd_ens1373_rear __devinitdata = .put = snd_es1373_rear_put, }; -static int snd_es1373_line_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_es1373_line_info snd_ctl_boolean_mono_info static int snd_es1373_line_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1707,15 +1683,7 @@ static int __devinit snd_ensoniq_1371_mixer(struct ensoniq *ensoniq, .get = snd_ensoniq_control_get, .put = snd_ensoniq_control_put, \ .private_value = mask } -static int snd_ensoniq_control_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_ensoniq_control_info snd_ctl_boolean_mono_info static int snd_ensoniq_control_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c index fec29a10894..fb25abe68a0 100644 --- a/sound/pci/es1938.c +++ b/sound/pci/es1938.c @@ -1,7 +1,7 @@ /* * Driver for ESS Solo-1 (ES1938, ES1946, ES1969) soundcard * Copyright (c) by Jaromir Koutek <miri@punknet.cz>, - * Jaroslav Kysela <perex@suse.cz>, + * Jaroslav Kysela <perex@perex.cz>, * Thomas Sailer <sailer@ife.ee.ethz.ch>, * Abramo Bagnara <abramo@alsa-project.org>, * Markus Gruber <gruber@eikon.tum.de> @@ -1066,15 +1066,7 @@ static int snd_es1938_put_mux(struct snd_kcontrol *kcontrol, return snd_es1938_mixer_bits(chip, 0x1c, 0x07, val) != val; } -static int snd_es1938_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_es1938_info_spatializer_enable snd_ctl_boolean_mono_info static int snd_es1938_get_spatializer_enable(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1120,15 +1112,7 @@ static int snd_es1938_get_hw_volume(struct snd_kcontrol *kcontrol, return 0; } -static int snd_es1938_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_es1938_info_hw_switch snd_ctl_boolean_stereo_info static int snd_es1938_get_hw_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index 2faf009076b..d69b11d1f99 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c @@ -843,10 +843,9 @@ static void snd_es1968_bob_dec(struct es1968 *chip) snd_es1968_bob_stop(chip); else if (chip->bob_freq > ESM_BOB_FREQ) { /* check reduction of timer frequency */ - struct list_head *p; int max_freq = ESM_BOB_FREQ; - list_for_each(p, &chip->substream_list) { - struct esschan *es = list_entry(p, struct esschan, list); + struct esschan *es; + list_for_each_entry(es, &chip->substream_list, list) { if (max_freq < es->bob_freq) max_freq = es->bob_freq; } @@ -1316,12 +1315,11 @@ static struct snd_pcm_hardware snd_es1968_capture = { static int calc_available_memory_size(struct es1968 *chip) { - struct list_head *p; int max_size = 0; - + struct esm_memory *buf; + mutex_lock(&chip->memory_mutex); - list_for_each(p, &chip->buf_list) { - struct esm_memory *buf = list_entry(p, struct esm_memory, list); + list_for_each_entry(buf, &chip->buf_list, list) { if (buf->empty && buf->buf.bytes > max_size) max_size = buf->buf.bytes; } @@ -1335,12 +1333,10 @@ static int calc_available_memory_size(struct es1968 *chip) static struct esm_memory *snd_es1968_new_memory(struct es1968 *chip, int size) { struct esm_memory *buf; - struct list_head *p; - + size = ALIGN(size, ESM_MEM_ALIGN); mutex_lock(&chip->memory_mutex); - list_for_each(p, &chip->buf_list) { - buf = list_entry(p, struct esm_memory, list); + list_for_each_entry(buf, &chip->buf_list, list) { if (buf->empty && buf->buf.bytes >= size) goto __found; } @@ -1938,10 +1934,9 @@ static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id) } if (event & ESM_SOUND_IRQ) { - struct list_head *p; + struct esschan *es; spin_lock(&chip->substream_lock); - list_for_each(p, &chip->substream_list) { - struct esschan *es = list_entry(p, struct esschan, list); + list_for_each_entry(es, &chip->substream_list, list) { if (es->running) snd_es1968_update_pcm(chip, es); } @@ -2345,7 +2340,7 @@ static int es1968_resume(struct pci_dev *pci) { struct snd_card *card = pci_get_drvdata(pci); struct es1968 *chip = card->private_data; - struct list_head *p; + struct esschan *es; if (! chip->do_pm) return 0; @@ -2374,8 +2369,7 @@ static int es1968_resume(struct pci_dev *pci) /* restore ac97 state */ snd_ac97_resume(chip->ac97); - list_for_each(p, &chip->substream_list) { - struct esschan *es = list_entry(p, struct esschan, list); + list_for_each_entry(es, &chip->substream_list, list) { switch (es->mode) { case ESM_MODE_PLAY: snd_es1968_playback_setup(chip, es, es->substream->runtime); diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index 11015178e20..9939109f05a 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -1,6 +1,6 @@ /* * The driver for the ForteMedia FM801 based soundcards - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * * Support FM only card by Andy Shevchenko <andy@smile.org.ua> * @@ -42,7 +42,7 @@ #define TEA575X_RADIO 1 #endif -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("ForteMedia FM801"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{ForteMedia,FM801}," diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index b2484bbdcc1..ab0c726d648 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile @@ -1,19 +1,18 @@ -snd-hda-intel-objs := hda_intel.o +snd-hda-intel-y := hda_intel.o # since snd-hda-intel is the only driver using hda-codec, # merge it into a single module although it was originally # designed to be individual modules -snd-hda-intel-objs += hda_codec.o \ - hda_generic.o \ - patch_realtek.o \ - patch_cmedia.o \ - patch_analog.o \ - patch_sigmatel.o \ - patch_si3054.o \ - patch_atihdmi.o \ - patch_conexant.o \ - patch_via.o -ifdef CONFIG_PROC_FS -snd-hda-intel-objs += hda_proc.o -endif +snd-hda-intel-y += hda_codec.o +snd-hda-intel-$(CONFIG_PROC_FS) += hda_proc.o +snd-hda-intel-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o +snd-hda-intel-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o +snd-hda-intel-$(CONFIG_SND_HDA_CODEC_REALTEK) += patch_realtek.o +snd-hda-intel-$(CONFIG_SND_HDA_CODEC_CMEDIA) += patch_cmedia.o +snd-hda-intel-$(CONFIG_SND_HDA_CODEC_ANALOG) += patch_analog.o +snd-hda-intel-$(CONFIG_SND_HDA_CODEC_SIGMATEL) += patch_sigmatel.o +snd-hda-intel-$(CONFIG_SND_HDA_CODEC_SI3054) += patch_si3054.o +snd-hda-intel-$(CONFIG_SND_HDA_CODEC_ATIHDMI) += patch_atihdmi.o +snd-hda-intel-$(CONFIG_SND_HDA_CODEC_CONEXANT) += patch_conexant.o +snd-hda-intel-$(CONFIG_SND_HDA_CODEC_VIA) += patch_via.o obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-intel.o diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index f87f8f08895..187533e477c 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -31,7 +31,15 @@ #include <sound/tlv.h> #include <sound/initval.h> #include "hda_local.h" - +#include <sound/hda_hwdep.h> + +#ifdef CONFIG_SND_HDA_POWER_SAVE +/* define this option here to hide as static */ +static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT; +module_param(power_save, int, 0644); +MODULE_PARM_DESC(power_save, "Automatic power-saving timeout " + "(in second, 0 = disable)."); +#endif /* * vendor / preset table @@ -59,6 +67,13 @@ static struct hda_vendor_id hda_vendor_ids[] = { #include "hda_patch.h" +#ifdef CONFIG_SND_HDA_POWER_SAVE +static void hda_power_work(struct work_struct *work); +static void hda_keep_power_on(struct hda_codec *codec); +#else +static inline void hda_keep_power_on(struct hda_codec *codec) {} +#endif + /** * snd_hda_codec_read - send a command and get the response * @codec: the HDA codec @@ -76,12 +91,14 @@ unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, unsigned int verb, unsigned int parm) { unsigned int res; + snd_hda_power_up(codec); mutex_lock(&codec->bus->cmd_mutex); if (!codec->bus->ops.command(codec, nid, direct, verb, parm)) res = codec->bus->ops.get_response(codec); else res = (unsigned int)-1; mutex_unlock(&codec->bus->cmd_mutex); + snd_hda_power_down(codec); return res; } @@ -101,9 +118,11 @@ int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct, unsigned int verb, unsigned int parm) { int err; + snd_hda_power_up(codec); mutex_lock(&codec->bus->cmd_mutex); err = codec->bus->ops.command(codec, nid, direct, verb, parm); mutex_unlock(&codec->bus->cmd_mutex); + snd_hda_power_down(codec); return err; } @@ -136,6 +155,8 @@ int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid, unsigned int parm; parm = snd_hda_param_read(codec, nid, AC_PAR_NODE_COUNT); + if (parm == -1) + return 0; *start_id = (parm >> 16) & 0x7fff; return (int)(parm & 0x7fff); } @@ -387,6 +408,13 @@ int __devinit snd_hda_bus_new(struct snd_card *card, return 0; } +#ifdef CONFIG_SND_HDA_GENERIC +#define is_generic_config(codec) \ + (codec->bus->modelname && !strcmp(codec->bus->modelname, "generic")) +#else +#define is_generic_config(codec) 0 +#endif + /* * find a matching codec preset */ @@ -395,7 +423,7 @@ find_codec_preset(struct hda_codec *codec) { const struct hda_codec_preset **tbl, *preset; - if (codec->bus->modelname && !strcmp(codec->bus->modelname, "generic")) + if (is_generic_config(codec)) return NULL; /* use the generic parser */ for (tbl = hda_preset_tables; *tbl; tbl++) { @@ -486,6 +514,10 @@ static int read_widget_caps(struct hda_codec *codec, hda_nid_t fg_node) } +static void init_hda_cache(struct hda_cache_rec *cache, + unsigned int record_size); +static void free_hda_cache(struct hda_cache_rec *cache); + /* * codec destructor */ @@ -493,17 +525,20 @@ static void snd_hda_codec_free(struct hda_codec *codec) { if (!codec) return; +#ifdef CONFIG_SND_HDA_POWER_SAVE + cancel_delayed_work(&codec->power_work); + flush_scheduled_work(); +#endif list_del(&codec->list); codec->bus->caddr_tbl[codec->addr] = NULL; if (codec->patch_ops.free) codec->patch_ops.free(codec); - kfree(codec->amp_info); + free_hda_cache(&codec->amp_cache); + free_hda_cache(&codec->cmd_cache); kfree(codec->wcaps); kfree(codec); } -static void init_amp_hash(struct hda_codec *codec); - /** * snd_hda_codec_new - create a HDA codec * @bus: the bus to assign @@ -537,7 +572,17 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, codec->bus = bus; codec->addr = codec_addr; mutex_init(&codec->spdif_mutex); - init_amp_hash(codec); + init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); + init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); + +#ifdef CONFIG_SND_HDA_POWER_SAVE + INIT_DELAYED_WORK(&codec->power_work, hda_power_work); + /* snd_hda_codec_new() marks the codec as power-up, and leave it as is. + * the caller has to power down appropriatley after initialization + * phase. + */ + hda_keep_power_on(codec); +#endif list_add_tail(&codec->list, &bus->codec_list); bus->caddr_tbl[codec_addr] = codec; @@ -581,10 +626,26 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, snd_hda_get_codec_name(codec, bus->card->mixername, sizeof(bus->card->mixername)); - if (codec->preset && codec->preset->patch) - err = codec->preset->patch(codec); - else +#ifdef CONFIG_SND_HDA_GENERIC + if (is_generic_config(codec)) { err = snd_hda_parse_generic_codec(codec); + goto patched; + } +#endif + if (codec->preset && codec->preset->patch) { + err = codec->preset->patch(codec); + goto patched; + } + + /* call the default parser */ +#ifdef CONFIG_SND_HDA_GENERIC + err = snd_hda_parse_generic_codec(codec); +#else + printk(KERN_ERR "hda-codec: No codec parser is available\n"); + err = -ENODEV; +#endif + + patched: if (err < 0) { snd_hda_codec_free(codec); return err; @@ -594,6 +655,9 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, init_unsol_queue(bus); snd_hda_codec_proc_new(codec); +#ifdef CONFIG_SND_HDA_HWDEP + snd_hda_create_hwdep(codec); +#endif sprintf(component, "HDA:%08x", codec->vendor_id); snd_component_add(codec->bus->card, component); @@ -637,59 +701,72 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, #define INFO_AMP_VOL(ch) (1 << (1 + (ch))) /* initialize the hash table */ -static void __devinit init_amp_hash(struct hda_codec *codec) +static void __devinit init_hda_cache(struct hda_cache_rec *cache, + unsigned int record_size) +{ + memset(cache, 0, sizeof(*cache)); + memset(cache->hash, 0xff, sizeof(cache->hash)); + cache->record_size = record_size; +} + +static void free_hda_cache(struct hda_cache_rec *cache) { - memset(codec->amp_hash, 0xff, sizeof(codec->amp_hash)); - codec->num_amp_entries = 0; - codec->amp_info_size = 0; - codec->amp_info = NULL; + kfree(cache->buffer); } /* query the hash. allocate an entry if not found. */ -static struct hda_amp_info *get_alloc_amp_hash(struct hda_codec *codec, u32 key) +static struct hda_cache_head *get_alloc_hash(struct hda_cache_rec *cache, + u32 key) { - u16 idx = key % (u16)ARRAY_SIZE(codec->amp_hash); - u16 cur = codec->amp_hash[idx]; - struct hda_amp_info *info; + u16 idx = key % (u16)ARRAY_SIZE(cache->hash); + u16 cur = cache->hash[idx]; + struct hda_cache_head *info; while (cur != 0xffff) { - info = &codec->amp_info[cur]; + info = (struct hda_cache_head *)(cache->buffer + + cur * cache->record_size); if (info->key == key) return info; cur = info->next; } /* add a new hash entry */ - if (codec->num_amp_entries >= codec->amp_info_size) { + if (cache->num_entries >= cache->size) { /* reallocate the array */ - int new_size = codec->amp_info_size + 64; - struct hda_amp_info *new_info; - new_info = kcalloc(new_size, sizeof(struct hda_amp_info), - GFP_KERNEL); - if (!new_info) { + unsigned int new_size = cache->size + 64; + void *new_buffer; + new_buffer = kcalloc(new_size, cache->record_size, GFP_KERNEL); + if (!new_buffer) { snd_printk(KERN_ERR "hda_codec: " "can't malloc amp_info\n"); return NULL; } - if (codec->amp_info) { - memcpy(new_info, codec->amp_info, - codec->amp_info_size * - sizeof(struct hda_amp_info)); - kfree(codec->amp_info); + if (cache->buffer) { + memcpy(new_buffer, cache->buffer, + cache->size * cache->record_size); + kfree(cache->buffer); } - codec->amp_info_size = new_size; - codec->amp_info = new_info; + cache->size = new_size; + cache->buffer = new_buffer; } - cur = codec->num_amp_entries++; - info = &codec->amp_info[cur]; + cur = cache->num_entries++; + info = (struct hda_cache_head *)(cache->buffer + + cur * cache->record_size); info->key = key; - info->status = 0; /* not initialized yet */ - info->next = codec->amp_hash[idx]; - codec->amp_hash[idx] = cur; + info->val = 0; + info->next = cache->hash[idx]; + cache->hash[idx] = cur; return info; } +/* query and allocate an amp hash entry */ +static inline struct hda_amp_info * +get_alloc_amp_hash(struct hda_codec *codec, u32 key) +{ + return (struct hda_amp_info *)get_alloc_hash(&codec->amp_cache, key); +} + /* * query AMP capabilities for the given widget and direction */ @@ -700,7 +777,7 @@ static u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction) info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, 0)); if (!info) return 0; - if (!(info->status & INFO_AMP_CAPS)) { + if (!(info->head.val & INFO_AMP_CAPS)) { if (!(get_wcaps(codec, nid) & AC_WCAP_AMP_OVRD)) nid = codec->afg; info->amp_caps = snd_hda_param_read(codec, nid, @@ -708,7 +785,7 @@ static u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction) AC_PAR_AMP_OUT_CAP : AC_PAR_AMP_IN_CAP); if (info->amp_caps) - info->status |= INFO_AMP_CAPS; + info->head.val |= INFO_AMP_CAPS; } return info->amp_caps; } @@ -722,7 +799,7 @@ int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, if (!info) return -EINVAL; info->amp_caps = caps; - info->status |= INFO_AMP_CAPS; + info->head.val |= INFO_AMP_CAPS; return 0; } @@ -736,7 +813,7 @@ static unsigned int get_vol_mute(struct hda_codec *codec, { u32 val, parm; - if (info->status & INFO_AMP_VOL(ch)) + if (info->head.val & INFO_AMP_VOL(ch)) return info->vol[ch]; parm = ch ? AC_AMP_GET_RIGHT : AC_AMP_GET_LEFT; @@ -745,7 +822,7 @@ static unsigned int get_vol_mute(struct hda_codec *codec, val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, parm); info->vol[ch] = val & 0xff; - info->status |= INFO_AMP_VOL(ch); + info->head.val |= INFO_AMP_VOL(ch); return info->vol[ch]; } @@ -792,12 +869,50 @@ int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, return 0; val &= mask; val |= get_vol_mute(codec, info, nid, ch, direction, idx) & ~mask; - if (info->vol[ch] == val && !codec->in_resume) + if (info->vol[ch] == val) return 0; put_vol_mute(codec, info, nid, ch, direction, idx, val); return 1; } +/* + * update the AMP stereo with the same mask and value + */ +int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid, + int direction, int idx, int mask, int val) +{ + int ch, ret = 0; + for (ch = 0; ch < 2; ch++) + ret |= snd_hda_codec_amp_update(codec, nid, ch, direction, + idx, mask, val); + return ret; +} + +#ifdef SND_HDA_NEEDS_RESUME +/* resume the all amp commands from the cache */ +void snd_hda_codec_resume_amp(struct hda_codec *codec) +{ + struct hda_amp_info *buffer = codec->amp_cache.buffer; + int i; + + for (i = 0; i < codec->amp_cache.size; i++, buffer++) { + u32 key = buffer->head.key; + hda_nid_t nid; + unsigned int idx, dir, ch; + if (!key) + continue; + nid = key & 0xff; + idx = (key >> 16) & 0xff; + dir = (key >> 24) & 0xff; + for (ch = 0; ch < 2; ch++) { + if (!(buffer->head.val & INFO_AMP_VOL(ch))) + continue; + put_vol_mute(codec, buffer, nid, ch, dir, idx, + buffer->vol[ch]); + } + } +} +#endif /* SND_HDA_NEEDS_RESUME */ /* * AMP control callbacks @@ -844,9 +959,11 @@ int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, long *valp = ucontrol->value.integer.value; if (chs & 1) - *valp++ = snd_hda_codec_amp_read(codec, nid, 0, dir, idx) & 0x7f; + *valp++ = snd_hda_codec_amp_read(codec, nid, 0, dir, idx) + & HDA_AMP_VOLMASK; if (chs & 2) - *valp = snd_hda_codec_amp_read(codec, nid, 1, dir, idx) & 0x7f; + *valp = snd_hda_codec_amp_read(codec, nid, 1, dir, idx) + & HDA_AMP_VOLMASK; return 0; } @@ -861,6 +978,7 @@ int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, long *valp = ucontrol->value.integer.value; int change = 0; + snd_hda_power_up(codec); if (chs & 1) { change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx, 0x7f, *valp); @@ -869,6 +987,7 @@ int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, if (chs & 2) change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx, 0x7f, *valp); + snd_hda_power_down(codec); return change; } @@ -923,10 +1042,10 @@ int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol, if (chs & 1) *valp++ = (snd_hda_codec_amp_read(codec, nid, 0, dir, idx) & - 0x80) ? 0 : 1; + HDA_AMP_MUTE) ? 0 : 1; if (chs & 2) *valp = (snd_hda_codec_amp_read(codec, nid, 1, dir, idx) & - 0x80) ? 0 : 1; + HDA_AMP_MUTE) ? 0 : 1; return 0; } @@ -941,15 +1060,22 @@ int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, long *valp = ucontrol->value.integer.value; int change = 0; + snd_hda_power_up(codec); if (chs & 1) { change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx, - 0x80, *valp ? 0 : 0x80); + HDA_AMP_MUTE, + *valp ? 0 : HDA_AMP_MUTE); valp++; } if (chs & 2) change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx, - 0x80, *valp ? 0 : 0x80); - + HDA_AMP_MUTE, + *valp ? 0 : HDA_AMP_MUTE); +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (codec->patch_ops.check_power_status) + codec->patch_ops.check_power_status(codec, nid); +#endif + snd_hda_power_down(codec); return change; } @@ -1002,6 +1128,93 @@ int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol, } /* + * generic bound volume/swtich controls + */ +int snd_hda_mixer_bind_ctls_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct hda_bind_ctls *c; + int err; + + c = (struct hda_bind_ctls *)kcontrol->private_value; + mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ + kcontrol->private_value = *c->values; + err = c->ops->info(kcontrol, uinfo); + kcontrol->private_value = (long)c; + mutex_unlock(&codec->spdif_mutex); + return err; +} + +int snd_hda_mixer_bind_ctls_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct hda_bind_ctls *c; + int err; + + c = (struct hda_bind_ctls *)kcontrol->private_value; + mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ + kcontrol->private_value = *c->values; + err = c->ops->get(kcontrol, ucontrol); + kcontrol->private_value = (long)c; + mutex_unlock(&codec->spdif_mutex); + return err; +} + +int snd_hda_mixer_bind_ctls_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct hda_bind_ctls *c; + unsigned long *vals; + int err = 0, change = 0; + + c = (struct hda_bind_ctls *)kcontrol->private_value; + mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ + for (vals = c->values; *vals; vals++) { + kcontrol->private_value = *vals; + err = c->ops->put(kcontrol, ucontrol); + if (err < 0) + break; + change |= err; + } + kcontrol->private_value = (long)c; + mutex_unlock(&codec->spdif_mutex); + return err < 0 ? err : change; +} + +int snd_hda_mixer_bind_tlv(struct snd_kcontrol *kcontrol, int op_flag, + unsigned int size, unsigned int __user *tlv) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct hda_bind_ctls *c; + int err; + + c = (struct hda_bind_ctls *)kcontrol->private_value; + mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ + kcontrol->private_value = *c->values; + err = c->ops->tlv(kcontrol, op_flag, size, tlv); + kcontrol->private_value = (long)c; + mutex_unlock(&codec->spdif_mutex); + return err; +} + +struct hda_ctl_ops snd_hda_bind_vol = { + .info = snd_hda_mixer_amp_volume_info, + .get = snd_hda_mixer_amp_volume_get, + .put = snd_hda_mixer_amp_volume_put, + .tlv = snd_hda_mixer_amp_tlv +}; + +struct hda_ctl_ops snd_hda_bind_sw = { + .info = snd_hda_mixer_amp_switch_info, + .get = snd_hda_mixer_amp_switch_get, + .put = snd_hda_mixer_amp_switch_put, + .tlv = snd_hda_mixer_amp_tlv +}; + +/* * SPDIF out controls */ @@ -1118,26 +1331,20 @@ static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol, change = codec->spdif_ctls != val; codec->spdif_ctls = val; - if (change || codec->in_resume) { - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, - val & 0xff); - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_2, - val >> 8); + if (change) { + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_DIGI_CONVERT_1, + val & 0xff); + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_DIGI_CONVERT_2, + val >> 8); } mutex_unlock(&codec->spdif_mutex); return change; } -static int snd_hda_spdif_out_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_hda_spdif_out_switch_info snd_ctl_boolean_mono_info static int snd_hda_spdif_out_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1161,17 +1368,16 @@ static int snd_hda_spdif_out_switch_put(struct snd_kcontrol *kcontrol, if (ucontrol->value.integer.value[0]) val |= AC_DIG1_ENABLE; change = codec->spdif_ctls != val; - if (change || codec->in_resume) { + if (change) { codec->spdif_ctls = val; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, - val & 0xff); + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_DIGI_CONVERT_1, + val & 0xff); /* unmute amp switch (if any) */ if ((get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) && (val & AC_DIG1_ENABLE)) - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | - AC_AMP_SET_OUTPUT); + snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, + HDA_AMP_MUTE, 0); } mutex_unlock(&codec->spdif_mutex); return change; @@ -1219,8 +1425,7 @@ static struct snd_kcontrol_new dig_mixes[] = { * * Returns 0 if successful, or a negative error code. */ -int __devinit snd_hda_create_spdif_out_ctls(struct hda_codec *codec, - hda_nid_t nid) +int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid) { int err; struct snd_kcontrol *kctl; @@ -1264,10 +1469,10 @@ static int snd_hda_spdif_in_switch_put(struct snd_kcontrol *kcontrol, mutex_lock(&codec->spdif_mutex); change = codec->spdif_in_enable != val; - if (change || codec->in_resume) { + if (change) { codec->spdif_in_enable = val; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, - val); + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_DIGI_CONVERT_1, val); } mutex_unlock(&codec->spdif_mutex); return change; @@ -1318,8 +1523,7 @@ static struct snd_kcontrol_new dig_in_ctls[] = { * * Returns 0 if successful, or a negative error code. */ -int __devinit snd_hda_create_spdif_in_ctls(struct hda_codec *codec, - hda_nid_t nid) +int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid) { int err; struct snd_kcontrol *kctl; @@ -1338,6 +1542,79 @@ int __devinit snd_hda_create_spdif_in_ctls(struct hda_codec *codec, return 0; } +#ifdef SND_HDA_NEEDS_RESUME +/* + * command cache + */ + +/* build a 32bit cache key with the widget id and the command parameter */ +#define build_cmd_cache_key(nid, verb) ((verb << 8) | nid) +#define get_cmd_cache_nid(key) ((key) & 0xff) +#define get_cmd_cache_cmd(key) (((key) >> 8) & 0xffff) + +/** + * snd_hda_codec_write_cache - send a single command with caching + * @codec: the HDA codec + * @nid: NID to send the command + * @direct: direct flag + * @verb: the verb to send + * @parm: the parameter for the verb + * + * Send a single command without waiting for response. + * + * Returns 0 if successful, or a negative error code. + */ +int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, + int direct, unsigned int verb, unsigned int parm) +{ + int err; + snd_hda_power_up(codec); + mutex_lock(&codec->bus->cmd_mutex); + err = codec->bus->ops.command(codec, nid, direct, verb, parm); + if (!err) { + struct hda_cache_head *c; + u32 key = build_cmd_cache_key(nid, verb); + c = get_alloc_hash(&codec->cmd_cache, key); + if (c) + c->val = parm; + } + mutex_unlock(&codec->bus->cmd_mutex); + snd_hda_power_down(codec); + return err; +} + +/* resume the all commands from the cache */ +void snd_hda_codec_resume_cache(struct hda_codec *codec) +{ + struct hda_cache_head *buffer = codec->cmd_cache.buffer; + int i; + + for (i = 0; i < codec->cmd_cache.size; i++, buffer++) { + u32 key = buffer->key; + if (!key) + continue; + snd_hda_codec_write(codec, get_cmd_cache_nid(key), 0, + get_cmd_cache_cmd(key), buffer->val); + } +} + +/** + * snd_hda_sequence_write_cache - sequence writes with caching + * @codec: the HDA codec + * @seq: VERB array to send + * + * Send the commands sequentially from the given array. + * Thte commands are recorded on cache for power-save and resume. + * The array must be terminated with NID=0. + */ +void snd_hda_sequence_write_cache(struct hda_codec *codec, + const struct hda_verb *seq) +{ + for (; seq->nid; seq++) + snd_hda_codec_write_cache(codec, seq->nid, 0, seq->verb, + seq->param); +} +#endif /* SND_HDA_NEEDS_RESUME */ /* * set power state of the codec @@ -1345,23 +1622,86 @@ int __devinit snd_hda_create_spdif_in_ctls(struct hda_codec *codec, static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, unsigned int power_state) { - hda_nid_t nid, nid_start; - int nodes; + hda_nid_t nid; + int i; snd_hda_codec_write(codec, fg, 0, AC_VERB_SET_POWER_STATE, power_state); - nodes = snd_hda_get_sub_nodes(codec, fg, &nid_start); - for (nid = nid_start; nid < nodes + nid_start; nid++) { - if (get_wcaps(codec, nid) & AC_WCAP_POWER) + nid = codec->start_nid; + for (i = 0; i < codec->num_nodes; i++, nid++) { + if (get_wcaps(codec, nid) & AC_WCAP_POWER) { + unsigned int pincap; + /* + * don't power down the widget if it controls eapd + * and EAPD_BTLENABLE is set. + */ + pincap = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); + if (pincap & AC_PINCAP_EAPD) { + int eapd = snd_hda_codec_read(codec, nid, + 0, AC_VERB_GET_EAPD_BTLENABLE, 0); + eapd &= 0x02; + if (power_state == AC_PWRST_D3 && eapd) + continue; + } snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, power_state); + } } - if (power_state == AC_PWRST_D0) + if (power_state == AC_PWRST_D0) { + unsigned long end_time; + int state; msleep(10); + /* wait until the codec reachs to D0 */ + end_time = jiffies + msecs_to_jiffies(500); + do { + state = snd_hda_codec_read(codec, fg, 0, + AC_VERB_GET_POWER_STATE, 0); + if (state == power_state) + break; + msleep(1); + } while (time_after_eq(end_time, jiffies)); + } +} + +#ifdef SND_HDA_NEEDS_RESUME +/* + * call suspend and power-down; used both from PM and power-save + */ +static void hda_call_codec_suspend(struct hda_codec *codec) +{ + if (codec->patch_ops.suspend) + codec->patch_ops.suspend(codec, PMSG_SUSPEND); + hda_set_power_state(codec, + codec->afg ? codec->afg : codec->mfg, + AC_PWRST_D3); +#ifdef CONFIG_SND_HDA_POWER_SAVE + cancel_delayed_work(&codec->power_work); + codec->power_on = 0; + codec->power_transition = 0; +#endif +} + +/* + * kick up codec; used both from PM and power-save + */ +static void hda_call_codec_resume(struct hda_codec *codec) +{ + hda_set_power_state(codec, + codec->afg ? codec->afg : codec->mfg, + AC_PWRST_D0); + if (codec->patch_ops.resume) + codec->patch_ops.resume(codec); + else { + if (codec->patch_ops.init) + codec->patch_ops.init(codec); + snd_hda_codec_resume_amp(codec); + snd_hda_codec_resume_cache(codec); + } } +#endif /* SND_HDA_NEEDS_RESUME */ /** @@ -1376,28 +1716,24 @@ int __devinit snd_hda_build_controls(struct hda_bus *bus) { struct hda_codec *codec; - /* build controls */ list_for_each_entry(codec, &bus->codec_list, list) { - int err; - if (!codec->patch_ops.build_controls) - continue; - err = codec->patch_ops.build_controls(codec); - if (err < 0) - return err; - } - - /* initialize */ - list_for_each_entry(codec, &bus->codec_list, list) { - int err; + int err = 0; + /* fake as if already powered-on */ + hda_keep_power_on(codec); + /* then fire up */ hda_set_power_state(codec, codec->afg ? codec->afg : codec->mfg, AC_PWRST_D0); - if (!codec->patch_ops.init) - continue; - err = codec->patch_ops.init(codec); + /* continue to initialize... */ + if (codec->patch_ops.init) + err = codec->patch_ops.init(codec); + if (!err && codec->patch_ops.build_controls) + err = codec->patch_ops.build_controls(codec); + snd_hda_power_down(codec); if (err < 0) return err; } + return 0; } @@ -1789,9 +2125,9 @@ int __devinit snd_hda_build_pcms(struct hda_bus *bus) * * If no entries are matching, the function returns a negative value. */ -int __devinit snd_hda_check_board_config(struct hda_codec *codec, - int num_configs, const char **models, - const struct snd_pci_quirk *tbl) +int snd_hda_check_board_config(struct hda_codec *codec, + int num_configs, const char **models, + const struct snd_pci_quirk *tbl) { if (codec->bus->modelname && models) { int i; @@ -1841,10 +2177,9 @@ int __devinit snd_hda_check_board_config(struct hda_codec *codec, * * Returns 0 if successful, or a negative error code. */ -int __devinit snd_hda_add_new_ctls(struct hda_codec *codec, - struct snd_kcontrol_new *knew) +int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) { - int err; + int err; for (; knew->name; knew++) { struct snd_kcontrol *kctl; @@ -1867,6 +2202,93 @@ int __devinit snd_hda_add_new_ctls(struct hda_codec *codec, return 0; } +#ifdef CONFIG_SND_HDA_POWER_SAVE +static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, + unsigned int power_state); + +static void hda_power_work(struct work_struct *work) +{ + struct hda_codec *codec = + container_of(work, struct hda_codec, power_work.work); + + if (!codec->power_on || codec->power_count) { + codec->power_transition = 0; + return; + } + + hda_call_codec_suspend(codec); + if (codec->bus->ops.pm_notify) + codec->bus->ops.pm_notify(codec); +} + +static void hda_keep_power_on(struct hda_codec *codec) +{ + codec->power_count++; + codec->power_on = 1; +} + +void snd_hda_power_up(struct hda_codec *codec) +{ + codec->power_count++; + if (codec->power_on || codec->power_transition) + return; + + codec->power_on = 1; + if (codec->bus->ops.pm_notify) + codec->bus->ops.pm_notify(codec); + hda_call_codec_resume(codec); + cancel_delayed_work(&codec->power_work); + codec->power_transition = 0; +} + +void snd_hda_power_down(struct hda_codec *codec) +{ + --codec->power_count; + if (!codec->power_on || codec->power_count || codec->power_transition) + return; + if (power_save) { + codec->power_transition = 1; /* avoid reentrance */ + schedule_delayed_work(&codec->power_work, + msecs_to_jiffies(power_save * 1000)); + } +} + +int snd_hda_check_amp_list_power(struct hda_codec *codec, + struct hda_loopback_check *check, + hda_nid_t nid) +{ + struct hda_amp_list *p; + int ch, v; + + if (!check->amplist) + return 0; + for (p = check->amplist; p->nid; p++) { + if (p->nid == nid) + break; + } + if (!p->nid) + return 0; /* nothing changed */ + + for (p = check->amplist; p->nid; p++) { + for (ch = 0; ch < 2; ch++) { + v = snd_hda_codec_amp_read(codec, p->nid, ch, p->dir, + p->idx); + if (!(v & HDA_AMP_MUTE) && v > 0) { + if (!check->power_on) { + check->power_on = 1; + snd_hda_power_up(codec); + } + return 1; + } + } + } + if (check->power_on) { + check->power_on = 0; + snd_hda_power_down(codec); + } + return 0; +} +#endif /* * Channel mode helper @@ -1913,12 +2335,12 @@ int snd_hda_ch_mode_put(struct hda_codec *codec, mode = ucontrol->value.enumerated.item[0]; snd_assert(mode < num_chmodes, return -EINVAL); - if (*max_channelsp == chmode[mode].channels && !codec->in_resume) + if (*max_channelsp == chmode[mode].channels) return 0; /* change the current channel setting */ *max_channelsp = chmode[mode].channels; if (chmode[mode].sequence) - snd_hda_sequence_write(codec, chmode[mode].sequence); + snd_hda_sequence_write_cache(codec, chmode[mode].sequence); return 1; } @@ -1933,6 +2355,8 @@ int snd_hda_input_mux_info(const struct hda_input_mux *imux, uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; uinfo->value.enumerated.items = imux->num_items; + if (!imux->num_items) + return 0; index = uinfo->value.enumerated.item; if (index >= imux->num_items) index = imux->num_items - 1; @@ -1948,13 +2372,15 @@ int snd_hda_input_mux_put(struct hda_codec *codec, { unsigned int idx; + if (!imux->num_items) + return 0; idx = ucontrol->value.enumerated.item[0]; if (idx >= imux->num_items) idx = imux->num_items - 1; - if (*cur_val == idx && !codec->in_resume) + if (*cur_val == idx) return 0; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, - imux->items[idx].index); + snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, + imux->items[idx].index); *cur_val = idx; return 1; } @@ -2118,7 +2544,7 @@ int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec, * Helper for automatic ping configuration */ -static int __devinit is_in_nid_list(hda_nid_t nid, hda_nid_t *list) +static int is_in_nid_list(hda_nid_t nid, hda_nid_t *list) { for (; *list; list++) if (*list == nid) @@ -2169,9 +2595,9 @@ static void sort_pins_by_sequence(hda_nid_t * pins, short * sequences, * The digital input/output pins are assigned to dig_in_pin and dig_out_pin, * respectively. */ -int __devinit snd_hda_parse_pin_def_config(struct hda_codec *codec, - struct auto_pin_cfg *cfg, - hda_nid_t *ignore_nids) +int snd_hda_parse_pin_def_config(struct hda_codec *codec, + struct auto_pin_cfg *cfg, + hda_nid_t *ignore_nids) { hda_nid_t nid, nid_start; int nodes; @@ -2371,13 +2797,12 @@ int snd_hda_suspend(struct hda_bus *bus, pm_message_t state) { struct hda_codec *codec; - /* FIXME: should handle power widget capabilities */ list_for_each_entry(codec, &bus->codec_list, list) { - if (codec->patch_ops.suspend) - codec->patch_ops.suspend(codec, state); - hda_set_power_state(codec, - codec->afg ? codec->afg : codec->mfg, - AC_PWRST_D3); +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (!codec->power_on) + continue; +#endif + hda_call_codec_suspend(codec); } return 0; } @@ -2388,76 +2813,30 @@ int snd_hda_suspend(struct hda_bus *bus, pm_message_t state) * @state: resume state * * Returns 0 if successful. + * + * This fucntion is defined only when POWER_SAVE isn't set. + * In the power-save mode, the codec is resumed dynamically. */ int snd_hda_resume(struct hda_bus *bus) { struct hda_codec *codec; list_for_each_entry(codec, &bus->codec_list, list) { - hda_set_power_state(codec, - codec->afg ? codec->afg : codec->mfg, - AC_PWRST_D0); - if (codec->patch_ops.resume) - codec->patch_ops.resume(codec); + if (snd_hda_codec_needs_resume(codec)) + hda_call_codec_resume(codec); } return 0; } - -/** - * snd_hda_resume_ctls - resume controls in the new control list - * @codec: the HDA codec - * @knew: the array of struct snd_kcontrol_new - * - * This function resumes the mixer controls in the struct snd_kcontrol_new array, - * originally for snd_hda_add_new_ctls(). - * The array must be terminated with an empty entry as terminator. - */ -int snd_hda_resume_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) +#ifdef CONFIG_SND_HDA_POWER_SAVE +int snd_hda_codecs_inuse(struct hda_bus *bus) { - struct snd_ctl_elem_value *val; + struct hda_codec *codec; - val = kmalloc(sizeof(*val), GFP_KERNEL); - if (!val) - return -ENOMEM; - codec->in_resume = 1; - for (; knew->name; knew++) { - int i, count; - count = knew->count ? knew->count : 1; - for (i = 0; i < count; i++) { - memset(val, 0, sizeof(*val)); - val->id.iface = knew->iface; - val->id.device = knew->device; - val->id.subdevice = knew->subdevice; - strcpy(val->id.name, knew->name); - val->id.index = knew->index ? knew->index : i; - /* Assume that get callback reads only from cache, - * not accessing to the real hardware - */ - if (snd_ctl_elem_read(codec->bus->card, val) < 0) - continue; - snd_ctl_elem_write(codec->bus->card, NULL, val); - } + list_for_each_entry(codec, &bus->codec_list, list) { + if (snd_hda_codec_needs_resume(codec)) + return 1; } - codec->in_resume = 0; - kfree(val); return 0; } - -/** - * snd_hda_resume_spdif_out - resume the digital out - * @codec: the HDA codec - */ -int snd_hda_resume_spdif_out(struct hda_codec *codec) -{ - return snd_hda_resume_ctls(codec, dig_mixes); -} - -/** - * snd_hda_resume_spdif_in - resume the digital in - * @codec: the HDA codec - */ -int snd_hda_resume_spdif_in(struct hda_codec *codec) -{ - return snd_hda_resume_ctls(codec, dig_in_ctls); -} +#endif #endif diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 56c26e7ccdf..2bce925d84e 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -24,6 +24,11 @@ #include <sound/info.h> #include <sound/control.h> #include <sound/pcm.h> +#include <sound/hwdep.h> + +#if defined(CONFIG_PM) || defined(CONFIG_SND_HDA_POWER_SAVE) +#define SND_HDA_NEEDS_RESUME /* resume control code is required */ +#endif /* * nodes @@ -199,7 +204,9 @@ enum { #define AC_AMPCAP_OFFSET_SHIFT 0 #define AC_AMPCAP_NUM_STEPS (0x7f<<8) /* number of steps */ #define AC_AMPCAP_NUM_STEPS_SHIFT 8 -#define AC_AMPCAP_STEP_SIZE (0x7f<<16) /* step size 0-32dB in 0.25dB */ +#define AC_AMPCAP_STEP_SIZE (0x7f<<16) /* step size 0-32dB + * in 0.25dB + */ #define AC_AMPCAP_STEP_SIZE_SHIFT 16 #define AC_AMPCAP_MUTE (1<<31) /* mute capable */ #define AC_AMPCAP_MUTE_SHIFT 31 @@ -409,6 +416,10 @@ struct hda_bus_ops { unsigned int (*get_response)(struct hda_codec *codec); /* free the private data */ void (*private_free)(struct hda_bus *); +#ifdef CONFIG_SND_HDA_POWER_SAVE + /* notify power-up/down from codec to contoller */ + void (*pm_notify)(struct hda_codec *codec); +#endif }; /* template to pass to the bus constructor */ @@ -436,7 +447,8 @@ struct hda_bus { /* codec linked list */ struct list_head codec_list; - struct hda_codec *caddr_tbl[HDA_MAX_CODEC_ADDRESS + 1]; /* caddr -> codec */ + /* link caddr -> codec */ + struct hda_codec *caddr_tbl[HDA_MAX_CODEC_ADDRESS + 1]; struct mutex cmd_mutex; @@ -469,19 +481,34 @@ struct hda_codec_ops { int (*init)(struct hda_codec *codec); void (*free)(struct hda_codec *codec); void (*unsol_event)(struct hda_codec *codec, unsigned int res); -#ifdef CONFIG_PM +#ifdef SND_HDA_NEEDS_RESUME int (*suspend)(struct hda_codec *codec, pm_message_t state); int (*resume)(struct hda_codec *codec); #endif +#ifdef CONFIG_SND_HDA_POWER_SAVE + int (*check_power_status)(struct hda_codec *codec, hda_nid_t nid); +#endif }; /* record for amp information cache */ -struct hda_amp_info { +struct hda_cache_head { u32 key; /* hash key */ + u16 val; /* assigned value */ + u16 next; /* next link; -1 = terminal */ +}; + +struct hda_amp_info { + struct hda_cache_head head; u32 amp_caps; /* amp capabilities */ u16 vol[2]; /* current volume & mute */ - u16 status; /* update flag */ - u16 next; /* next link */ +}; + +struct hda_cache_rec { + u16 hash[64]; /* hash table for index */ + unsigned int num_entries; /* number of assigned entries */ + unsigned int size; /* allocated size */ + unsigned int record_size; /* record size (including header) */ + void *buffer; /* hash table entries */ }; /* PCM callbacks */ @@ -499,7 +526,7 @@ struct hda_pcm_ops { /* PCM information for each substream */ struct hda_pcm_stream { - unsigned int substreams; /* number of substreams, 0 = not exist */ + unsigned int substreams; /* number of substreams, 0 = not exist*/ unsigned int channels_min; /* min. number of channels */ unsigned int channels_max; /* max. number of channels */ hda_nid_t nid; /* default NID to query rates/formats/bps, or set up */ @@ -536,11 +563,6 @@ struct hda_codec { /* set by patch */ struct hda_codec_ops patch_ops; - /* resume phase - all controls should update even if - * the values are not changed - */ - unsigned int in_resume; - /* PCM to create, set by patch_ops.build_pcms callback */ unsigned int num_pcms; struct hda_pcm *pcm_info; @@ -553,16 +575,22 @@ struct hda_codec { hda_nid_t start_nid; u32 *wcaps; - /* hash for amp access */ - u16 amp_hash[32]; - int num_amp_entries; - int amp_info_size; - struct hda_amp_info *amp_info; + struct hda_cache_rec amp_cache; /* cache for amp access */ + struct hda_cache_rec cmd_cache; /* cache for other commands */ struct mutex spdif_mutex; unsigned int spdif_status; /* IEC958 status bits */ unsigned short spdif_ctls; /* SPDIF control bits */ unsigned int spdif_in_enable; /* SPDIF input enable? */ + + struct snd_hwdep *hwdep; /* assigned hwdep device */ + +#ifdef CONFIG_SND_HDA_POWER_SAVE + unsigned int power_on :1; /* current (global) power-state */ + unsigned int power_transition :1; /* power-state in transition */ + int power_count; /* current (global) power refcount */ + struct delayed_work power_work; /* delayed task for powerdown */ +#endif }; /* direction */ @@ -582,13 +610,17 @@ int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, /* * low level functions */ -unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, int direct, +unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, + int direct, unsigned int verb, unsigned int parm); int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct, unsigned int verb, unsigned int parm); -#define snd_hda_param_read(codec, nid, param) snd_hda_codec_read(codec, nid, 0, AC_VERB_PARAMETERS, param) -int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid, hda_nid_t *start_id); -int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid, hda_nid_t *conn_list, int max_conns); +#define snd_hda_param_read(codec, nid, param) \ + snd_hda_codec_read(codec, nid, 0, AC_VERB_PARAMETERS, param) +int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid, + hda_nid_t *start_id); +int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid, + hda_nid_t *conn_list, int max_conns); struct hda_verb { hda_nid_t nid; @@ -596,11 +628,24 @@ struct hda_verb { u32 param; }; -void snd_hda_sequence_write(struct hda_codec *codec, const struct hda_verb *seq); +void snd_hda_sequence_write(struct hda_codec *codec, + const struct hda_verb *seq); /* unsolicited event */ int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex); +/* cached write */ +#ifdef SND_HDA_NEEDS_RESUME +int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, + int direct, unsigned int verb, unsigned int parm); +void snd_hda_sequence_write_cache(struct hda_codec *codec, + const struct hda_verb *seq); +void snd_hda_codec_resume_cache(struct hda_codec *codec); +#else +#define snd_hda_codec_write_cache snd_hda_codec_write +#define snd_hda_sequence_write_cache snd_hda_sequence_write +#endif + /* * Mixer */ @@ -610,10 +655,13 @@ int snd_hda_build_controls(struct hda_bus *bus); * PCM */ int snd_hda_build_pcms(struct hda_bus *bus); -void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, u32 stream_tag, +void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, + u32 stream_tag, int channel_id, int format); -unsigned int snd_hda_calc_stream_format(unsigned int rate, unsigned int channels, - unsigned int format, unsigned int maxbps); +unsigned int snd_hda_calc_stream_format(unsigned int rate, + unsigned int channels, + unsigned int format, + unsigned int maxbps); int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, u32 *ratesp, u64 *formatsp, unsigned int *bpsp); int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid, @@ -632,4 +680,19 @@ int snd_hda_suspend(struct hda_bus *bus, pm_message_t state); int snd_hda_resume(struct hda_bus *bus); #endif +/* + * power saving + */ +#ifdef CONFIG_SND_HDA_POWER_SAVE +void snd_hda_power_up(struct hda_codec *codec); +void snd_hda_power_down(struct hda_codec *codec); +#define snd_hda_codec_needs_resume(codec) codec->power_count +int snd_hda_codecs_inuse(struct hda_bus *bus); +#else +static inline void snd_hda_power_up(struct hda_codec *codec) {} +static inline void snd_hda_power_down(struct hda_codec *codec) {} +#define snd_hda_codec_needs_resume(codec) 1 +#define snd_hda_codecs_inuse(bus) 1 +#endif + #endif /* __SOUND_HDA_CODEC_H */ diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 000287f7da4..c957eb58de5 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -70,6 +70,13 @@ struct hda_gspec { struct hda_pcm pcm_rec; /* PCM information */ struct list_head nid_list; /* list of widgets */ + +#ifdef CONFIG_SND_HDA_POWER_SAVE +#define MAX_LOOPBACK_AMPS 7 + struct hda_loopback_check loopback; + int num_loopbacks; + struct hda_amp_list loopback_list[MAX_LOOPBACK_AMPS + 1]; +#endif }; /* @@ -88,13 +95,12 @@ struct hda_gspec { static void snd_hda_generic_free(struct hda_codec *codec) { struct hda_gspec *spec = codec->spec; - struct list_head *p, *n; + struct hda_gnode *node, *n; if (! spec) return; /* free all widgets */ - list_for_each_safe(p, n, &spec->nid_list) { - struct hda_gnode *node = list_entry(p, struct hda_gnode, list); + list_for_each_entry_safe(node, n, &spec->nid_list, list) { if (node->conn_list != node->slist) kfree(node->conn_list); kfree(node); @@ -196,11 +202,9 @@ static int build_afg_tree(struct hda_codec *codec) /* FIXME: should avoid the braindead linear search */ static struct hda_gnode *hda_get_node(struct hda_gspec *spec, hda_nid_t nid) { - struct list_head *p; struct hda_gnode *node; - list_for_each(p, &spec->nid_list) { - node = list_entry(p, struct hda_gnode, list); + list_for_each_entry(node, &spec->nid_list, list) { if (node->nid == nid) return node; } @@ -218,9 +222,8 @@ static int unmute_output(struct hda_codec *codec, struct hda_gnode *node) ofs = (node->amp_out_caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT; if (val >= ofs) val -= ofs; - val |= AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT; - val |= AC_AMP_SET_OUTPUT; - return snd_hda_codec_write(codec, node->nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, val); + snd_hda_codec_amp_stereo(codec, node->nid, HDA_OUTPUT, 0, 0xff, val); + return 0; } /* @@ -234,11 +237,8 @@ static int unmute_input(struct hda_codec *codec, struct hda_gnode *node, unsigne ofs = (node->amp_in_caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT; if (val >= ofs) val -= ofs; - val |= AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT; - val |= AC_AMP_SET_INPUT; - // awk added - fixed to allow unmuting of indexed amps - val |= index << AC_AMP_SET_INDEX_SHIFT; - return snd_hda_codec_write(codec, node->nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, val); + snd_hda_codec_amp_stereo(codec, node->nid, HDA_INPUT, index, 0xff, val); + return 0; } /* @@ -248,7 +248,8 @@ static int select_input_connection(struct hda_codec *codec, struct hda_gnode *no unsigned int index) { snd_printdd("CONNECT: NID=0x%x IDX=0x%x\n", node->nid, index); - return snd_hda_codec_write(codec, node->nid, 0, AC_VERB_SET_CONNECT_SEL, index); + return snd_hda_codec_write_cache(codec, node->nid, 0, + AC_VERB_SET_CONNECT_SEL, index); } /* @@ -256,11 +257,9 @@ static int select_input_connection(struct hda_codec *codec, struct hda_gnode *no */ static void clear_check_flags(struct hda_gspec *spec) { - struct list_head *p; struct hda_gnode *node; - list_for_each(p, &spec->nid_list) { - node = list_entry(p, struct hda_gnode, list); + list_for_each_entry(node, &spec->nid_list, list) { node->checked = 0; } } @@ -343,12 +342,10 @@ static struct hda_gnode *parse_output_jack(struct hda_codec *codec, struct hda_gspec *spec, int jack_type) { - struct list_head *p; struct hda_gnode *node; int err; - list_for_each(p, &spec->nid_list) { - node = list_entry(p, struct hda_gnode, list); + list_for_each_entry(node, &spec->nid_list, list) { if (node->type != AC_WID_PIN) continue; /* output capable? */ @@ -379,7 +376,7 @@ static struct hda_gnode *parse_output_jack(struct hda_codec *codec, /* unmute the PIN output */ unmute_output(codec, node); /* set PIN-Out enable */ - snd_hda_codec_write(codec, node->nid, 0, + snd_hda_codec_write_cache(codec, node->nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN | ((node->pin_caps & AC_PINCAP_HP_DRV) ? @@ -570,7 +567,8 @@ static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec, /* unmute the PIN external input */ unmute_input(codec, node, 0); /* index = 0? */ /* set PIN-In enable */ - snd_hda_codec_write(codec, node->nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl); + snd_hda_codec_write_cache(codec, node->nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl); return 1; /* found */ } @@ -659,7 +657,6 @@ static int parse_input_path(struct hda_codec *codec, struct hda_gnode *adc_node) static int parse_input(struct hda_codec *codec) { struct hda_gspec *spec = codec->spec; - struct list_head *p; struct hda_gnode *node; int err; @@ -668,8 +665,7 @@ static int parse_input(struct hda_codec *codec) * If it reaches to certain input PINs, we take it as the * input path. */ - list_for_each(p, &spec->nid_list) { - node = list_entry(p, struct hda_gnode, list); + list_for_each_entry(node, &spec->nid_list, list) { if (node->wid_caps & AC_WCAP_DIGITAL) continue; /* skip SPDIF */ if (node->type == AC_WID_AUD_IN) { @@ -684,11 +680,33 @@ static int parse_input(struct hda_codec *codec) return 0; } +#ifdef CONFIG_SND_HDA_POWER_SAVE +static void add_input_loopback(struct hda_codec *codec, hda_nid_t nid, + int dir, int idx) +{ + struct hda_gspec *spec = codec->spec; + struct hda_amp_list *p; + + if (spec->num_loopbacks >= MAX_LOOPBACK_AMPS) { + snd_printk(KERN_ERR "hda_generic: Too many loopback ctls\n"); + return; + } + p = &spec->loopback_list[spec->num_loopbacks++]; + p->nid = nid; + p->dir = dir; + p->idx = idx; + spec->loopback.amplist = spec->loopback_list; +} +#else +#define add_input_loopback(codec,nid,dir,idx) +#endif + /* * create mixer controls if possible */ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node, - unsigned int index, const char *type, const char *dir_sfx) + unsigned int index, const char *type, + const char *dir_sfx, int is_loopback) { char name[32]; int err; @@ -702,6 +720,8 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node, if ((node->wid_caps & AC_WCAP_IN_AMP) && (node->amp_in_caps & AC_AMPCAP_MUTE)) { knew = (struct snd_kcontrol_new)HDA_CODEC_MUTE(name, node->nid, index, HDA_INPUT); + if (is_loopback) + add_input_loopback(codec, node->nid, HDA_INPUT, index); snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index); if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0) return err; @@ -709,6 +729,8 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node, } else if ((node->wid_caps & AC_WCAP_OUT_AMP) && (node->amp_out_caps & AC_AMPCAP_MUTE)) { knew = (struct snd_kcontrol_new)HDA_CODEC_MUTE(name, node->nid, 0, HDA_OUTPUT); + if (is_loopback) + add_input_loopback(codec, node->nid, HDA_OUTPUT, 0); snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid); if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0) return err; @@ -767,7 +789,7 @@ static int create_output_mixers(struct hda_codec *codec, const char **names) for (i = 0; i < spec->pcm_vol_nodes; i++) { err = create_mixer(codec, spec->pcm_vol[i].node, spec->pcm_vol[i].index, - names[i], "Playback"); + names[i], "Playback", 0); if (err < 0) return err; } @@ -784,7 +806,7 @@ static int build_output_controls(struct hda_codec *codec) case 1: return create_mixer(codec, spec->pcm_vol[0].node, spec->pcm_vol[0].index, - "Master", "Playback"); + "Master", "Playback", 0); case 2: if (defcfg_type(spec->out_pin_node[0]) == AC_JACK_SPEAKER) return create_output_mixers(codec, types_speaker); @@ -820,7 +842,7 @@ static int build_input_controls(struct hda_codec *codec) if (spec->input_mux.num_items == 1) { err = create_mixer(codec, adc_node, spec->input_mux.items[0].index, - NULL, "Capture"); + NULL, "Capture", 0); if (err < 0) return err; return 0; @@ -886,7 +908,8 @@ static int parse_loopback_path(struct hda_codec *codec, struct hda_gspec *spec, return err; else if (err >= 1) { if (err == 1) { - err = create_mixer(codec, node, i, type, "Playback"); + err = create_mixer(codec, node, i, type, + "Playback", 1); if (err < 0) return err; if (err > 0) @@ -911,7 +934,6 @@ static int parse_loopback_path(struct hda_codec *codec, struct hda_gspec *spec, static int build_loopback_controls(struct hda_codec *codec) { struct hda_gspec *spec = codec->spec; - struct list_head *p; struct hda_gnode *node; int err; const char *type; @@ -919,8 +941,7 @@ static int build_loopback_controls(struct hda_codec *codec) if (! spec->out_pin_node[0]) return 0; - list_for_each(p, &spec->nid_list) { - node = list_entry(p, struct hda_gnode, list); + list_for_each_entry(node, &spec->nid_list, list) { if (node->type != AC_WID_PIN) continue; /* input capable? */ @@ -1022,6 +1043,14 @@ static int build_generic_pcms(struct hda_codec *codec) return 0; } +#ifdef CONFIG_SND_HDA_POWER_SAVE +static int generic_check_power_status(struct hda_codec *codec, hda_nid_t nid) +{ + struct hda_gspec *spec = codec->spec; + return snd_hda_check_amp_list_power(codec, &spec->loopback, nid); +} +#endif + /* */ @@ -1029,6 +1058,9 @@ static struct hda_codec_ops generic_patch_ops = { .build_controls = build_generic_controls, .build_pcms = build_generic_pcms, .free = snd_hda_generic_free, +#ifdef CONFIG_SND_HDA_POWER_SAVE + .check_power_status = generic_check_power_status, +#endif }; /* diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c new file mode 100644 index 00000000000..bafb7b01f5a --- /dev/null +++ b/sound/pci/hda/hda_hwdep.c @@ -0,0 +1,122 @@ +/* + * HWDEP Interface for HD-audio codec + * + * Copyright (c) 2007 Takashi Iwai <tiwai@suse.de> + * + * This driver 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 driver 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/init.h> +#include <linux/slab.h> +#include <linux/pci.h> +#include <linux/compat.h> +#include <linux/mutex.h> +#include <sound/core.h> +#include "hda_codec.h" +#include "hda_local.h" +#include <sound/hda_hwdep.h> + +/* + * write/read an out-of-bound verb + */ +static int verb_write_ioctl(struct hda_codec *codec, + struct hda_verb_ioctl __user *arg) +{ + u32 verb, res; + + if (get_user(verb, &arg->verb)) + return -EFAULT; + res = snd_hda_codec_read(codec, verb >> 24, 0, + (verb >> 8) & 0xffff, verb & 0xff); + if (put_user(res, &arg->res)) + return -EFAULT; + return 0; +} + +static int get_wcap_ioctl(struct hda_codec *codec, + struct hda_verb_ioctl __user *arg) +{ + u32 verb, res; + + if (get_user(verb, &arg->verb)) + return -EFAULT; + res = get_wcaps(codec, verb >> 24); + if (put_user(res, &arg->res)) + return -EFAULT; + return 0; +} + + +/* + */ +static int hda_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct hda_codec *codec = hw->private_data; + void __user *argp = (void __user *)arg; + + switch (cmd) { + case HDA_IOCTL_PVERSION: + return put_user(HDA_HWDEP_VERSION, (int __user *)argp); + case HDA_IOCTL_VERB_WRITE: + return verb_write_ioctl(codec, argp); + case HDA_IOCTL_GET_WCAP: + return get_wcap_ioctl(codec, argp); + } + return -ENOIOCTLCMD; +} + +#ifdef CONFIG_COMPAT +static int hda_hwdep_ioctl_compat(struct snd_hwdep *hw, struct file *file, + unsigned int cmd, unsigned long arg) +{ + return hda_hwdep_ioctl(hw, file, cmd, (unsigned long)compat_ptr(arg)); +} +#endif + +static int hda_hwdep_open(struct snd_hwdep *hw, struct file *file) +{ +#ifndef CONFIG_SND_DEBUG_DETECT + if (!capable(CAP_SYS_RAWIO)) + return -EACCES; +#endif + return 0; +} + +int __devinit snd_hda_create_hwdep(struct hda_codec *codec) +{ + char hwname[16]; + struct snd_hwdep *hwdep; + int err; + + sprintf(hwname, "HDA Codec %d", codec->addr); + err = snd_hwdep_new(codec->bus->card, hwname, codec->addr, &hwdep); + if (err < 0) + return err; + codec->hwdep = hwdep; + sprintf(hwdep->name, "HDA Codec %d", codec->addr); + hwdep->iface = SNDRV_HWDEP_IFACE_HDA; + hwdep->private_data = codec; + hwdep->exclusive = 1; + + hwdep->ops.open = hda_hwdep_open; + hwdep->ops.ioctl = hda_hwdep_ioctl; +#ifdef CONFIG_COMPAT + hwdep->ops.ioctl_compat = hda_hwdep_ioctl_compat; +#endif + + return 0; +} diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 92bc8b3fa2a..3fa0f970490 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1,6 +1,7 @@ /* * - * hda_intel.c - Implementation of primary alsa driver code base for Intel HD Audio. + * hda_intel.c - Implementation of primary alsa driver code base + * for Intel HD Audio. * * Copyright(c) 2004 Intel Corporation. All rights reserved. * @@ -64,14 +65,27 @@ MODULE_PARM_DESC(id, "ID string for Intel HD audio interface."); module_param(model, charp, 0444); MODULE_PARM_DESC(model, "Use the given board model."); module_param(position_fix, int, 0444); -MODULE_PARM_DESC(position_fix, "Fix DMA pointer (0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size)."); +MODULE_PARM_DESC(position_fix, "Fix DMA pointer " + "(0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size)."); module_param(probe_mask, int, 0444); MODULE_PARM_DESC(probe_mask, "Bitmask to probe codecs (default = -1)."); module_param(single_cmd, bool, 0444); -MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs (for debugging only)."); +MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs " + "(for debugging only)."); module_param(enable_msi, int, 0); MODULE_PARM_DESC(enable_msi, "Enable Message Signaled Interrupt (MSI)"); +#ifdef CONFIG_SND_HDA_POWER_SAVE +/* power_save option is defined in hda_codec.c */ + +/* reset the HD-audio controller in power save mode. + * this may give more power-saving, but will take longer time to + * wake up. + */ +static int power_save_controller = 1; +module_param(power_save_controller, bool, 0644); +MODULE_PARM_DESC(power_save_controller, "Reset controller in power save mode."); +#endif /* just for backward compatibility */ static int enable; @@ -98,6 +112,7 @@ MODULE_DESCRIPTION("Intel HDA driver"); #define SFX "hda-intel: " + /* * registers */ @@ -213,15 +228,16 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; #define SD_INT_DESC_ERR 0x10 /* descriptor error interrupt */ #define SD_INT_FIFO_ERR 0x08 /* FIFO error interrupt */ #define SD_INT_COMPLETE 0x04 /* completion interrupt */ -#define SD_INT_MASK (SD_INT_DESC_ERR|SD_INT_FIFO_ERR|SD_INT_COMPLETE) +#define SD_INT_MASK (SD_INT_DESC_ERR|SD_INT_FIFO_ERR|\ + SD_INT_COMPLETE) /* SD_STS */ #define SD_STS_FIFO_READY 0x20 /* FIFO ready */ /* INTCTL and INTSTS */ -#define ICH6_INT_ALL_STREAM 0xff /* all stream interrupts */ -#define ICH6_INT_CTRL_EN 0x40000000 /* controller interrupt enable bit */ -#define ICH6_INT_GLOBAL_EN 0x80000000 /* global interrupt enable bit */ +#define ICH6_INT_ALL_STREAM 0xff /* all stream interrupts */ +#define ICH6_INT_CTRL_EN 0x40000000 /* controller interrupt enable bit */ +#define ICH6_INT_GLOBAL_EN 0x80000000 /* global interrupt enable bit */ /* GCTL unsolicited response enable bit */ #define ICH6_GCTL_UREN (1<<8) @@ -257,22 +273,26 @@ enum { */ struct azx_dev { - u32 *bdl; /* virtual address of the BDL */ - dma_addr_t bdl_addr; /* physical address of the BDL */ - u32 *posbuf; /* position buffer pointer */ + u32 *bdl; /* virtual address of the BDL */ + dma_addr_t bdl_addr; /* physical address of the BDL */ + u32 *posbuf; /* position buffer pointer */ - unsigned int bufsize; /* size of the play buffer in bytes */ - unsigned int fragsize; /* size of each period in bytes */ - unsigned int frags; /* number for period in the play buffer */ - unsigned int fifo_size; /* FIFO size */ + unsigned int bufsize; /* size of the play buffer in bytes */ + unsigned int fragsize; /* size of each period in bytes */ + unsigned int frags; /* number for period in the play buffer */ + unsigned int fifo_size; /* FIFO size */ - void __iomem *sd_addr; /* stream descriptor pointer */ + void __iomem *sd_addr; /* stream descriptor pointer */ - u32 sd_int_sta_mask; /* stream int status mask */ + u32 sd_int_sta_mask; /* stream int status mask */ /* pcm support */ - struct snd_pcm_substream *substream; /* assigned substream, set in PCM open */ - unsigned int format_val; /* format value to be set in the controller and the codec */ + struct snd_pcm_substream *substream; /* assigned substream, + * set in PCM open + */ + unsigned int format_val; /* format value to be set in the + * controller and the codec + */ unsigned char stream_tag; /* assigned stream */ unsigned char index; /* stream index */ /* for sanity check of position buffer */ @@ -337,6 +357,7 @@ struct azx { /* flags */ int position_fix; + unsigned int running :1; unsigned int initialized :1; unsigned int single_cmd :1; unsigned int polling_mode :1; @@ -418,7 +439,8 @@ static int azx_alloc_cmd_io(struct azx *chip) int err; /* single page (at least 4096 bytes) must suffice for both ringbuffes */ - err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), + err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(chip->pci), PAGE_SIZE, &chip->rb); if (err < 0) { snd_printk(KERN_ERR SFX "cannot allocate CORB/RIRB\n"); @@ -531,9 +553,9 @@ static unsigned int azx_rirb_get_response(struct hda_codec *codec) azx_update_rirb(chip); spin_unlock_irq(&chip->reg_lock); } - if (! chip->rirb.cmds) + if (!chip->rirb.cmds) return chip->rirb.res; /* the last value */ - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } while (time_after_eq(timeout, jiffies)); if (chip->msi) { @@ -585,16 +607,19 @@ static int azx_single_send_cmd(struct hda_codec *codec, u32 val) while (timeout--) { /* check ICB busy bit */ - if (! (azx_readw(chip, IRS) & ICH6_IRS_BUSY)) { + if (!((azx_readw(chip, IRS) & ICH6_IRS_BUSY))) { /* Clear IRV valid bit */ - azx_writew(chip, IRS, azx_readw(chip, IRS) | ICH6_IRS_VALID); + azx_writew(chip, IRS, azx_readw(chip, IRS) | + ICH6_IRS_VALID); azx_writel(chip, IC, val); - azx_writew(chip, IRS, azx_readw(chip, IRS) | ICH6_IRS_BUSY); + azx_writew(chip, IRS, azx_readw(chip, IRS) | + ICH6_IRS_BUSY); return 0; } udelay(1); } - snd_printd(SFX "send_cmd timeout: IRS=0x%x, val=0x%x\n", azx_readw(chip, IRS), val); + snd_printd(SFX "send_cmd timeout: IRS=0x%x, val=0x%x\n", + azx_readw(chip, IRS), val); return -EIO; } @@ -610,7 +635,8 @@ static unsigned int azx_single_get_response(struct hda_codec *codec) return azx_readl(chip, IR); udelay(1); } - snd_printd(SFX "get_response timeout: IRS=0x%x\n", azx_readw(chip, IRS)); + snd_printd(SFX "get_response timeout: IRS=0x%x\n", + azx_readw(chip, IRS)); return (unsigned int)-1; } @@ -652,12 +678,18 @@ static unsigned int azx_get_response(struct hda_codec *codec) return azx_rirb_get_response(codec); } +#ifdef CONFIG_SND_HDA_POWER_SAVE +static void azx_power_notify(struct hda_codec *codec); +#endif /* reset codec link */ static int azx_reset(struct azx *chip) { int count; + /* clear STATESTS */ + azx_writeb(chip, STATESTS, STATESTS_INT_MASK); + /* reset controller */ azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~ICH6_GCTL_RESET); @@ -777,18 +809,12 @@ static void azx_stream_stop(struct azx *chip, struct azx_dev *azx_dev) /* - * initialize the chip + * reset and start the controller registers */ static void azx_init_chip(struct azx *chip) { - unsigned char reg; - - /* Clear bits 0-2 of PCI register TCSEL (at offset 0x44) - * TCSEL == Traffic Class Select Register, which sets PCI express QOS - * Ensuring these bits are 0 clears playback static on some HD Audio codecs - */ - pci_read_config_byte (chip->pci, ICH6_PCIREG_TCSEL, ®); - pci_write_config_byte(chip->pci, ICH6_PCIREG_TCSEL, reg & 0xf8); + if (chip->initialized) + return; /* reset controller */ azx_reset(chip); @@ -805,19 +831,45 @@ static void azx_init_chip(struct azx *chip) azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr); azx_writel(chip, DPUBASE, upper_32bit(chip->posbuf.addr)); + chip->initialized = 1; +} + +/* + * initialize the PCI registers + */ +/* update bits in a PCI register byte */ +static void update_pci_byte(struct pci_dev *pci, unsigned int reg, + unsigned char mask, unsigned char val) +{ + unsigned char data; + + pci_read_config_byte(pci, reg, &data); + data &= ~mask; + data |= (val & mask); + pci_write_config_byte(pci, reg, data); +} + +static void azx_init_pci(struct azx *chip) +{ + /* Clear bits 0-2 of PCI register TCSEL (at offset 0x44) + * TCSEL == Traffic Class Select Register, which sets PCI express QOS + * Ensuring these bits are 0 clears playback static on some HD Audio + * codecs + */ + update_pci_byte(chip->pci, ICH6_PCIREG_TCSEL, 0x07, 0); + switch (chip->driver_type) { case AZX_DRIVER_ATI: /* For ATI SB450 azalia HD audio, we need to enable snoop */ - pci_read_config_byte(chip->pci, ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, - ®); - pci_write_config_byte(chip->pci, ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, - (reg & 0xf8) | ATI_SB450_HDAUDIO_ENABLE_SNOOP); + update_pci_byte(chip->pci, + ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, + 0x07, ATI_SB450_HDAUDIO_ENABLE_SNOOP); break; case AZX_DRIVER_NVIDIA: /* For NVIDIA HDA, enable snoop */ - pci_read_config_byte(chip->pci,NVIDIA_HDA_TRANSREG_ADDR, ®); - pci_write_config_byte(chip->pci,NVIDIA_HDA_TRANSREG_ADDR, - (reg & 0xf0) | NVIDIA_HDA_ENABLE_COHBITS); + update_pci_byte(chip->pci, + NVIDIA_HDA_TRANSREG_ADDR, + 0x0f, NVIDIA_HDA_ENABLE_COHBITS); break; } } @@ -857,7 +909,7 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id) /* clear rirb int */ status = azx_readb(chip, RIRBSTS); if (status & RIRB_INT_MASK) { - if (! chip->single_cmd && (status & RIRB_INT_RESPONSE)) + if (!chip->single_cmd && (status & RIRB_INT_RESPONSE)) azx_update_rirb(chip); azx_writeb(chip, RIRBSTS, RIRB_INT_MASK); } @@ -911,9 +963,11 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev) int timeout; /* make sure the run bit is zero for SD */ - azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) & ~SD_CTL_DMA_START); + azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) & + ~SD_CTL_DMA_START); /* reset stream */ - azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) | SD_CTL_STREAM_RESET); + azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) | + SD_CTL_STREAM_RESET); udelay(3); timeout = 300; while (!((val = azx_sd_readb(azx_dev, SD_CTL)) & SD_CTL_STREAM_RESET) && @@ -931,7 +985,7 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev) /* program the stream_tag */ azx_sd_writel(azx_dev, SD_CTL, - (azx_sd_readl(azx_dev, SD_CTL) & ~SD_CTL_STREAM_TAG_MASK) | + (azx_sd_readl(azx_dev, SD_CTL) & ~SD_CTL_STREAM_TAG_MASK)| (azx_dev->stream_tag << SD_CTL_STREAM_TAG_SHIFT)); /* program the length of samples in cyclic buffer */ @@ -951,11 +1005,13 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev) azx_sd_writel(azx_dev, SD_BDLPU, upper_32bit(azx_dev->bdl_addr)); /* enable the position buffer */ - if (! (azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE)) - azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE); + if (!(azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE)) + azx_writel(chip, DPLBASE, + (u32)chip->posbuf.addr |ICH6_DPLBASE_ENABLE); /* set the interrupt enable bits in the descriptor control register */ - azx_sd_writel(azx_dev, SD_CTL, azx_sd_readl(azx_dev, SD_CTL) | SD_INT_MASK); + azx_sd_writel(azx_dev, SD_CTL, + azx_sd_readl(azx_dev, SD_CTL) | SD_INT_MASK); return 0; } @@ -986,8 +1042,12 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model) bus_temp.pci = chip->pci; bus_temp.ops.command = azx_send_cmd; bus_temp.ops.get_response = azx_get_response; +#ifdef CONFIG_SND_HDA_POWER_SAVE + bus_temp.ops.pm_notify = azx_power_notify; +#endif - if ((err = snd_hda_bus_new(chip->card, &bus_temp, &chip->bus)) < 0) + err = snd_hda_bus_new(chip->card, &bus_temp, &chip->bus); + if (err < 0) return err; codecs = audio_codecs = 0; @@ -1038,7 +1098,7 @@ static inline struct azx_dev *azx_assign_device(struct azx *chip, int stream) nums = chip->capture_streams; } for (i = 0; i < nums; i++, dev++) - if (! chip->azx_dev[dev].opened) { + if (!chip->azx_dev[dev].opened) { chip->azx_dev[dev].opened = 1; return &chip->azx_dev[dev]; } @@ -1052,7 +1112,8 @@ static inline void azx_release_device(struct azx_dev *azx_dev) } static struct snd_pcm_hardware azx_pcm_hw = { - .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID | /* No full-resume yet implemented */ @@ -1105,8 +1166,11 @@ static int azx_pcm_open(struct snd_pcm_substream *substream) 128); snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 128); - if ((err = hinfo->ops.open(hinfo, apcm->codec, substream)) < 0) { + snd_hda_power_up(apcm->codec); + err = hinfo->ops.open(hinfo, apcm->codec, substream); + if (err < 0) { azx_release_device(azx_dev); + snd_hda_power_down(apcm->codec); mutex_unlock(&chip->open_mutex); return err; } @@ -1135,13 +1199,16 @@ static int azx_pcm_close(struct snd_pcm_substream *substream) spin_unlock_irqrestore(&chip->reg_lock, flags); azx_release_device(azx_dev); hinfo->ops.close(hinfo, apcm->codec, substream); + snd_hda_power_down(apcm->codec); mutex_unlock(&chip->open_mutex); return 0; } -static int azx_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) +static int azx_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) { - return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); + return snd_pcm_lib_malloc_pages(substream, + params_buffer_bytes(hw_params)); } static int azx_pcm_hw_free(struct snd_pcm_substream *substream) @@ -1175,13 +1242,15 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream) runtime->channels, runtime->format, hinfo->maxbps); - if (! azx_dev->format_val) { - snd_printk(KERN_ERR SFX "invalid format_val, rate=%d, ch=%d, format=%d\n", + if (!azx_dev->format_val) { + snd_printk(KERN_ERR SFX + "invalid format_val, rate=%d, ch=%d, format=%d\n", runtime->rate, runtime->channels, runtime->format); return -EINVAL; } - snd_printdd("azx_pcm_prepare: bufsize=0x%x, fragsize=0x%x, format=0x%x\n", + snd_printdd("azx_pcm_prepare: bufsize=0x%x, fragsize=0x%x, " + "format=0x%x\n", azx_dev->bufsize, azx_dev->fragsize, azx_dev->format_val); azx_setup_periods(azx_dev); azx_setup_controller(chip, azx_dev); @@ -1223,7 +1292,8 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) cmd == SNDRV_PCM_TRIGGER_SUSPEND || cmd == SNDRV_PCM_TRIGGER_STOP) { int timeout = 5000; - while (azx_sd_readb(azx_dev, SD_CTL) & SD_CTL_DMA_START && --timeout) + while ((azx_sd_readb(azx_dev, SD_CTL) & SD_CTL_DMA_START) && + --timeout) ; } return err; @@ -1241,7 +1311,7 @@ static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream) /* use the position buffer */ pos = le32_to_cpu(*azx_dev->posbuf); if (chip->position_fix == POS_FIX_AUTO && - azx_dev->period_intr == 1 && ! pos) { + azx_dev->period_intr == 1 && !pos) { printk(KERN_WARNING "hda-intel: Invalid position buffer, " "using LPIB read method instead.\n"); @@ -1292,7 +1362,8 @@ static int __devinit create_codec_pcm(struct azx *chip, struct hda_codec *codec, snd_assert(cpcm->name, return -EINVAL); err = snd_pcm_new(chip->card, cpcm->name, pcm_dev, - cpcm->stream[0].substreams, cpcm->stream[1].substreams, + cpcm->stream[0].substreams, + cpcm->stream[1].substreams, &pcm); if (err < 0) return err; @@ -1322,26 +1393,27 @@ static int __devinit create_codec_pcm(struct azx *chip, struct hda_codec *codec, static int __devinit azx_pcm_create(struct azx *chip) { - struct list_head *p; struct hda_codec *codec; int c, err; int pcm_dev; - if ((err = snd_hda_build_pcms(chip->bus)) < 0) + err = snd_hda_build_pcms(chip->bus); + if (err < 0) return err; /* create audio PCMs */ pcm_dev = 0; - list_for_each(p, &chip->bus->codec_list) { - codec = list_entry(p, struct hda_codec, list); + list_for_each_entry(codec, &chip->bus->codec_list, list) { for (c = 0; c < codec->num_pcms; c++) { if (codec->pcm_info[c].is_modem) continue; /* create later */ if (pcm_dev >= AZX_MAX_AUDIO_PCMS) { - snd_printk(KERN_ERR SFX "Too many audio PCMs\n"); + snd_printk(KERN_ERR SFX + "Too many audio PCMs\n"); return -EINVAL; } - err = create_codec_pcm(chip, codec, &codec->pcm_info[c], pcm_dev); + err = create_codec_pcm(chip, codec, + &codec->pcm_info[c], pcm_dev); if (err < 0) return err; pcm_dev++; @@ -1350,16 +1422,17 @@ static int __devinit azx_pcm_create(struct azx *chip) /* create modem PCMs */ pcm_dev = AZX_MAX_AUDIO_PCMS; - list_for_each(p, &chip->bus->codec_list) { - codec = list_entry(p, struct hda_codec, list); + list_for_each_entry(codec, &chip->bus->codec_list, list) { for (c = 0; c < codec->num_pcms; c++) { - if (! codec->pcm_info[c].is_modem) + if (!codec->pcm_info[c].is_modem) continue; /* already created */ if (pcm_dev >= AZX_MAX_PCMS) { - snd_printk(KERN_ERR SFX "Too many modem PCMs\n"); + snd_printk(KERN_ERR SFX + "Too many modem PCMs\n"); return -EINVAL; } - err = create_codec_pcm(chip, codec, &codec->pcm_info[c], pcm_dev); + err = create_codec_pcm(chip, codec, + &codec->pcm_info[c], pcm_dev); if (err < 0) return err; chip->pcm[pcm_dev]->dev_class = SNDRV_PCM_CLASS_MODEM; @@ -1386,7 +1459,8 @@ static int __devinit azx_init_stream(struct azx *chip) int i; /* initialize each stream (aka device) - * assign the starting bdl address to each stream (device) and initialize + * assign the starting bdl address to each stream (device) + * and initialize */ for (i = 0; i < chip->num_streams; i++) { unsigned int off = sizeof(u32) * (i * AZX_MAX_FRAG * 4); @@ -1423,6 +1497,46 @@ static int azx_acquire_irq(struct azx *chip, int do_disconnect) } +static void azx_stop_chip(struct azx *chip) +{ + if (!chip->initialized) + return; + + /* disable interrupts */ + azx_int_disable(chip); + azx_int_clear(chip); + + /* disable CORB/RIRB */ + azx_free_cmd_io(chip); + + /* disable position buffer */ + azx_writel(chip, DPLBASE, 0); + azx_writel(chip, DPUBASE, 0); + + chip->initialized = 0; +} + +#ifdef CONFIG_SND_HDA_POWER_SAVE +/* power-up/down the controller */ +static void azx_power_notify(struct hda_codec *codec) +{ + struct azx *chip = codec->bus->private_data; + struct hda_codec *c; + int power_on = 0; + + list_for_each_entry(c, &codec->bus->codec_list, list) { + if (c->power_on) { + power_on = 1; + break; + } + } + if (power_on) + azx_init_chip(chip); + else if (chip->running && power_save_controller) + azx_stop_chip(chip); +} +#endif /* CONFIG_SND_HDA_POWER_SAVE */ + #ifdef CONFIG_PM /* * power management @@ -1436,8 +1550,9 @@ static int azx_suspend(struct pci_dev *pci, pm_message_t state) snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); for (i = 0; i < chip->pcm_devs; i++) snd_pcm_suspend_all(chip->pcm[i]); - snd_hda_suspend(chip->bus, state); - azx_free_cmd_io(chip); + if (chip->initialized) + snd_hda_suspend(chip->bus, state); + azx_stop_chip(chip); if (chip->irq >= 0) { synchronize_irq(chip->irq); free_irq(chip->irq, chip); @@ -1470,7 +1585,11 @@ static int azx_resume(struct pci_dev *pci) chip->msi = 0; if (azx_acquire_irq(chip, 1) < 0) return -EIO; - azx_init_chip(chip); + azx_init_pci(chip); + + if (snd_hda_codecs_inuse(chip->bus)) + azx_init_chip(chip); + snd_hda_resume(chip->bus); snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0; @@ -1485,20 +1604,9 @@ static int azx_free(struct azx *chip) { if (chip->initialized) { int i; - for (i = 0; i < chip->num_streams; i++) azx_stream_stop(chip, &chip->azx_dev[i]); - - /* disable interrupts */ - azx_int_disable(chip); - azx_int_clear(chip); - - /* disable CORB/RIRB */ - azx_free_cmd_io(chip); - - /* disable position buffer */ - azx_writel(chip, DPLBASE, 0); - azx_writel(chip, DPUBASE, 0); + azx_stop_chip(chip); } if (chip->irq >= 0) { @@ -1534,6 +1642,7 @@ static int azx_dev_free(struct snd_device *device) */ static struct snd_pci_quirk position_fix_list[] __devinitdata = { SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_NONE), + SND_PCI_QUIRK(0x1028, 0x01de, "Dell Precision 390", POS_FIX_NONE), {} }; @@ -1544,7 +1653,7 @@ static int __devinit check_position_fix(struct azx *chip, int fix) if (fix == POS_FIX_AUTO) { q = snd_pci_quirk_lookup(chip->pci, position_fix_list); if (q) { - snd_printdd(KERN_INFO + printk(KERN_INFO "hda_intel: position_fix set to %d " "for device %04x:%04x\n", q->value, q->subvendor, q->subdevice); @@ -1555,6 +1664,36 @@ static int __devinit check_position_fix(struct azx *chip, int fix) } /* + * black-lists for probe_mask + */ +static struct snd_pci_quirk probe_mask_list[] __devinitdata = { + /* Thinkpad often breaks the controller communication when accessing + * to the non-working (or non-existing) modem codec slot. + */ + SND_PCI_QUIRK(0x1014, 0x05b7, "Thinkpad Z60", 0x01), + SND_PCI_QUIRK(0x17aa, 0x2010, "Thinkpad X/T/R60", 0x01), + SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X/T/R61", 0x01), + {} +}; + +static void __devinit check_probe_mask(struct azx *chip) +{ + const struct snd_pci_quirk *q; + + if (probe_mask == -1) { + q = snd_pci_quirk_lookup(chip->pci, probe_mask_list); + if (q) { + printk(KERN_INFO + "hda_intel: probe_mask set to 0x%x " + "for device %04x:%04x\n", + q->value, q->subvendor, q->subdevice); + probe_mask = q->value; + } + } +} + + +/* * constructor */ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, @@ -1589,6 +1728,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, chip->msi = enable_msi; chip->position_fix = check_position_fix(chip, position_fix); + check_probe_mask(chip); chip->single_cmd = single_cmd; @@ -1650,37 +1790,43 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, break; } chip->num_streams = chip->playback_streams + chip->capture_streams; - chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev), GFP_KERNEL); + chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev), + GFP_KERNEL); if (!chip->azx_dev) { snd_printk(KERN_ERR "cannot malloc azx_dev\n"); goto errout; } /* allocate memory for the BDL for each stream */ - if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), - BDL_SIZE, &chip->bdl)) < 0) { + err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(chip->pci), + BDL_SIZE, &chip->bdl); + if (err < 0) { snd_printk(KERN_ERR SFX "cannot allocate BDL\n"); goto errout; } /* allocate memory for the position buffer */ - if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), - chip->num_streams * 8, &chip->posbuf)) < 0) { + err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(chip->pci), + chip->num_streams * 8, &chip->posbuf); + if (err < 0) { snd_printk(KERN_ERR SFX "cannot allocate posbuf\n"); goto errout; } /* allocate CORB/RIRB */ - if (! chip->single_cmd) - if ((err = azx_alloc_cmd_io(chip)) < 0) + if (!chip->single_cmd) { + err = azx_alloc_cmd_io(chip); + if (err < 0) goto errout; + } /* initialize streams */ azx_init_stream(chip); /* initialize chip */ + azx_init_pci(chip); azx_init_chip(chip); - chip->initialized = 1; - /* codec detection */ if (!chip->codec_mask) { snd_printk(KERN_ERR SFX "no codecs found!\n"); @@ -1688,14 +1834,16 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, goto errout; } - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) <0) { + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); + if (err <0) { snd_printk(KERN_ERR SFX "Error creating device [card]!\n"); goto errout; } strcpy(card->driver, "HDA-Intel"); strcpy(card->shortname, driver_short_names[chip->driver_type]); - sprintf(card->longname, "%s at 0x%lx irq %i", card->shortname, chip->addr, chip->irq); + sprintf(card->longname, "%s at 0x%lx irq %i", + card->shortname, chip->addr, chip->irq); *rchip = chip; return 0; @@ -1705,7 +1853,21 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, return err; } -static int __devinit azx_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) +static void power_down_all_codecs(struct azx *chip) +{ +#ifdef CONFIG_SND_HDA_POWER_SAVE + /* The codecs were powered up in snd_hda_codec_new(). + * Now all initialization done, so turn them down if possible + */ + struct hda_codec *codec; + list_for_each_entry(codec, &chip->bus->codec_list, list) { + snd_hda_power_down(codec); + } +#endif +} + +static int __devinit azx_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { struct snd_card *card; struct azx *chip; @@ -1725,31 +1887,37 @@ static int __devinit azx_probe(struct pci_dev *pci, const struct pci_device_id * card->private_data = chip; /* create codec instances */ - if ((err = azx_codec_create(chip, model)) < 0) { + err = azx_codec_create(chip, model); + if (err < 0) { snd_card_free(card); return err; } /* create PCM streams */ - if ((err = azx_pcm_create(chip)) < 0) { + err = azx_pcm_create(chip); + if (err < 0) { snd_card_free(card); return err; } /* create mixer controls */ - if ((err = azx_mixer_create(chip)) < 0) { + err = azx_mixer_create(chip); + if (err < 0) { snd_card_free(card); return err; } snd_card_set_dev(card, &pci->dev); - if ((err = snd_card_register(card)) < 0) { + err = snd_card_register(card); + if (err < 0) { snd_card_free(card); return err; } pci_set_drvdata(pci, card); + chip->running = 1; + power_down_all_codecs(chip); return err; } @@ -1791,6 +1959,10 @@ static struct pci_device_id azx_ids[] = { { 0x10de, 0x0775, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP77 */ { 0x10de, 0x0776, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP77 */ { 0x10de, 0x0777, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP77 */ + { 0x10de, 0x0ac0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP79 */ + { 0x10de, 0x0ac1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP79 */ + { 0x10de, 0x0ac2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP79 */ + { 0x10de, 0x0ac3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP79 */ { 0, } }; MODULE_DEVICE_TABLE(pci, azx_ids); diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index f91ea5ec9f6..a79d0ed5469 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -26,7 +26,8 @@ /* * for mixer controls */ -#define HDA_COMPOSE_AMP_VAL(nid,chs,idx,dir) ((nid) | ((chs)<<16) | ((dir)<<18) | ((idx)<<19)) +#define HDA_COMPOSE_AMP_VAL(nid,chs,idx,dir) \ + ((nid) | ((chs)<<16) | ((dir)<<18) | ((idx)<<19)) /* mono volume with index (index=0,1,...) (channel=1,2) */ #define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ @@ -64,18 +65,35 @@ #define HDA_CODEC_MUTE(xname, nid, xindex, direction) \ HDA_CODEC_MUTE_MONO(xname, nid, 3, xindex, direction) -int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); -int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); -int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); -int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, unsigned int size, unsigned int __user *tlv); -int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); -int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); -int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); +int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo); +int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, + unsigned int size, unsigned int __user *tlv); +int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo); +int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); /* lowlevel accessor with caching; use carefully */ int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int index); int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int idx, int mask, int val); +int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid, + int dir, int idx, int mask, int val); +#ifdef SND_HDA_NEEDS_RESUME +void snd_hda_codec_resume_amp(struct hda_codec *codec); +#endif + +/* amp value bits */ +#define HDA_AMP_MUTE 0x80 +#define HDA_AMP_UNMUTE 0x00 +#define HDA_AMP_VOLMASK 0x7f /* mono switch binding multiple inputs */ #define HDA_BIND_MUTE_MONO(xname, nid, channel, indices, direction) \ @@ -86,11 +104,61 @@ int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, indices, direction) } /* stereo switch binding multiple inputs */ -#define HDA_BIND_MUTE(xname,nid,indices,dir) HDA_BIND_MUTE_MONO(xname,nid,3,indices,dir) +#define HDA_BIND_MUTE(xname,nid,indices,dir) \ + HDA_BIND_MUTE_MONO(xname,nid,3,indices,dir) + +int snd_hda_mixer_bind_switch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + +/* more generic bound controls */ +struct hda_ctl_ops { + snd_kcontrol_info_t *info; + snd_kcontrol_get_t *get; + snd_kcontrol_put_t *put; + snd_kcontrol_tlv_rw_t *tlv; +}; -int snd_hda_mixer_bind_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); -int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); +extern struct hda_ctl_ops snd_hda_bind_vol; /* for bind-volume with TLV */ +extern struct hda_ctl_ops snd_hda_bind_sw; /* for bind-switch */ +struct hda_bind_ctls { + struct hda_ctl_ops *ops; + long values[]; +}; + +int snd_hda_mixer_bind_ctls_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo); +int snd_hda_mixer_bind_ctls_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_hda_mixer_bind_ctls_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_hda_mixer_bind_tlv(struct snd_kcontrol *kcontrol, int op_flag, + unsigned int size, unsigned int __user *tlv); + +#define HDA_BIND_VOL(xname, bindrec) \ + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\ + SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ + SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK,\ + .info = snd_hda_mixer_bind_ctls_info,\ + .get = snd_hda_mixer_bind_ctls_get,\ + .put = snd_hda_mixer_bind_ctls_put,\ + .tlv = { .c = snd_hda_mixer_bind_tlv },\ + .private_value = (long) (bindrec) } +#define HDA_BIND_SW(xname, bindrec) \ + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER,\ + .name = xname, \ + .info = snd_hda_mixer_bind_ctls_info,\ + .get = snd_hda_mixer_bind_ctls_get,\ + .put = snd_hda_mixer_bind_ctls_put,\ + .private_value = (long) (bindrec) } + +/* + * SPDIF I/O + */ int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid); int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid); @@ -107,8 +175,10 @@ struct hda_input_mux { struct hda_input_mux_item items[HDA_MAX_NUM_INPUTS]; }; -int snd_hda_input_mux_info(const struct hda_input_mux *imux, struct snd_ctl_elem_info *uinfo); -int snd_hda_input_mux_put(struct hda_codec *codec, const struct hda_input_mux *imux, +int snd_hda_input_mux_info(const struct hda_input_mux *imux, + struct snd_ctl_elem_info *uinfo); +int snd_hda_input_mux_put(struct hda_codec *codec, + const struct hda_input_mux *imux, struct snd_ctl_elem_value *ucontrol, hda_nid_t nid, unsigned int *cur_val); @@ -120,13 +190,19 @@ struct hda_channel_mode { const struct hda_verb *sequence; }; -int snd_hda_ch_mode_info(struct hda_codec *codec, struct snd_ctl_elem_info *uinfo, - const struct hda_channel_mode *chmode, int num_chmodes); -int snd_hda_ch_mode_get(struct hda_codec *codec, struct snd_ctl_elem_value *ucontrol, - const struct hda_channel_mode *chmode, int num_chmodes, +int snd_hda_ch_mode_info(struct hda_codec *codec, + struct snd_ctl_elem_info *uinfo, + const struct hda_channel_mode *chmode, + int num_chmodes); +int snd_hda_ch_mode_get(struct hda_codec *codec, + struct snd_ctl_elem_value *ucontrol, + const struct hda_channel_mode *chmode, + int num_chmodes, int max_channels); -int snd_hda_ch_mode_put(struct hda_codec *codec, struct snd_ctl_elem_value *ucontrol, - const struct hda_channel_mode *chmode, int num_chmodes, +int snd_hda_ch_mode_put(struct hda_codec *codec, + struct snd_ctl_elem_value *ucontrol, + const struct hda_channel_mode *chmode, + int num_chmodes, int *max_channelsp); /* @@ -146,20 +222,25 @@ struct hda_multi_out { int dig_out_used; /* current usage of digital out (HDA_DIG_XXX) */ }; -int snd_hda_multi_out_dig_open(struct hda_codec *codec, struct hda_multi_out *mout); -int snd_hda_multi_out_dig_close(struct hda_codec *codec, struct hda_multi_out *mout); +int snd_hda_multi_out_dig_open(struct hda_codec *codec, + struct hda_multi_out *mout); +int snd_hda_multi_out_dig_close(struct hda_codec *codec, + struct hda_multi_out *mout); int snd_hda_multi_out_dig_prepare(struct hda_codec *codec, struct hda_multi_out *mout, unsigned int stream_tag, unsigned int format, struct snd_pcm_substream *substream); -int snd_hda_multi_out_analog_open(struct hda_codec *codec, struct hda_multi_out *mout, +int snd_hda_multi_out_analog_open(struct hda_codec *codec, + struct hda_multi_out *mout, struct snd_pcm_substream *substream); -int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, struct hda_multi_out *mout, +int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, + struct hda_multi_out *mout, unsigned int stream_tag, unsigned int format, struct snd_pcm_substream *substream); -int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec, struct hda_multi_out *mout); +int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec, + struct hda_multi_out *mout); /* * generic codec parser @@ -181,16 +262,8 @@ static inline int snd_hda_codec_proc_new(struct hda_codec *codec) { return 0; } int snd_hda_check_board_config(struct hda_codec *codec, int num_configs, const char **modelnames, const struct snd_pci_quirk *pci_list); -int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew); - -/* - * power management - */ -#ifdef CONFIG_PM -int snd_hda_resume_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew); -int snd_hda_resume_spdif_out(struct hda_codec *codec); -int snd_hda_resume_spdif_in(struct hda_codec *codec); -#endif +int snd_hda_add_new_ctls(struct hda_codec *codec, + struct snd_kcontrol_new *knew); /* * unsolicited event handler @@ -232,7 +305,9 @@ extern const char *auto_pin_cfg_labels[AUTO_PIN_LAST]; struct auto_pin_cfg { int line_outs; - hda_nid_t line_out_pins[5]; /* sorted in the order of Front/Surr/CLFE/Side */ + hda_nid_t line_out_pins[5]; /* sorted in the order of + * Front/Surr/CLFE/Side + */ int speaker_outs; hda_nid_t speaker_pins[5]; int hp_outs; @@ -243,13 +318,19 @@ struct auto_pin_cfg { hda_nid_t dig_in_pin; }; -#define get_defcfg_connect(cfg) ((cfg & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT) -#define get_defcfg_association(cfg) ((cfg & AC_DEFCFG_DEF_ASSOC) >> AC_DEFCFG_ASSOC_SHIFT) -#define get_defcfg_location(cfg) ((cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT) -#define get_defcfg_sequence(cfg) (cfg & AC_DEFCFG_SEQUENCE) -#define get_defcfg_device(cfg) ((cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT) - -int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *cfg, +#define get_defcfg_connect(cfg) \ + ((cfg & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT) +#define get_defcfg_association(cfg) \ + ((cfg & AC_DEFCFG_DEF_ASSOC) >> AC_DEFCFG_ASSOC_SHIFT) +#define get_defcfg_location(cfg) \ + ((cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT) +#define get_defcfg_sequence(cfg) \ + (cfg & AC_DEFCFG_SEQUENCE) +#define get_defcfg_device(cfg) \ + ((cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT) + +int snd_hda_parse_pin_def_config(struct hda_codec *codec, + struct auto_pin_cfg *cfg, hda_nid_t *ignore_nids); /* amp values */ @@ -280,4 +361,32 @@ static inline u32 get_wcaps(struct hda_codec *codec, hda_nid_t nid) int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, unsigned int caps); +/* + * hwdep interface + */ +int snd_hda_create_hwdep(struct hda_codec *codec); + +/* + * power-management + */ + +#ifdef CONFIG_SND_HDA_POWER_SAVE +void snd_hda_schedule_power_save(struct hda_codec *codec); + +struct hda_amp_list { + hda_nid_t nid; + unsigned char dir; + unsigned char idx; +}; + +struct hda_loopback_check { + struct hda_amp_list *amplist; + int power_on; +}; + +int snd_hda_check_amp_list_power(struct hda_codec *codec, + struct hda_loopback_check *check, + hda_nid_t nid); +#endif /* CONFIG_SND_HDA_POWER_SAVE */ + #endif /* __SOUND_HDA_LOCAL_H */ diff --git a/sound/pci/hda/hda_patch.h b/sound/pci/hda/hda_patch.h index 9f9e9ae44a9..f5c23bb16d7 100644 --- a/sound/pci/hda/hda_patch.h +++ b/sound/pci/hda/hda_patch.h @@ -20,13 +20,29 @@ extern struct hda_codec_preset snd_hda_preset_conexant[]; extern struct hda_codec_preset snd_hda_preset_via[]; static const struct hda_codec_preset *hda_preset_tables[] = { +#ifdef CONFIG_SND_HDA_CODEC_REALTEK snd_hda_preset_realtek, +#endif +#ifdef CONFIG_SND_HDA_CODEC_CMEDIA snd_hda_preset_cmedia, +#endif +#ifdef CONFIG_SND_HDA_CODEC_ANALOG snd_hda_preset_analog, +#endif +#ifdef CONFIG_SND_HDA_CODEC_SIGMATEL snd_hda_preset_sigmatel, +#endif +#ifdef CONFIG_SND_HDA_CODEC_SI3054 snd_hda_preset_si3054, +#endif +#ifdef CONFIG_SND_HDA_CODEC_ATIHDMI snd_hda_preset_atihdmi, +#endif +#ifdef CONFIG_SND_HDA_CODEC_CONEXANT snd_hda_preset_conexant, +#endif +#ifdef CONFIG_SND_HDA_CODEC_VIA snd_hda_preset_via, +#endif NULL }; diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index ac15066fd30..e94944f34ff 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -58,7 +58,8 @@ static void print_amp_caps(struct snd_info_buffer *buffer, snd_iprintf(buffer, "N/A\n"); return; } - snd_iprintf(buffer, "ofs=0x%02x, nsteps=0x%02x, stepsize=0x%02x, mute=%x\n", + snd_iprintf(buffer, "ofs=0x%02x, nsteps=0x%02x, stepsize=0x%02x, " + "mute=%x\n", caps & AC_AMPCAP_OFFSET, (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT, (caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT, @@ -76,11 +77,13 @@ static void print_amp_vals(struct snd_info_buffer *buffer, for (i = 0; i < indices; i++) { snd_iprintf(buffer, " ["); if (stereo) { - val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, + val = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_AMP_GAIN_MUTE, AC_AMP_GET_LEFT | dir | i); snd_iprintf(buffer, "0x%02x ", val); } - val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, + val = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_AMP_GAIN_MUTE, AC_AMP_GET_RIGHT | dir | i); snd_iprintf(buffer, "0x%02x]", val); } @@ -237,7 +240,8 @@ static void print_pin_caps(struct snd_info_buffer *buffer, } -static void print_codec_info(struct snd_info_entry *entry, struct snd_info_buffer *buffer) +static void print_codec_info(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) { struct hda_codec *codec = entry->private_data; char buf[32]; @@ -258,6 +262,7 @@ static void print_codec_info(struct snd_info_entry *entry, struct snd_info_buffe if (! codec->afg) return; + snd_hda_power_up(codec); snd_iprintf(buffer, "Default PCM:\n"); print_pcm_caps(buffer, codec, codec->afg); snd_iprintf(buffer, "Default Amp-In caps: "); @@ -268,12 +273,15 @@ static void print_codec_info(struct snd_info_entry *entry, struct snd_info_buffe nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid); if (! nid || nodes < 0) { snd_iprintf(buffer, "Invalid AFG subtree\n"); + snd_hda_power_down(codec); return; } for (i = 0; i < nodes; i++, nid++) { - unsigned int wid_caps = snd_hda_param_read(codec, nid, - AC_PAR_AUDIO_WIDGET_CAP); - unsigned int wid_type = (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; + unsigned int wid_caps = + snd_hda_param_read(codec, nid, + AC_PAR_AUDIO_WIDGET_CAP); + unsigned int wid_type = + (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; int conn_len = 0; hda_nid_t conn[HDA_MAX_CONNECTIONS]; @@ -313,7 +321,9 @@ static void print_codec_info(struct snd_info_entry *entry, struct snd_info_buffe if (wid_type == AC_WID_PIN) { unsigned int pinctls; print_pin_caps(buffer, codec, nid); - pinctls = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + pinctls = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, + 0); snd_iprintf(buffer, " Pin-ctls: 0x%02x:", pinctls); if (pinctls & AC_PINCTL_IN_EN) snd_iprintf(buffer, " IN"); @@ -333,7 +343,8 @@ static void print_codec_info(struct snd_info_entry *entry, struct snd_info_buffe if (wid_caps & AC_WCAP_POWER) snd_iprintf(buffer, " Power: 0x%x\n", snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_POWER_STATE, 0)); + AC_VERB_GET_POWER_STATE, + 0)); if (wid_caps & AC_WCAP_CONN_LIST) { int c, curr = -1; @@ -350,6 +361,7 @@ static void print_codec_info(struct snd_info_entry *entry, struct snd_info_buffe snd_iprintf(buffer, "\n"); } } + snd_hda_power_down(codec); } /* diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 4d7f8d11ad7..54cfd4526d2 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -73,6 +73,12 @@ struct ad198x_spec { struct snd_kcontrol_new *kctl_alloc; struct hda_input_mux private_imux; hda_nid_t private_dac_nids[4]; + + unsigned int jack_present :1; + +#ifdef CONFIG_SND_HDA_POWER_SAVE + struct hda_loopback_check loopback; +#endif }; /* @@ -144,6 +150,14 @@ static int ad198x_build_controls(struct hda_codec *codec) return 0; } +#ifdef CONFIG_SND_HDA_POWER_SAVE +static int ad198x_check_power_status(struct hda_codec *codec, hda_nid_t nid) +{ + struct ad198x_spec *spec = codec->spec; + return snd_hda_check_amp_list_power(codec, &spec->loopback, nid); +} +#endif + /* * Analog playback callbacks */ @@ -318,30 +332,13 @@ static void ad198x_free(struct hda_codec *codec) kfree(codec->spec); } -#ifdef CONFIG_PM -static int ad198x_resume(struct hda_codec *codec) -{ - struct ad198x_spec *spec = codec->spec; - int i; - - codec->patch_ops.init(codec); - for (i = 0; i < spec->num_mixers; i++) - snd_hda_resume_ctls(codec, spec->mixers[i]); - if (spec->multiout.dig_out_nid) - snd_hda_resume_spdif_out(codec); - if (spec->dig_in_nid) - snd_hda_resume_spdif_in(codec); - return 0; -} -#endif - static struct hda_codec_ops ad198x_patch_ops = { .build_controls = ad198x_build_controls, .build_pcms = ad198x_build_pcms, .init = ad198x_init, .free = ad198x_free, -#ifdef CONFIG_PM - .resume = ad198x_resume, +#ifdef CONFIG_SND_HDA_POWER_SAVE + .check_power_status = ad198x_check_power_status, #endif }; @@ -350,15 +347,7 @@ static struct hda_codec_ops ad198x_patch_ops = { * EAPD control * the private value = nid | (invert << 8) */ -static int ad198x_eapd_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 ad198x_eapd_info snd_ctl_boolean_mono_info static int ad198x_eapd_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -384,12 +373,12 @@ static int ad198x_eapd_put(struct snd_kcontrol *kcontrol, eapd = ucontrol->value.integer.value[0]; if (invert) eapd = !eapd; - if (eapd == spec->cur_eapd && ! codec->in_resume) + if (eapd == spec->cur_eapd) return 0; spec->cur_eapd = eapd; - snd_hda_codec_write(codec, nid, - 0, AC_VERB_SET_EAPD_BTLENABLE, - eapd ? 0x02 : 0x00); + snd_hda_codec_write_cache(codec, nid, + 0, AC_VERB_SET_EAPD_BTLENABLE, + eapd ? 0x02 : 0x00); return 1; } @@ -430,94 +419,36 @@ static struct hda_input_mux ad1986a_capture_source = { }, }; -/* - * PCM control - * - * bind volumes/mutes of 3 DACs as a single PCM control for simplicity - */ - -#define ad1986a_pcm_amp_vol_info snd_hda_mixer_amp_volume_info - -static int ad1986a_pcm_amp_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *ad = codec->spec; - - mutex_lock(&ad->amp_mutex); - snd_hda_mixer_amp_volume_get(kcontrol, ucontrol); - mutex_unlock(&ad->amp_mutex); - return 0; -} - -static int ad1986a_pcm_amp_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *ad = codec->spec; - int i, change = 0; - - mutex_lock(&ad->amp_mutex); - for (i = 0; i < ARRAY_SIZE(ad1986a_dac_nids); i++) { - kcontrol->private_value = HDA_COMPOSE_AMP_VAL(ad1986a_dac_nids[i], 3, 0, HDA_OUTPUT); - change |= snd_hda_mixer_amp_volume_put(kcontrol, ucontrol); - } - kcontrol->private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT); - mutex_unlock(&ad->amp_mutex); - return change; -} - -#define ad1986a_pcm_amp_sw_info snd_hda_mixer_amp_switch_info -static int ad1986a_pcm_amp_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *ad = codec->spec; - - mutex_lock(&ad->amp_mutex); - snd_hda_mixer_amp_switch_get(kcontrol, ucontrol); - mutex_unlock(&ad->amp_mutex); - return 0; -} - -static int ad1986a_pcm_amp_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *ad = codec->spec; - int i, change = 0; +static struct hda_bind_ctls ad1986a_bind_pcm_vol = { + .ops = &snd_hda_bind_vol, + .values = { + HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(AD1986A_SURR_DAC, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(AD1986A_CLFE_DAC, 3, 0, HDA_OUTPUT), + 0 + }, +}; - mutex_lock(&ad->amp_mutex); - for (i = 0; i < ARRAY_SIZE(ad1986a_dac_nids); i++) { - kcontrol->private_value = HDA_COMPOSE_AMP_VAL(ad1986a_dac_nids[i], 3, 0, HDA_OUTPUT); - change |= snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); - } - kcontrol->private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT); - mutex_unlock(&ad->amp_mutex); - return change; -} +static struct hda_bind_ctls ad1986a_bind_pcm_sw = { + .ops = &snd_hda_bind_sw, + .values = { + HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(AD1986A_SURR_DAC, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(AD1986A_CLFE_DAC, 3, 0, HDA_OUTPUT), + 0 + }, +}; /* * mixers */ static struct snd_kcontrol_new ad1986a_mixers[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "PCM Playback Volume", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | - SNDRV_CTL_ELEM_ACCESS_TLV_READ | - SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, - .info = ad1986a_pcm_amp_vol_info, - .get = ad1986a_pcm_amp_vol_get, - .put = ad1986a_pcm_amp_vol_put, - .tlv = { .c = snd_hda_mixer_amp_tlv }, - .private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT) - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "PCM Playback Switch", - .info = ad1986a_pcm_amp_sw_info, - .get = ad1986a_pcm_amp_sw_get, - .put = ad1986a_pcm_amp_sw_put, - .private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT) - }, + /* + * bind volumes/mutes of 3 DACs as a single PCM control for simplicity + */ + HDA_BIND_VOL("PCM Playback Volume", &ad1986a_bind_pcm_vol), + HDA_BIND_SW("PCM Playback Switch", &ad1986a_bind_pcm_sw), HDA_CODEC_VOLUME("Front Playback Volume", 0x1b, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x1c, 0x0, HDA_OUTPUT), @@ -569,13 +500,30 @@ static struct snd_kcontrol_new ad1986a_3st_mixers[] = { /* laptop model - 2ch only */ static hda_nid_t ad1986a_laptop_dac_nids[1] = { AD1986A_FRONT_DAC }; +/* master controls both pins 0x1a and 0x1b */ +static struct hda_bind_ctls ad1986a_laptop_master_vol = { + .ops = &snd_hda_bind_vol, + .values = { + HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), + 0, + }, +}; + +static struct hda_bind_ctls ad1986a_laptop_master_sw = { + .ops = &snd_hda_bind_sw, + .values = { + HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), + 0, + }, +}; + static struct snd_kcontrol_new ad1986a_laptop_mixers[] = { HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Master Playback Volume", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Master Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - /* HDA_CODEC_VOLUME("Headphone Playback Volume", 0x1a, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT), */ + HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol), + HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw), HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT), @@ -603,68 +551,114 @@ static struct snd_kcontrol_new ad1986a_laptop_mixers[] = { /* laptop-eapd model - 2ch only */ -/* master controls both pins 0x1a and 0x1b */ -static int ad1986a_laptop_master_vol_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static struct hda_input_mux ad1986a_laptop_eapd_capture_source = { + .num_items = 3, + .items = { + { "Mic", 0x0 }, + { "Internal Mic", 0x4 }, + { "Mix", 0x5 }, + }, +}; + +static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = { + HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol), + HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw), + HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Source", + .info = ad198x_mux_enum_info, + .get = ad198x_mux_enum_get, + .put = ad198x_mux_enum_put, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "External Amplifier", + .info = ad198x_eapd_info, + .get = ad198x_eapd_get, + .put = ad198x_eapd_put, + .private_value = 0x1b | (1 << 8), /* port-D, inversed */ + }, + { } /* end */ +}; + +/* laptop-automute - 2ch only */ + +static void ad1986a_update_hp(struct hda_codec *codec) { - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - long *valp = ucontrol->value.integer.value; - int change; + struct ad198x_spec *spec = codec->spec; + unsigned int mute; - change = snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_OUTPUT, 0, - 0x7f, valp[0] & 0x7f); - change |= snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_OUTPUT, 0, - 0x7f, valp[1] & 0x7f); - snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0, - 0x7f, valp[0] & 0x7f); - snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0, - 0x7f, valp[1] & 0x7f); - return change; + if (spec->jack_present) + mute = HDA_AMP_MUTE; /* mute internal speaker */ + else + /* unmute internal speaker if necessary */ + mute = snd_hda_codec_amp_read(codec, 0x1a, 0, HDA_OUTPUT, 0); + snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); } -static int ad1986a_laptop_master_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static void ad1986a_hp_automute(struct hda_codec *codec) +{ + struct ad198x_spec *spec = codec->spec; + unsigned int present; + + present = snd_hda_codec_read(codec, 0x1a, 0, AC_VERB_GET_PIN_SENSE, 0); + spec->jack_present = (present & 0x80000000) != 0; + ad1986a_update_hp(codec); +} + +#define AD1986A_HP_EVENT 0x37 + +static void ad1986a_hp_unsol_event(struct hda_codec *codec, unsigned int res) +{ + if ((res >> 26) != AD1986A_HP_EVENT) + return; + ad1986a_hp_automute(codec); +} + +static int ad1986a_hp_init(struct hda_codec *codec) +{ + ad198x_init(codec); + ad1986a_hp_automute(codec); + return 0; +} + +/* bind hp and internal speaker mute (with plug check) */ +static int ad1986a_hp_master_sw_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); long *valp = ucontrol->value.integer.value; int change; change = snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_OUTPUT, 0, - 0x80, valp[0] ? 0 : 0x80); + HDA_AMP_MUTE, + valp[0] ? 0 : HDA_AMP_MUTE); change |= snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_OUTPUT, 0, - 0x80, valp[1] ? 0 : 0x80); - snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0, - 0x80, valp[0] ? 0 : 0x80); - snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0, - 0x80, valp[1] ? 0 : 0x80); + HDA_AMP_MUTE, + valp[1] ? 0 : HDA_AMP_MUTE); + if (change) + ad1986a_update_hp(codec); return change; } -static struct hda_input_mux ad1986a_laptop_eapd_capture_source = { - .num_items = 3, - .items = { - { "Mic", 0x0 }, - { "Internal Mic", 0x4 }, - { "Mix", 0x5 }, - }, -}; - -static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Volume", - .info = snd_hda_mixer_amp_volume_info, - .get = snd_hda_mixer_amp_volume_get, - .put = ad1986a_laptop_master_vol_put, - .tlv = { .c = snd_hda_mixer_amp_tlv }, - .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), - }, +static struct snd_kcontrol_new ad1986a_laptop_automute_mixers[] = { + HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", .info = snd_hda_mixer_amp_switch_info, .get = snd_hda_mixer_amp_switch_get, - .put = ad1986a_laptop_master_sw_put, + .put = ad1986a_hp_master_sw_put, .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), }, HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), @@ -674,6 +668,8 @@ static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = { HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Beep Playback Volume", 0x18, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Beep Playback Switch", 0x18, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT), { @@ -807,12 +803,20 @@ static struct hda_verb ad1986a_ultra_init[] = { { } /* end */ }; +/* pin sensing on HP jack */ +static struct hda_verb ad1986a_hp_init_verbs[] = { + {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_HP_EVENT}, + {} +}; + + /* models */ enum { AD1986A_6STACK, AD1986A_3STACK, AD1986A_LAPTOP, AD1986A_LAPTOP_EAPD, + AD1986A_LAPTOP_AUTOMUTE, AD1986A_ULTRA, AD1986A_MODELS }; @@ -822,6 +826,7 @@ static const char *ad1986a_models[AD1986A_MODELS] = { [AD1986A_3STACK] = "3stack", [AD1986A_LAPTOP] = "laptop", [AD1986A_LAPTOP_EAPD] = "laptop-eapd", + [AD1986A_LAPTOP_AUTOMUTE] = "laptop-automute", [AD1986A_ULTRA] = "ultra", }; @@ -850,11 +855,22 @@ static struct snd_pci_quirk ad1986a_cfg_tbl[] = { SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA), SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP), SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_3STACK), - SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_LAPTOP_EAPD), + SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_LAPTOP_AUTOMUTE), SND_PCI_QUIRK(0x17c0, 0x2017, "Samsung M50", AD1986A_LAPTOP), {} }; +#ifdef CONFIG_SND_HDA_POWER_SAVE +static struct hda_amp_list ad1986a_loopbacks[] = { + { 0x13, HDA_OUTPUT, 0 }, /* Mic */ + { 0x14, HDA_OUTPUT, 0 }, /* Phone */ + { 0x15, HDA_OUTPUT, 0 }, /* CD */ + { 0x16, HDA_OUTPUT, 0 }, /* Aux */ + { 0x17, HDA_OUTPUT, 0 }, /* Line */ + { } /* end */ +}; +#endif + static int patch_ad1986a(struct hda_codec *codec) { struct ad198x_spec *spec; @@ -864,7 +880,6 @@ static int patch_ad1986a(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; - mutex_init(&spec->amp_mutex); codec->spec = spec; spec->multiout.max_channels = 6; @@ -879,6 +894,9 @@ static int patch_ad1986a(struct hda_codec *codec) spec->mixers[0] = ad1986a_mixers; spec->num_init_verbs = 1; spec->init_verbs[0] = ad1986a_init_verbs; +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = ad1986a_loopbacks; +#endif codec->patch_ops = ad198x_patch_ops; @@ -914,6 +932,19 @@ static int patch_ad1986a(struct hda_codec *codec) spec->multiout.dig_out_nid = 0; spec->input_mux = &ad1986a_laptop_eapd_capture_source; break; + case AD1986A_LAPTOP_AUTOMUTE: + spec->mixers[0] = ad1986a_laptop_automute_mixers; + spec->num_init_verbs = 3; + spec->init_verbs[1] = ad1986a_eapd_init_verbs; + spec->init_verbs[2] = ad1986a_hp_init_verbs; + spec->multiout.max_channels = 2; + spec->multiout.num_dacs = 1; + spec->multiout.dac_nids = ad1986a_laptop_dac_nids; + spec->multiout.dig_out_nid = 0; + spec->input_mux = &ad1986a_laptop_eapd_capture_source; + codec->patch_ops.unsol_event = ad1986a_hp_unsol_event; + codec->patch_ops.init = ad1986a_hp_init; + break; case AD1986A_ULTRA: spec->mixers[0] = ad1986a_laptop_eapd_mixers; spec->num_init_verbs = 2; @@ -982,8 +1013,9 @@ static int ad1983_spdif_route_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ if (spec->spdif_route != ucontrol->value.enumerated.item[0]) { spec->spdif_route = ucontrol->value.enumerated.item[0]; - snd_hda_codec_write(codec, spec->multiout.dig_out_nid, 0, - AC_VERB_SET_CONNECT_SEL, spec->spdif_route); + snd_hda_codec_write_cache(codec, spec->multiout.dig_out_nid, 0, + AC_VERB_SET_CONNECT_SEL, + spec->spdif_route); return 1; } return 0; @@ -1063,6 +1095,13 @@ static struct hda_verb ad1983_init_verbs[] = { { } /* end */ }; +#ifdef CONFIG_SND_HDA_POWER_SAVE +static struct hda_amp_list ad1983_loopbacks[] = { + { 0x12, HDA_OUTPUT, 0 }, /* Mic */ + { 0x13, HDA_OUTPUT, 0 }, /* Line */ + { } /* end */ +}; +#endif static int patch_ad1983(struct hda_codec *codec) { @@ -1072,7 +1111,6 @@ static int patch_ad1983(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; - mutex_init(&spec->amp_mutex); codec->spec = spec; spec->multiout.max_channels = 2; @@ -1088,6 +1126,9 @@ static int patch_ad1983(struct hda_codec *codec) spec->num_init_verbs = 1; spec->init_verbs[0] = ad1983_init_verbs; spec->spdif_route = 0; +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = ad1983_loopbacks; +#endif codec->patch_ops = ad198x_patch_ops; @@ -1211,6 +1252,17 @@ static struct hda_verb ad1981_init_verbs[] = { { } /* end */ }; +#ifdef CONFIG_SND_HDA_POWER_SAVE +static struct hda_amp_list ad1981_loopbacks[] = { + { 0x12, HDA_OUTPUT, 0 }, /* Front Mic */ + { 0x13, HDA_OUTPUT, 0 }, /* Line */ + { 0x1b, HDA_OUTPUT, 0 }, /* Aux */ + { 0x1c, HDA_OUTPUT, 0 }, /* Mic */ + { 0x1d, HDA_OUTPUT, 0 }, /* CD */ + { } /* end */ +}; +#endif + /* * Patch for HP nx6320 * @@ -1240,31 +1292,21 @@ static int ad1981_hp_master_sw_put(struct snd_kcontrol *kcontrol, return 0; /* toggle HP mute appropriately */ - snd_hda_codec_amp_update(codec, 0x06, 0, HDA_OUTPUT, 0, - 0x80, spec->cur_eapd ? 0 : 0x80); - snd_hda_codec_amp_update(codec, 0x06, 1, HDA_OUTPUT, 0, - 0x80, spec->cur_eapd ? 0 : 0x80); + snd_hda_codec_amp_stereo(codec, 0x06, HDA_OUTPUT, 0, + HDA_AMP_MUTE, + spec->cur_eapd ? 0 : HDA_AMP_MUTE); return 1; } /* bind volumes of both NID 0x05 and 0x06 */ -static int ad1981_hp_master_vol_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - long *valp = ucontrol->value.integer.value; - int change; - - change = snd_hda_codec_amp_update(codec, 0x05, 0, HDA_OUTPUT, 0, - 0x7f, valp[0] & 0x7f); - change |= snd_hda_codec_amp_update(codec, 0x05, 1, HDA_OUTPUT, 0, - 0x7f, valp[1] & 0x7f); - snd_hda_codec_amp_update(codec, 0x06, 0, HDA_OUTPUT, 0, - 0x7f, valp[0] & 0x7f); - snd_hda_codec_amp_update(codec, 0x06, 1, HDA_OUTPUT, 0, - 0x7f, valp[1] & 0x7f); - return change; -} +static struct hda_bind_ctls ad1981_hp_bind_master_vol = { + .ops = &snd_hda_bind_vol, + .values = { + HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x06, 3, 0, HDA_OUTPUT), + 0 + }, +}; /* mute internal speaker if HP is plugged */ static void ad1981_hp_automute(struct hda_codec *codec) @@ -1273,10 +1315,8 @@ static void ad1981_hp_automute(struct hda_codec *codec) present = snd_hda_codec_read(codec, 0x06, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - snd_hda_codec_amp_update(codec, 0x05, 0, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); - snd_hda_codec_amp_update(codec, 0x05, 1, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); + snd_hda_codec_amp_stereo(codec, 0x05, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); } /* toggle input of built-in and mic jack appropriately */ @@ -1327,14 +1367,7 @@ static struct hda_input_mux ad1981_hp_capture_source = { }; static struct snd_kcontrol_new ad1981_hp_mixers[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Volume", - .info = snd_hda_mixer_amp_volume_info, - .get = snd_hda_mixer_amp_volume_get, - .put = ad1981_hp_master_vol_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT), - }, + HDA_BIND_VOL("Master Playback Volume", &ad1981_hp_bind_master_vol), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", @@ -1474,7 +1507,6 @@ static int patch_ad1981(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; - mutex_init(&spec->amp_mutex); codec->spec = spec; spec->multiout.max_channels = 2; @@ -1490,6 +1522,9 @@ static int patch_ad1981(struct hda_codec *codec) spec->num_init_verbs = 1; spec->init_verbs[0] = ad1981_init_verbs; spec->spdif_route = 0; +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = ad1981_loopbacks; +#endif codec->patch_ops = ad198x_patch_ops; @@ -1897,16 +1932,19 @@ static int ad1988_spdif_playback_source_get(struct snd_kcontrol *kcontrol, struct hda_codec *codec = snd_kcontrol_chip(kcontrol); unsigned int sel; - sel = snd_hda_codec_read(codec, 0x02, 0, AC_VERB_GET_CONNECT_SEL, 0); - if (sel > 0) { + sel = snd_hda_codec_read(codec, 0x1d, 0, AC_VERB_GET_AMP_GAIN_MUTE, + AC_AMP_GET_INPUT); + if (!(sel & 0x80)) + ucontrol->value.enumerated.item[0] = 0; + else { sel = snd_hda_codec_read(codec, 0x0b, 0, AC_VERB_GET_CONNECT_SEL, 0); if (sel < 3) sel++; else sel = 0; + ucontrol->value.enumerated.item[0] = sel; } - ucontrol->value.enumerated.item[0] = sel; return 0; } @@ -1918,23 +1956,39 @@ static int ad1988_spdif_playback_source_put(struct snd_kcontrol *kcontrol, int change; val = ucontrol->value.enumerated.item[0]; - sel = snd_hda_codec_read(codec, 0x02, 0, AC_VERB_GET_CONNECT_SEL, 0); if (!val) { - change = sel != 0; - if (change || codec->in_resume) - snd_hda_codec_write(codec, 0x02, 0, - AC_VERB_SET_CONNECT_SEL, 0); + sel = snd_hda_codec_read(codec, 0x1d, 0, + AC_VERB_GET_AMP_GAIN_MUTE, + AC_AMP_GET_INPUT); + change = sel & 0x80; + if (change) { + snd_hda_codec_write_cache(codec, 0x1d, 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_IN_UNMUTE(0)); + snd_hda_codec_write_cache(codec, 0x1d, 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_IN_MUTE(1)); + } } else { - change = sel == 0; - if (change || codec->in_resume) - snd_hda_codec_write(codec, 0x02, 0, - AC_VERB_SET_CONNECT_SEL, 1); + sel = snd_hda_codec_read(codec, 0x1d, 0, + AC_VERB_GET_AMP_GAIN_MUTE, + AC_AMP_GET_INPUT | 0x01); + change = sel & 0x80; + if (change) { + snd_hda_codec_write_cache(codec, 0x1d, 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_IN_MUTE(0)); + snd_hda_codec_write_cache(codec, 0x1d, 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_IN_UNMUTE(1)); + } sel = snd_hda_codec_read(codec, 0x0b, 0, AC_VERB_GET_CONNECT_SEL, 0) + 1; change |= sel != val; - if (change || codec->in_resume) - snd_hda_codec_write(codec, 0x0b, 0, - AC_VERB_SET_CONNECT_SEL, val - 1); + if (change) + snd_hda_codec_write_cache(codec, 0x0b, 0, + AC_VERB_SET_CONNECT_SEL, + val - 1); } return change; } @@ -2047,10 +2101,9 @@ static struct hda_verb ad1988_spdif_init_verbs[] = { {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */ {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0}, /* ADC1 */ {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* SPDIF out pin */ {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x17}, /* 0dB */ { } }; @@ -2225,6 +2278,15 @@ static void ad1988_laptop_unsol_event(struct hda_codec *codec, unsigned int res) snd_hda_sequence_write(codec, ad1988_laptop_hp_off); } +#ifdef CONFIG_SND_HDA_POWER_SAVE +static struct hda_amp_list ad1988_loopbacks[] = { + { 0x20, HDA_INPUT, 0 }, /* Front Mic */ + { 0x20, HDA_INPUT, 1 }, /* Line */ + { 0x20, HDA_INPUT, 4 }, /* Mic */ + { 0x20, HDA_INPUT, 6 }, /* CD */ + { } /* end */ +}; +#endif /* * Automatic parse of I/O pins from the BIOS configuration @@ -2663,7 +2725,6 @@ static int patch_ad1988(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; - mutex_init(&spec->amp_mutex); codec->spec = spec; if (is_rev2(codec)) @@ -2770,6 +2831,9 @@ static int patch_ad1988(struct hda_codec *codec) codec->patch_ops.unsol_event = ad1988_laptop_unsol_event; break; } +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = ad1988_loopbacks; +#endif return 0; } @@ -2926,6 +2990,16 @@ static struct hda_verb ad1884_init_verbs[] = { { } /* end */ }; +#ifdef CONFIG_SND_HDA_POWER_SAVE +static struct hda_amp_list ad1884_loopbacks[] = { + { 0x20, HDA_INPUT, 0 }, /* Front Mic */ + { 0x20, HDA_INPUT, 1 }, /* Mic */ + { 0x20, HDA_INPUT, 2 }, /* CD */ + { 0x20, HDA_INPUT, 4 }, /* Docking */ + { } /* end */ +}; +#endif + static int patch_ad1884(struct hda_codec *codec) { struct ad198x_spec *spec; @@ -2950,6 +3024,9 @@ static int patch_ad1884(struct hda_codec *codec) spec->num_init_verbs = 1; spec->init_verbs[0] = ad1884_init_verbs; spec->spdif_route = 0; +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = ad1884_loopbacks; +#endif codec->patch_ops = ad198x_patch_ops; @@ -3331,6 +3408,16 @@ static struct hda_verb ad1882_init_verbs[] = { { } /* end */ }; +#ifdef CONFIG_SND_HDA_POWER_SAVE +static struct hda_amp_list ad1882_loopbacks[] = { + { 0x20, HDA_INPUT, 0 }, /* Front Mic */ + { 0x20, HDA_INPUT, 1 }, /* Mic */ + { 0x20, HDA_INPUT, 4 }, /* Line */ + { 0x20, HDA_INPUT, 6 }, /* CD */ + { } /* end */ +}; +#endif + /* models */ enum { AD1882_3STACK, @@ -3369,6 +3456,9 @@ static int patch_ad1882(struct hda_codec *codec) spec->num_init_verbs = 1; spec->init_verbs[0] = ad1882_init_verbs; spec->spdif_route = 0; +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = ad1882_loopbacks; +#endif codec->patch_ops = ad198x_patch_ops; diff --git a/sound/pci/hda/patch_atihdmi.c b/sound/pci/hda/patch_atihdmi.c index 72d3ab9751a..fbb8969dc55 100644 --- a/sound/pci/hda/patch_atihdmi.c +++ b/sound/pci/hda/patch_atihdmi.c @@ -62,19 +62,6 @@ static int atihdmi_init(struct hda_codec *codec) return 0; } -#ifdef CONFIG_PM -/* - * resume - */ -static int atihdmi_resume(struct hda_codec *codec) -{ - atihdmi_init(codec); - snd_hda_resume_spdif_out(codec); - - return 0; -} -#endif - /* * Digital out */ @@ -141,9 +128,6 @@ static struct hda_codec_ops atihdmi_patch_ops = { .build_pcms = atihdmi_build_pcms, .init = atihdmi_init, .free = atihdmi_free, -#ifdef CONFIG_PM - .resume = atihdmi_resume, -#endif }; static int patch_atihdmi(struct hda_codec *codec) diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index 3c722e667bc..2468f317122 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c @@ -427,27 +427,6 @@ static int cmi9880_init(struct hda_codec *codec) return 0; } -#ifdef CONFIG_PM -/* - * resume - */ -static int cmi9880_resume(struct hda_codec *codec) -{ - struct cmi_spec *spec = codec->spec; - - cmi9880_init(codec); - snd_hda_resume_ctls(codec, cmi9880_basic_mixer); - if (spec->channel_modes) - snd_hda_resume_ctls(codec, cmi9880_ch_mode_mixer); - if (spec->multiout.dig_out_nid) - snd_hda_resume_spdif_out(codec); - if (spec->dig_in_nid) - snd_hda_resume_spdif_in(codec); - - return 0; -} -#endif - /* * Analog playback callbacks */ @@ -635,9 +614,6 @@ static struct hda_codec_ops cmi9880_patch_ops = { .build_pcms = cmi9880_build_pcms, .init = cmi9880_init, .free = cmi9880_free, -#ifdef CONFIG_PM - .resume = cmi9880_resume, -#endif }; static int patch_cmi9880(struct hda_codec *codec) diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 4d8e8af5c81..080e3001d9c 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -311,23 +311,6 @@ static void conexant_free(struct hda_codec *codec) kfree(codec->spec); } -#ifdef CONFIG_PM -static int conexant_resume(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - int i; - - codec->patch_ops.init(codec); - for (i = 0; i < spec->num_mixers; i++) - snd_hda_resume_ctls(codec, spec->mixers[i]); - if (spec->multiout.dig_out_nid) - snd_hda_resume_spdif_out(codec); - if (spec->dig_in_nid) - snd_hda_resume_spdif_in(codec); - return 0; -} -#endif - static int conexant_build_controls(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; @@ -358,9 +341,6 @@ static struct hda_codec_ops conexant_patch_ops = { .build_pcms = conexant_build_pcms, .init = conexant_init, .free = conexant_free, -#ifdef CONFIG_PM - .resume = conexant_resume, -#endif }; /* @@ -368,15 +348,7 @@ static struct hda_codec_ops conexant_patch_ops = { * the private value = nid | (invert << 8) */ -static int cxt_eapd_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 cxt_eapd_info snd_ctl_boolean_mono_info static int cxt_eapd_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -404,13 +376,13 @@ static int cxt_eapd_put(struct snd_kcontrol *kcontrol, eapd = ucontrol->value.integer.value[0]; if (invert) eapd = !eapd; - if (eapd == spec->cur_eapd && !codec->in_resume) + if (eapd == spec->cur_eapd) return 0; spec->cur_eapd = eapd; - snd_hda_codec_write(codec, nid, - 0, AC_VERB_SET_EAPD_BTLENABLE, - eapd ? 0x02 : 0x00); + snd_hda_codec_write_cache(codec, nid, + 0, AC_VERB_SET_EAPD_BTLENABLE, + eapd ? 0x02 : 0x00); return 1; } @@ -500,34 +472,25 @@ static int cxt5045_hp_master_sw_put(struct snd_kcontrol *kcontrol, /* toggle internal speakers mute depending of presence of * the headphone jack */ - bits = (!spec->hp_present && spec->cur_eapd) ? 0 : 0x80; - snd_hda_codec_amp_update(codec, 0x10, 0, HDA_OUTPUT, 0, 0x80, bits); - snd_hda_codec_amp_update(codec, 0x10, 1, HDA_OUTPUT, 0, 0x80, bits); + bits = (!spec->hp_present && spec->cur_eapd) ? 0 : HDA_AMP_MUTE; + snd_hda_codec_amp_stereo(codec, 0x10, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); - bits = spec->cur_eapd ? 0 : 0x80; - snd_hda_codec_amp_update(codec, 0x11, 0, HDA_OUTPUT, 0, 0x80, bits); - snd_hda_codec_amp_update(codec, 0x11, 1, HDA_OUTPUT, 0, 0x80, bits); + bits = spec->cur_eapd ? 0 : HDA_AMP_MUTE; + snd_hda_codec_amp_stereo(codec, 0x11, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); return 1; } /* bind volumes of both NID 0x10 and 0x11 */ -static int cxt5045_hp_master_vol_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - long *valp = ucontrol->value.integer.value; - int change; - - change = snd_hda_codec_amp_update(codec, 0x10, 0, HDA_OUTPUT, 0, - 0x7f, valp[0] & 0x7f); - change |= snd_hda_codec_amp_update(codec, 0x10, 1, HDA_OUTPUT, 0, - 0x7f, valp[1] & 0x7f); - snd_hda_codec_amp_update(codec, 0x11, 0, HDA_OUTPUT, 0, - 0x7f, valp[0] & 0x7f); - snd_hda_codec_amp_update(codec, 0x11, 1, HDA_OUTPUT, 0, - 0x7f, valp[1] & 0x7f); - return change; -} +static struct hda_bind_ctls cxt5045_hp_bind_master_vol = { + .ops = &snd_hda_bind_vol, + .values = { + HDA_COMPOSE_AMP_VAL(0x10, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT), + 0 + }, +}; /* toggle input of built-in and mic jack appropriately */ static void cxt5045_hp_automic(struct hda_codec *codec) @@ -562,9 +525,9 @@ static void cxt5045_hp_automute(struct hda_codec *codec) spec->hp_present = snd_hda_codec_read(codec, 0x11, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = (spec->hp_present || !spec->cur_eapd) ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x10, 0, HDA_OUTPUT, 0, 0x80, bits); - snd_hda_codec_amp_update(codec, 0x10, 1, HDA_OUTPUT, 0, 0x80, bits); + bits = (spec->hp_present || !spec->cur_eapd) ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x10, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); } /* unsolicited event for HP jack sensing */ @@ -595,14 +558,7 @@ static struct snd_kcontrol_new cxt5045_mixers[] = { HDA_CODEC_MUTE("Int Mic Switch", 0x1a, 0x01, HDA_INPUT), HDA_CODEC_VOLUME("Ext Mic Volume", 0x1a, 0x02, HDA_INPUT), HDA_CODEC_MUTE("Ext Mic Switch", 0x1a, 0x02, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Volume", - .info = snd_hda_mixer_amp_volume_info, - .get = snd_hda_mixer_amp_volume_get, - .put = cxt5045_hp_master_vol_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x10, 3, 0, HDA_OUTPUT), - }, + HDA_BIND_VOL("Master Playback Volume", &cxt5045_hp_bind_master_vol), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", @@ -915,33 +871,24 @@ static int cxt5047_hp_master_sw_put(struct snd_kcontrol *kcontrol, /* toggle internal speakers mute depending of presence of * the headphone jack */ - bits = (!spec->hp_present && spec->cur_eapd) ? 0 : 0x80; - snd_hda_codec_amp_update(codec, 0x1d, 0, HDA_OUTPUT, 0, 0x80, bits); - snd_hda_codec_amp_update(codec, 0x1d, 1, HDA_OUTPUT, 0, 0x80, bits); - bits = spec->cur_eapd ? 0 : 0x80; - snd_hda_codec_amp_update(codec, 0x13, 0, HDA_OUTPUT, 0, 0x80, bits); - snd_hda_codec_amp_update(codec, 0x13, 1, HDA_OUTPUT, 0, 0x80, bits); + bits = (!spec->hp_present && spec->cur_eapd) ? 0 : HDA_AMP_MUTE; + snd_hda_codec_amp_stereo(codec, 0x1d, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); + bits = spec->cur_eapd ? 0 : HDA_AMP_MUTE; + snd_hda_codec_amp_stereo(codec, 0x13, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); return 1; } /* bind volumes of both NID 0x13 (Headphones) and 0x1d (Speakers) */ -static int cxt5047_hp_master_vol_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - long *valp = ucontrol->value.integer.value; - int change; - - change = snd_hda_codec_amp_update(codec, 0x1d, 0, HDA_OUTPUT, 0, - 0x7f, valp[0] & 0x7f); - change |= snd_hda_codec_amp_update(codec, 0x1d, 1, HDA_OUTPUT, 0, - 0x7f, valp[1] & 0x7f); - snd_hda_codec_amp_update(codec, 0x13, 0, HDA_OUTPUT, 0, - 0x7f, valp[0] & 0x7f); - snd_hda_codec_amp_update(codec, 0x13, 1, HDA_OUTPUT, 0, - 0x7f, valp[1] & 0x7f); - return change; -} +static struct hda_bind_ctls cxt5047_bind_master_vol = { + .ops = &snd_hda_bind_vol, + .values = { + HDA_COMPOSE_AMP_VAL(0x13, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT), + 0 + }, +}; /* mute internal speaker if HP is plugged */ static void cxt5047_hp_automute(struct hda_codec *codec) @@ -952,12 +899,12 @@ static void cxt5047_hp_automute(struct hda_codec *codec) spec->hp_present = snd_hda_codec_read(codec, 0x13, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = (spec->hp_present || !spec->cur_eapd) ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x1d, 0, HDA_OUTPUT, 0, 0x80, bits); - snd_hda_codec_amp_update(codec, 0x1d, 1, HDA_OUTPUT, 0, 0x80, bits); + bits = (spec->hp_present || !spec->cur_eapd) ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x1d, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); /* Mute/Unmute PCM 2 for good measure - some systems need this */ - snd_hda_codec_amp_update(codec, 0x1c, 0, HDA_OUTPUT, 0, 0x80, bits); - snd_hda_codec_amp_update(codec, 0x1c, 1, HDA_OUTPUT, 0, 0x80, bits); + snd_hda_codec_amp_stereo(codec, 0x1c, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); } /* mute internal speaker if HP is plugged */ @@ -969,12 +916,12 @@ static void cxt5047_hp2_automute(struct hda_codec *codec) spec->hp_present = snd_hda_codec_read(codec, 0x13, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = spec->hp_present ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x1d, 0, HDA_OUTPUT, 0, 0x80, bits); - snd_hda_codec_amp_update(codec, 0x1d, 1, HDA_OUTPUT, 0, 0x80, bits); + bits = spec->hp_present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x1d, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); /* Mute/Unmute PCM 2 for good measure - some systems need this */ - snd_hda_codec_amp_update(codec, 0x1c, 0, HDA_OUTPUT, 0, 0x80, bits); - snd_hda_codec_amp_update(codec, 0x1c, 1, HDA_OUTPUT, 0, 0x80, bits); + snd_hda_codec_amp_stereo(codec, 0x1c, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); } /* toggle input of built-in and mic jack appropriately */ @@ -1063,14 +1010,7 @@ static struct snd_kcontrol_new cxt5047_toshiba_mixers[] = { HDA_CODEC_MUTE("Capture Switch", 0x12, 0x03, HDA_INPUT), HDA_CODEC_VOLUME("PCM Volume", 0x10, 0x00, HDA_OUTPUT), HDA_CODEC_MUTE("PCM Switch", 0x10, 0x00, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Volume", - .info = snd_hda_mixer_amp_volume_info, - .get = snd_hda_mixer_amp_volume_get, - .put = cxt5047_hp_master_vol_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x13, 3, 0, HDA_OUTPUT), - }, + HDA_BIND_VOL("Master Playback Volume", &cxt5047_bind_master_vol), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 9a47eec5a27..53b0428abfc 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -102,6 +102,8 @@ enum { /* ALC268 models */ enum { ALC268_3ST, + ALC268_TOSHIBA, + ALC268_ACER, ALC268_AUTO, ALC268_MODEL_LAST /* last tag */ }; @@ -129,6 +131,7 @@ enum { ALC861VD_6ST_DIG, ALC861VD_LENOVO, ALC861VD_DALLAS, + ALC861VD_HP, ALC861VD_AUTO, ALC861VD_MODEL_LAST, }; @@ -140,6 +143,7 @@ enum { ALC662_3ST_6ch, ALC662_5ST_DIG, ALC662_LENOVO_101E, + ALC662_ASUS_EEEPC_P701, ALC662_AUTO, ALC662_MODEL_LAST, }; @@ -152,7 +156,9 @@ enum { ALC882_W2JC, ALC882_TARGA, ALC882_ASUS_A7J, + ALC882_ASUS_A7M, ALC885_MACPRO, + ALC885_MBP3, ALC885_IMAC24, ALC882_AUTO, ALC882_MODEL_LAST, @@ -167,12 +173,14 @@ enum { ALC883_TARGA_DIG, ALC883_TARGA_2ch_DIG, ALC883_ACER, + ALC883_ACER_ASPIRE, ALC883_MEDION, ALC883_MEDION_MD2, ALC883_LAPTOP_EAPD, ALC883_LENOVO_101E_2ch, ALC883_LENOVO_NB0763, - ALC888_LENOVO_MS7195_DIG, + ALC888_LENOVO_MS7195_DIG, + ALC883_HAIER_W66, ALC888_6ST_HP, ALC888_3ST_HP, ALC883_AUTO, @@ -239,6 +247,10 @@ struct alc_spec { /* for pin sensing */ unsigned int sense_updated: 1; unsigned int jack_present: 1; + +#ifdef CONFIG_SND_HDA_POWER_SAVE + struct hda_loopback_check loopback; +#endif }; /* @@ -263,6 +275,9 @@ struct alc_config_preset { const struct hda_input_mux *input_mux; void (*unsol_event)(struct hda_codec *, unsigned int); void (*init_hook)(struct hda_codec *); +#ifdef CONFIG_SND_HDA_POWER_SAVE + struct hda_amp_list *loopbacks; +#endif }; @@ -441,8 +456,9 @@ static int alc_pin_mode_put(struct snd_kcontrol *kcontrol, change = pinctl != alc_pin_mode_values[val]; if (change) { /* Set pin mode to that requested */ - snd_hda_codec_write(codec,nid,0,AC_VERB_SET_PIN_WIDGET_CONTROL, - alc_pin_mode_values[val]); + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + alc_pin_mode_values[val]); /* Also enable the retasking pin's input/output as required * for the requested pin mode. Enum values of 2 or less are @@ -455,19 +471,15 @@ static int alc_pin_mode_put(struct snd_kcontrol *kcontrol, * this turns out to be necessary in the future. */ if (val <= 2) { - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_MUTE); - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_UNMUTE(0)); + snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, + HDA_AMP_MUTE, HDA_AMP_MUTE); + snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0, + HDA_AMP_MUTE, 0); } else { - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_MUTE(0)); - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_UNMUTE); + snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0, + HDA_AMP_MUTE, HDA_AMP_MUTE); + snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, + HDA_AMP_MUTE, 0); } } return change; @@ -486,15 +498,7 @@ static int alc_pin_mode_put(struct snd_kcontrol *kcontrol, * needed for any "production" models. */ #ifdef CONFIG_SND_DEBUG -static int alc_gpio_data_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 alc_gpio_data_info snd_ctl_boolean_mono_info static int alc_gpio_data_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -527,7 +531,8 @@ static int alc_gpio_data_put(struct snd_kcontrol *kcontrol, gpio_data &= ~mask; else gpio_data |= mask; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_GPIO_DATA, gpio_data); + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_GPIO_DATA, gpio_data); return change; } @@ -547,15 +552,7 @@ static int alc_gpio_data_put(struct snd_kcontrol *kcontrol, * necessary. */ #ifdef CONFIG_SND_DEBUG -static int alc_spdif_ctrl_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 alc_spdif_ctrl_info snd_ctl_boolean_mono_info static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -588,8 +585,8 @@ static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol, ctrl_data &= ~mask; else ctrl_data |= mask; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, - ctrl_data); + snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, + ctrl_data); return change; } @@ -638,6 +635,9 @@ static void setup_preset(struct alc_spec *spec, spec->unsol_event = preset->unsol_event; spec->init_hook = preset->init_hook; +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = preset->loopbacks; +#endif } /* Enable GPIO mask and set output */ @@ -662,6 +662,44 @@ static struct hda_verb alc_gpio3_init_verbs[] = { { } }; +static void alc_sku_automute(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + unsigned int mute; + unsigned int present; + unsigned int hp_nid = spec->autocfg.hp_pins[0]; + unsigned int sp_nid = spec->autocfg.speaker_pins[0]; + + /* need to execute and sync at first */ + snd_hda_codec_read(codec, hp_nid, 0, AC_VERB_SET_PIN_SENSE, 0); + present = snd_hda_codec_read(codec, hp_nid, 0, + AC_VERB_GET_PIN_SENSE, 0); + spec->jack_present = (present & 0x80000000) != 0; + if (spec->jack_present) { + /* mute internal speaker */ + snd_hda_codec_amp_stereo(codec, sp_nid, HDA_OUTPUT, 0, + HDA_AMP_MUTE, HDA_AMP_MUTE); + } else { + /* unmute internal speaker if necessary */ + mute = snd_hda_codec_amp_read(codec, hp_nid, 0, HDA_OUTPUT, 0); + snd_hda_codec_amp_stereo(codec, sp_nid, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); + } +} + +/* unsolicited event for HP jack sensing */ +static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res) +{ + if (codec->vendor_id == 0x10ec0880) + res >>= 28; + else + res >>= 26; + if (res != ALC880_HP_EVENT) + return; + + alc_sku_automute(codec); +} + /* 32-bit subsystem ID for BIOS loading in HD Audio codec. * 31 ~ 16 : Manufacture ID * 15 ~ 8 : SKU ID @@ -672,13 +710,48 @@ static void alc_subsystem_id(struct hda_codec *codec, unsigned int porta, unsigned int porte, unsigned int portd) { - unsigned int ass, tmp; + unsigned int ass, tmp, i; + unsigned nid; + struct alc_spec *spec = codec->spec; - ass = codec->subsystem_id; - if (!(ass & 1)) + ass = codec->subsystem_id & 0xffff; + if ((ass != codec->bus->pci->subsystem_device) && (ass & 1)) + goto do_sku; + + /* + * 31~30 : port conetcivity + * 29~21 : reserve + * 20 : PCBEEP input + * 19~16 : Check sum (15:1) + * 15~1 : Custom + * 0 : override + */ + nid = 0x1d; + if (codec->vendor_id == 0x10ec0260) + nid = 0x17; + ass = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_CONFIG_DEFAULT, 0); + if (!(ass & 1) && !(ass & 0x100000)) + return; + if ((ass >> 30) != 1) /* no physical connection */ return; - /* Override */ + /* check sum */ + tmp = 0; + for (i = 1; i < 16; i++) { + if ((ass >> i) && 1) + tmp++; + } + if (((ass >> 16) & 0xf) != tmp) + return; +do_sku: + /* + * 0 : override + * 1 : Swap Jack + * 2 : 0 --> Desktop, 1 --> Laptop + * 3~5 : External Amplifier control + * 7~6 : Reserved + */ tmp = (ass & 0x38) >> 3; /* external Amp control */ switch (tmp) { case 1: @@ -690,38 +763,108 @@ static void alc_subsystem_id(struct hda_codec *codec, case 7: snd_hda_sequence_write(codec, alc_gpio3_init_verbs); break; - case 5: + case 5: /* set EAPD output high */ switch (codec->vendor_id) { - case 0x10ec0862: - case 0x10ec0660: - case 0x10ec0662: + case 0x10ec0260: + snd_hda_codec_write(codec, 0x0f, 0, + AC_VERB_SET_EAPD_BTLENABLE, 2); + snd_hda_codec_write(codec, 0x10, 0, + AC_VERB_SET_EAPD_BTLENABLE, 2); + break; + case 0x10ec0262: case 0x10ec0267: case 0x10ec0268: + case 0x10ec0269: + case 0x10ec0862: + case 0x10ec0662: snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_EAPD_BTLENABLE, 2); snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_EAPD_BTLENABLE, 2); - return; + break; } - case 6: - if (ass & 4) { /* bit 2 : 0 = Desktop, 1 = Laptop */ - hda_nid_t port = 0; - tmp = (ass & 0x1800) >> 11; - switch (tmp) { - case 0: port = porta; break; - case 1: port = porte; break; - case 2: port = portd; break; - } - if (port) - snd_hda_codec_write(codec, port, 0, - AC_VERB_SET_EAPD_BTLENABLE, - 2); + switch (codec->vendor_id) { + case 0x10ec0260: + snd_hda_codec_write(codec, 0x1a, 0, + AC_VERB_SET_COEF_INDEX, 7); + tmp = snd_hda_codec_read(codec, 0x1a, 0, + AC_VERB_GET_PROC_COEF, 0); + snd_hda_codec_write(codec, 0x1a, 0, + AC_VERB_SET_COEF_INDEX, 7); + snd_hda_codec_write(codec, 0x1a, 0, + AC_VERB_SET_PROC_COEF, + tmp | 0x2010); + break; + case 0x10ec0262: + case 0x10ec0880: + case 0x10ec0882: + case 0x10ec0883: + case 0x10ec0885: + case 0x10ec0888: + snd_hda_codec_write(codec, 0x20, 0, + AC_VERB_SET_COEF_INDEX, 7); + tmp = snd_hda_codec_read(codec, 0x20, 0, + AC_VERB_GET_PROC_COEF, 0); + snd_hda_codec_write(codec, 0x20, 0, + AC_VERB_SET_COEF_INDEX, 7); + snd_hda_codec_write(codec, 0x20, 0, + AC_VERB_SET_PROC_COEF, + tmp | 0x2010); + break; + case 0x10ec0267: + case 0x10ec0268: + snd_hda_codec_write(codec, 0x20, 0, + AC_VERB_SET_COEF_INDEX, 7); + tmp = snd_hda_codec_read(codec, 0x20, 0, + AC_VERB_GET_PROC_COEF, 0); + snd_hda_codec_write(codec, 0x20, 0, + AC_VERB_SET_COEF_INDEX, 7); + snd_hda_codec_write(codec, 0x20, 0, + AC_VERB_SET_PROC_COEF, + tmp | 0x3000); + break; } - snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7); - snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, - (tmp == 5 ? 0x3040 : 0x3050)); + default: break; } + + /* is laptop and enable the function "Mute internal speaker + * when the external headphone out jack is plugged" + */ + if (!(ass & 0x4) || !(ass & 0x8000)) + return; + /* + * 10~8 : Jack location + * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered + * 14~13: Resvered + * 15 : 1 --> enable the function "Mute internal speaker + * when the external headphone out jack is plugged" + */ + if (!spec->autocfg.speaker_pins[0]) { + if (spec->multiout.dac_nids[0]) + spec->autocfg.speaker_pins[0] = + spec->multiout.dac_nids[0]; + else + return; + } + + if (!spec->autocfg.hp_pins[0]) { + tmp = (ass >> 11) & 0x3; /* HP to chassis */ + if (tmp == 0) + spec->autocfg.hp_pins[0] = porta; + else if (tmp == 1) + spec->autocfg.hp_pins[0] = porte; + else if (tmp == 2) + spec->autocfg.hp_pins[0] = portd; + else + return; + } + + snd_hda_codec_write(codec, spec->autocfg.hp_pins[0], 0, + AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | ALC880_HP_EVENT); + spec->unsol_event = alc_sku_unsol_event; + spec->init_hook = alc_sku_automute; } /* @@ -1304,11 +1447,13 @@ static struct hda_verb alc880_volume_init_verbs[] = { * panel mic (mic 2) */ /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* * Set up output mixers (0x0c - 0x0f) @@ -1568,15 +1713,11 @@ static void alc880_uniwill_hp_automute(struct hda_codec *codec) present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x16, 0, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x16, 1, HDA_OUTPUT, 0, - 0x80, bits); + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); + snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); } /* auto-toggle front mic */ @@ -1587,11 +1728,8 @@ static void alc880_uniwill_mic_automute(struct hda_codec *codec) present = snd_hda_codec_read(codec, 0x18, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x0b, 0, HDA_INPUT, 1, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x0b, 1, HDA_INPUT, 1, - 0x80, bits); + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits); } static void alc880_uniwill_automute(struct hda_codec *codec) @@ -1623,11 +1761,8 @@ static void alc880_uniwill_p53_hp_automute(struct hda_codec *codec) present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x15, 0, HDA_INPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x15, 1, HDA_INPUT, 0, - 0x80, bits); + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x15, HDA_INPUT, 0, HDA_AMP_MUTE, bits); } static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec) @@ -1635,19 +1770,14 @@ static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec) unsigned int present; present = snd_hda_codec_read(codec, 0x21, 0, - AC_VERB_GET_VOLUME_KNOB_CONTROL, 0) & 0x7f; - - snd_hda_codec_amp_update(codec, 0x0c, 0, HDA_OUTPUT, 0, - 0x7f, present); - snd_hda_codec_amp_update(codec, 0x0c, 1, HDA_OUTPUT, 0, - 0x7f, present); - - snd_hda_codec_amp_update(codec, 0x0d, 0, HDA_OUTPUT, 0, - 0x7f, present); - snd_hda_codec_amp_update(codec, 0x0d, 1, HDA_OUTPUT, 0, - 0x7f, present); - + AC_VERB_GET_VOLUME_KNOB_CONTROL, 0); + present &= HDA_AMP_VOLMASK; + snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0, + HDA_AMP_VOLMASK, present); + snd_hda_codec_amp_stereo(codec, 0x0d, HDA_OUTPUT, 0, + HDA_AMP_VOLMASK, present); } + static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec, unsigned int res) { @@ -1868,8 +1998,8 @@ static struct hda_verb alc880_lg_init_verbs[] = { {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, /* mute all amp mixer inputs */ {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(6)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(7)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* line-in to input */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, @@ -1900,11 +2030,9 @@ static void alc880_lg_automute(struct hda_codec *codec) present = snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x17, 0, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x17, 1, HDA_OUTPUT, 0, - 0x80, bits); + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); } static void alc880_lg_unsol_event(struct hda_codec *codec, unsigned int res) @@ -1973,7 +2101,7 @@ static struct hda_verb alc880_lg_lw_init_verbs[] = { {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(7)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* speaker-out */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, @@ -1999,11 +2127,9 @@ static void alc880_lg_lw_automute(struct hda_codec *codec) present = snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, - 0x80, bits); + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); } static void alc880_lg_lw_unsol_event(struct hda_codec *codec, unsigned int res) @@ -2015,6 +2141,24 @@ static void alc880_lg_lw_unsol_event(struct hda_codec *codec, unsigned int res) alc880_lg_lw_automute(codec); } +#ifdef CONFIG_SND_HDA_POWER_SAVE +static struct hda_amp_list alc880_loopbacks[] = { + { 0x0b, HDA_INPUT, 0 }, + { 0x0b, HDA_INPUT, 1 }, + { 0x0b, HDA_INPUT, 2 }, + { 0x0b, HDA_INPUT, 3 }, + { 0x0b, HDA_INPUT, 4 }, + { } /* end */ +}; + +static struct hda_amp_list alc880_lg_loopbacks[] = { + { 0x0b, HDA_INPUT, 1 }, + { 0x0b, HDA_INPUT, 6 }, + { 0x0b, HDA_INPUT, 7 }, + { } /* end */ +}; +#endif + /* * Common callbacks */ @@ -2041,24 +2185,11 @@ static void alc_unsol_event(struct hda_codec *codec, unsigned int res) spec->unsol_event(codec, res); } -#ifdef CONFIG_PM -/* - * resume - */ -static int alc_resume(struct hda_codec *codec) +#ifdef CONFIG_SND_HDA_POWER_SAVE +static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid) { struct alc_spec *spec = codec->spec; - int i; - - alc_init(codec); - for (i = 0; i < spec->num_mixers; i++) - snd_hda_resume_ctls(codec, spec->mixers[i]); - if (spec->multiout.dig_out_nid) - snd_hda_resume_spdif_out(codec); - if (spec->dig_in_nid) - snd_hda_resume_spdif_in(codec); - - return 0; + return snd_hda_check_amp_list_power(codec, &spec->loopback, nid); } #endif @@ -2293,8 +2424,8 @@ static struct hda_codec_ops alc_patch_ops = { .init = alc_init, .free = alc_free, .unsol_event = alc_unsol_event, -#ifdef CONFIG_PM - .resume = alc_resume, +#ifdef CONFIG_SND_HDA_POWER_SAVE + .check_power_status = alc_check_power_status, #endif }; @@ -2392,11 +2523,14 @@ static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); new_ctl = ctls[ucontrol->value.enumerated.item[0]]; if (old_ctl != new_ctl) { - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, new_ctl); - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, - (ucontrol->value.enumerated.item[0] >= 3 ? - 0xb080 : 0xb000)); + int val; + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + new_ctl); + val = ucontrol->value.enumerated.item[0] >= 3 ? + HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, + HDA_AMP_MUTE, val); return 1; } return 0; @@ -2439,7 +2573,8 @@ static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol, sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3; if (ucontrol->value.enumerated.item[0] != sel) { sel = ucontrol->value.enumerated.item[0] & 3; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, sel); + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_CONNECT_SEL, sel); return 1; } return 0; @@ -2885,6 +3020,7 @@ static struct alc_config_preset alc880_presets[] = { alc880_beep_init_verbs }, .num_dacs = ARRAY_SIZE(alc880_dac_nids), .dac_nids = alc880_dac_nids, + .dig_out_nid = ALC880_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), .channel_mode = alc880_2_jack_modes, .input_mux = &alc880_capture_source, @@ -2916,6 +3052,9 @@ static struct alc_config_preset alc880_presets[] = { .input_mux = &alc880_lg_capture_source, .unsol_event = alc880_lg_unsol_event, .init_hook = alc880_lg_automute, +#ifdef CONFIG_SND_HDA_POWER_SAVE + .loopbacks = alc880_lg_loopbacks, +#endif }, [ALC880_LG_LW] = { .mixers = { alc880_lg_lw_mixer }, @@ -3399,6 +3538,10 @@ static int patch_alc880(struct hda_codec *codec) codec->patch_ops = alc_patch_ops; if (board_config == ALC880_AUTO) spec->init_hook = alc880_auto_init; +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (!spec->loopback.amplist) + spec->loopback.amplist = alc880_loopbacks; +#endif return 0; } @@ -3747,12 +3890,12 @@ static struct hda_verb alc260_init_verbs[] = { /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & * Line In 2 = 0x03 */ - /* mute CD */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - /* mute Line In */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - /* mute Mic */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + /* mute analog inputs */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ /* mute Front out path */ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, @@ -3797,12 +3940,12 @@ static struct hda_verb alc260_hp_init_verbs[] = { /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & * Line In 2 = 0x03 */ - /* unmute CD */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, - /* unmute Line In */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, - /* unmute Mic */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + /* mute analog inputs */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ /* Unmute Front out path */ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, @@ -3847,12 +3990,12 @@ static struct hda_verb alc260_hp_3013_init_verbs[] = { /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 & * Line In 2 = 0x03 */ - /* unmute CD */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, - /* unmute Line In */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, - /* unmute Mic */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + /* mute analog inputs */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */ /* Unmute Front out path */ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, @@ -4069,13 +4212,17 @@ static void alc260_replacer_672v_automute(struct hda_codec *codec) present = snd_hda_codec_read(codec, 0x0f, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; if (present) { - snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 1); - snd_hda_codec_write(codec, 0x0f, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP); + snd_hda_codec_write_cache(codec, 0x01, 0, + AC_VERB_SET_GPIO_DATA, 1); + snd_hda_codec_write_cache(codec, 0x0f, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + PIN_HP); } else { - snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0); - snd_hda_codec_write(codec, 0x0f, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); + snd_hda_codec_write_cache(codec, 0x01, 0, + AC_VERB_SET_GPIO_DATA, 0); + snd_hda_codec_write_cache(codec, 0x0f, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + PIN_OUT); } } @@ -4470,11 +4617,12 @@ static struct hda_verb alc260_volume_init_verbs[] = { * front panel mic (mic 2) */ /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + /* mute analog inputs */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* * Set up output mixers (0x08 - 0x0a) @@ -4551,6 +4699,17 @@ static void alc260_auto_init(struct hda_codec *codec) alc260_auto_init_analog_input(codec); } +#ifdef CONFIG_SND_HDA_POWER_SAVE +static struct hda_amp_list alc260_loopbacks[] = { + { 0x07, HDA_INPUT, 0 }, + { 0x07, HDA_INPUT, 1 }, + { 0x07, HDA_INPUT, 2 }, + { 0x07, HDA_INPUT, 3 }, + { 0x07, HDA_INPUT, 4 }, + { } /* end */ +}; +#endif + /* * ALC260 configurations */ @@ -4750,6 +4909,10 @@ static int patch_alc260(struct hda_codec *codec) codec->patch_ops = alc_patch_ops; if (board_config == ALC260_AUTO) spec->init_hook = alc260_auto_init; +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (!spec->loopback.amplist) + spec->loopback.amplist = alc260_loopbacks; +#endif return 0; } @@ -4812,12 +4975,13 @@ static int alc882_mux_enum_put(struct snd_kcontrol *kcontrol, idx = ucontrol->value.enumerated.item[0]; if (idx >= imux->num_items) idx = imux->num_items - 1; - if (*cur_val == idx && !codec->in_resume) + if (*cur_val == idx) return 0; for (i = 0; i < imux->num_items; i++) { - unsigned int v = (i == idx) ? 0x7000 : 0x7080; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, - v | (imux->items[i].index << 8)); + unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE; + snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, + imux->items[i].index, + HDA_AMP_MUTE, v); } *cur_val = idx; return 1; @@ -4879,6 +5043,38 @@ static struct hda_channel_mode alc882_sixstack_modes[2] = { { 8, alc882_sixstack_ch8_init }, }; +/* + * macbook pro ALC885 can switch LineIn to LineOut without loosing Mic + */ + +/* + * 2ch mode + */ +static struct hda_verb alc885_mbp_ch2_init[] = { + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, + { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + { } /* end */ +}; + +/* + * 6ch mode + */ +static struct hda_verb alc885_mbp_ch6_init[] = { + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + { } /* end */ +}; + +static struct hda_channel_mode alc885_mbp_6ch_modes[2] = { + { 2, alc885_mbp_ch2_init }, + { 6, alc885_mbp_ch6_init }, +}; + + /* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b */ @@ -4909,6 +5105,19 @@ static struct snd_kcontrol_new alc882_base_mixer[] = { { } /* end */ }; +static struct snd_kcontrol_new alc885_mbp3_mixer[] = { + HDA_CODEC_VOLUME("Master Volume", 0x0c, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE ("Master Switch", 0x0c, 0x02, HDA_INPUT), + HDA_CODEC_MUTE ("Speaker Switch", 0x14, 0x00, HDA_OUTPUT), + HDA_CODEC_VOLUME("Line Out Volume", 0x0d,0x00, HDA_OUTPUT), + HDA_CODEC_VOLUME("Line In Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE ("Line In Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT), + HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT), + HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0x00, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT), + { } /* end */ +}; static struct snd_kcontrol_new alc882_w2jc_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), @@ -4934,8 +5143,10 @@ static struct snd_kcontrol_new alc882_targa_mixer[] = { HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), { } /* end */ }; @@ -4955,6 +5166,23 @@ static struct snd_kcontrol_new alc882_asus_a7j_mixer[] = { HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + { } /* end */ +}; + +static struct snd_kcontrol_new alc882_asus_a7m_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), + HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), { } /* end */ }; @@ -5119,6 +5347,66 @@ static struct hda_verb alc882_macpro_init_verbs[] = { { } }; +/* Macbook Pro rev3 */ +static struct hda_verb alc885_mbp3_init_verbs[] = { + /* Front mixer: unmute input/output amp left and right (volume = 0) */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* Rear mixer */ + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* Front Pin: output 0 (0x0c) */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* HP Pin: output 0 (0x0d) */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + /* Mic (rear) pin: input vref at 80% */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Front Mic pin: input vref at 80% */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line In pin: use output 1 when in LineOut mode */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, + + /* FIXME: use matrix-type input source selection */ + /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ + /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* Input mixer2 */ + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* Input mixer3 */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* ADC1: mute amp left and right */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* ADC2: mute amp left and right */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* ADC3: mute amp left and right */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, + + { } +}; + /* iMac 24 mixer. */ static struct snd_kcontrol_new alc885_imac24_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT), @@ -5154,14 +5442,10 @@ static void alc885_imac24_automute(struct hda_codec *codec) present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - snd_hda_codec_amp_update(codec, 0x18, 0, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); - snd_hda_codec_amp_update(codec, 0x18, 1, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); - snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); - snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); + snd_hda_codec_amp_stereo(codec, 0x18, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); } /* Processes unsolicited events. */ @@ -5173,6 +5457,27 @@ static void alc885_imac24_unsol_event(struct hda_codec *codec, alc885_imac24_automute(codec); } +static void alc885_mbp3_automute(struct hda_codec *codec) +{ + unsigned int present; + + present = snd_hda_codec_read(codec, 0x15, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE); + +} +static void alc885_mbp3_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + /* Headphone insertion or removal. */ + if ((res >> 26) == ALC880_HP_EVENT) + alc885_mbp3_automute(codec); +} + + static struct hda_verb alc882_targa_verbs[] = { {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, @@ -5198,11 +5503,10 @@ static void alc882_targa_automute(struct hda_codec *codec) present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); - snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); - snd_hda_codec_write(codec, 1, 0, AC_VERB_SET_GPIO_DATA, present ? 1 : 3); + snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA, + present ? 1 : 3); } static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res) @@ -5233,6 +5537,24 @@ static struct hda_verb alc882_asus_a7j_verbs[] = { { } /* end */ }; +static struct hda_verb alc882_asus_a7m_verbs[] = { + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */ + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ + {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */ + + {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */ + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */ + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ + { } /* end */ +}; + static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted) { unsigned int gpiostate, gpiomask, gpiodir; @@ -5265,6 +5587,20 @@ static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted) AC_VERB_SET_GPIO_DATA, gpiostate); } +/* set up GPIO at initialization */ +static void alc885_macpro_init_hook(struct hda_codec *codec) +{ + alc882_gpio_mute(codec, 0, 0); + alc882_gpio_mute(codec, 1, 0); +} + +/* set up GPIO and update auto-muting at initialization */ +static void alc885_imac24_init_hook(struct hda_codec *codec) +{ + alc885_macpro_init_hook(codec); + alc885_imac24_automute(codec); +} + /* * generic initialization of ADC, input mixers and output mixers */ @@ -5279,17 +5615,17 @@ static struct hda_verb alc882_auto_init_verbs[] = { {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback * mixer widget * Note: PASD motherboards uses the Line In 2 as the input for * front panel mic (mic 2) */ /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* * Set up output mixers (0x0c - 0x0f) @@ -5378,6 +5714,10 @@ static struct snd_kcontrol_new alc882_capture_mixer[] = { { } /* end */ }; +#ifdef CONFIG_SND_HDA_POWER_SAVE +#define alc882_loopbacks alc880_loopbacks +#endif + /* pcm configuration: identiacal with ALC880 */ #define alc882_pcm_analog_playback alc880_pcm_analog_playback #define alc882_pcm_analog_capture alc880_pcm_analog_capture @@ -5392,7 +5732,11 @@ static const char *alc882_models[ALC882_MODEL_LAST] = { [ALC882_6ST_DIG] = "6stack-dig", [ALC882_ARIMA] = "arima", [ALC882_W2JC] = "w2jc", + [ALC882_TARGA] = "targa", + [ALC882_ASUS_A7J] = "asus-a7j", + [ALC882_ASUS_A7M] = "asus-a7m", [ALC885_MACPRO] = "macpro", + [ALC885_MBP3] = "mbp3", [ALC885_IMAC24] = "imac24", [ALC882_AUTO] = "auto", }; @@ -5404,6 +5748,8 @@ static struct snd_pci_quirk alc882_cfg_tbl[] = { SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */ SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA), SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J), + SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J), + SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M), SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG), SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG), SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC), @@ -5455,6 +5801,20 @@ static struct alc_config_preset alc882_presets[] = { .input_mux = &alc882_capture_source, .dig_out_nid = ALC882_DIGOUT_NID, }, + [ALC885_MBP3] = { + .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer }, + .init_verbs = { alc885_mbp3_init_verbs, + alc880_gpio1_init_verbs }, + .num_dacs = ARRAY_SIZE(alc882_dac_nids), + .dac_nids = alc882_dac_nids, + .channel_mode = alc885_mbp_6ch_modes, + .num_channel_mode = ARRAY_SIZE(alc885_mbp_6ch_modes), + .input_mux = &alc882_capture_source, + .dig_out_nid = ALC882_DIGOUT_NID, + .dig_in_nid = ALC882_DIGIN_NID, + .unsol_event = alc885_mbp3_unsol_event, + .init_hook = alc885_mbp3_automute, + }, [ALC885_MACPRO] = { .mixers = { alc882_macpro_mixer }, .init_verbs = { alc882_macpro_init_verbs }, @@ -5465,6 +5825,7 @@ static struct alc_config_preset alc882_presets[] = { .num_channel_mode = ARRAY_SIZE(alc882_ch_modes), .channel_mode = alc882_ch_modes, .input_mux = &alc882_capture_source, + .init_hook = alc885_macpro_init_hook, }, [ALC885_IMAC24] = { .mixers = { alc885_imac24_mixer }, @@ -5477,7 +5838,7 @@ static struct alc_config_preset alc882_presets[] = { .channel_mode = alc882_ch_modes, .input_mux = &alc882_capture_source, .unsol_event = alc885_imac24_unsol_event, - .init_hook = alc885_imac24_automute, + .init_hook = alc885_imac24_init_hook, }, [ALC882_TARGA] = { .mixers = { alc882_targa_mixer, alc882_chmode_mixer, @@ -5509,6 +5870,19 @@ static struct alc_config_preset alc882_presets[] = { .need_dac_fix = 1, .input_mux = &alc882_capture_source, }, + [ALC882_ASUS_A7M] = { + .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer }, + .init_verbs = { alc882_init_verbs, alc882_eapd_verbs, + alc880_gpio1_init_verbs, + alc882_asus_a7m_verbs }, + .num_dacs = ARRAY_SIZE(alc882_dac_nids), + .dac_nids = alc882_dac_nids, + .dig_out_nid = ALC882_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), + .channel_mode = alc880_threestack_modes, + .need_dac_fix = 1, + .input_mux = &alc882_capture_source, + }, }; @@ -5608,6 +5982,32 @@ static void alc882_auto_init_analog_input(struct hda_codec *codec) } } +/* add mic boosts if needed */ +static int alc_auto_add_mic_boost(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int err; + hda_nid_t nid; + + nid = spec->autocfg.input_pins[AUTO_PIN_MIC]; + if (nid) { + err = add_control(spec, ALC_CTL_WIDGET_VOL, + "Mic Boost", + HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT)); + if (err < 0) + return err; + } + nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC]; + if (nid) { + err = add_control(spec, ALC_CTL_WIDGET_VOL, + "Front Mic Boost", + HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT)); + if (err < 0) + return err; + } + return 0; +} + /* almost identical with ALC880 parser... */ static int alc882_parse_auto_config(struct hda_codec *codec) { @@ -5616,10 +6016,17 @@ static int alc882_parse_auto_config(struct hda_codec *codec) if (err < 0) return err; - else if (err > 0) - /* hack - override the init verbs */ - spec->init_verbs[0] = alc882_auto_init_verbs; - return err; + else if (!err) + return 0; /* no config found */ + + err = alc_auto_add_mic_boost(codec); + if (err < 0) + return err; + + /* hack - override the init verbs */ + spec->init_verbs[0] = alc882_auto_init_verbs; + + return 1; /* config found */ } /* additional initialization for auto-configuration model */ @@ -5654,6 +6061,9 @@ static int patch_alc882(struct hda_codec *codec) case 0x106b1000: /* iMac 24 */ board_config = ALC885_IMAC24; break; + case 0x106b2c00: /* Macbook Pro rev3 */ + board_config = ALC885_MBP3; + break; default: printk(KERN_INFO "hda_codec: Unknown model for ALC882, " "trying auto-probe from BIOS...\n"); @@ -5680,11 +6090,6 @@ static int patch_alc882(struct hda_codec *codec) if (board_config != ALC882_AUTO) setup_preset(spec, &alc882_presets[board_config]); - if (board_config == ALC885_MACPRO || board_config == ALC885_IMAC24) { - alc882_gpio_mute(codec, 0, 0); - alc882_gpio_mute(codec, 1, 0); - } - spec->stream_name_analog = "ALC882 Analog"; spec->stream_analog_playback = &alc882_pcm_analog_playback; spec->stream_analog_capture = &alc882_pcm_analog_capture; @@ -5715,6 +6120,10 @@ static int patch_alc882(struct hda_codec *codec) codec->patch_ops = alc_patch_ops; if (board_config == ALC882_AUTO) spec->init_hook = alc882_auto_init; +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (!spec->loopback.amplist) + spec->loopback.amplist = alc882_loopbacks; +#endif return 0; } @@ -5792,12 +6201,13 @@ static int alc883_mux_enum_put(struct snd_kcontrol *kcontrol, idx = ucontrol->value.enumerated.item[0]; if (idx >= imux->num_items) idx = imux->num_items - 1; - if (*cur_val == idx && !codec->in_resume) + if (*cur_val == idx) return 0; for (i = 0; i < imux->num_items; i++) { - unsigned int v = (i == idx) ? 0x7000 : 0x7080; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, - v | (imux->items[i].index << 8)); + unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE; + snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, + imux->items[i].index, + HDA_AMP_MUTE, v); } *cur_val = idx; return 1; @@ -5822,6 +6232,18 @@ static struct hda_verb alc883_3ST_ch2_init[] = { }; /* + * 4ch mode + */ +static struct hda_verb alc883_3ST_ch4_init[] = { + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { } /* end */ +}; + +/* * 6ch mode */ static struct hda_verb alc883_3ST_ch6_init[] = { @@ -5834,8 +6256,9 @@ static struct hda_verb alc883_3ST_ch6_init[] = { { } /* end */ }; -static struct hda_channel_mode alc883_3ST_6ch_modes[2] = { +static struct hda_channel_mode alc883_3ST_6ch_modes[3] = { { 2, alc883_3ST_ch2_init }, + { 4, alc883_3ST_ch4_init }, { 6, alc883_3ST_ch6_init }, }; @@ -6235,6 +6658,31 @@ static struct snd_kcontrol_new alc888_3st_hp_mixer[] = { { } /* end */ }; +static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 2, + .info = alc883_mux_enum_info, + .get = alc883_mux_enum_get, + .put = alc883_mux_enum_put, + }, + { } /* end */ +}; + static struct snd_kcontrol_new alc883_chmode_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -6270,11 +6718,12 @@ static struct hda_verb alc883_init_verbs[] = { {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + /* mute analog input loopbacks */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* Front Pin: output 0 (0x0c) */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, @@ -6366,6 +6815,19 @@ static struct hda_verb alc888_lenovo_ms7195_verbs[] = { { } /* end */ }; +static struct hda_verb alc883_haier_w66_verbs[] = { + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + { } /* end */ +}; + static struct hda_verb alc888_6st_hp_verbs[] = { {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */ {0x15, AC_VERB_SET_CONNECT_SEL, 0x02}, /* Rear : output 2 (0x0e) */ @@ -6409,15 +6871,10 @@ static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec) present = snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); - snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); - snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); - snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); - + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); } /* toggle RCA according to the front-jack state */ @@ -6427,12 +6884,10 @@ static void alc888_lenovo_ms7195_rca_automute(struct hda_codec *codec) present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); - snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); - + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); } + static void alc883_lenovo_ms7195_unsol_event(struct hda_codec *codec, unsigned int res) { @@ -6459,10 +6914,8 @@ static void alc883_medion_md2_automute(struct hda_codec *codec) present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); - snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); } static void alc883_medion_md2_unsol_event(struct hda_codec *codec, @@ -6480,13 +6933,11 @@ static void alc883_tagra_automute(struct hda_codec *codec) present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_write(codec, 1, 0, AC_VERB_SET_GPIO_DATA, - present ? 1 : 3); + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); + snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA, + present ? 1 : 3); } static void alc883_tagra_unsol_event(struct hda_codec *codec, unsigned int res) @@ -6495,6 +6946,25 @@ static void alc883_tagra_unsol_event(struct hda_codec *codec, unsigned int res) alc883_tagra_automute(codec); } +static void alc883_haier_w66_automute(struct hda_codec *codec) +{ + unsigned int present; + unsigned char bits; + + present = snd_hda_codec_read(codec, 0x1b, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + bits = present ? 0x80 : 0; + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + 0x80, bits); +} + +static void alc883_haier_w66_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) == ALC880_HP_EVENT) + alc883_haier_w66_automute(codec); +} + static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec) { unsigned int present; @@ -6502,11 +6972,9 @@ static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec) present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, - 0x80, bits); + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); } static void alc883_lenovo_101e_all_automute(struct hda_codec *codec) @@ -6516,15 +6984,11 @@ static void alc883_lenovo_101e_all_automute(struct hda_codec *codec) present = snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, - 0x80, bits); + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); } static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec, @@ -6536,6 +7000,44 @@ static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec, alc883_lenovo_101e_ispeaker_automute(codec); } +/* toggle speaker-output according to the hp-jack state */ +static void alc883_acer_aspire_automute(struct hda_codec *codec) +{ + unsigned int present; + + present = snd_hda_codec_read(codec, 0x14, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); +} + +static void alc883_acer_aspire_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) == ALC880_HP_EVENT) + alc883_acer_aspire_automute(codec); +} + +static struct hda_verb alc883_acer_eapd_verbs[] = { + /* HP Pin: output 0 (0x0c) */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* Front Pin: output 0 (0x0c) */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* eanable EAPD on medion laptop */ + {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, + {0x20, AC_VERB_SET_PROC_COEF, 0x3050}, + /* enable unsolicited event */ + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + { } +}; + /* * generic initialization of ADC, input mixers and output mixers */ @@ -6548,17 +7050,17 @@ static struct hda_verb alc883_auto_init_verbs[] = { {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback * mixer widget * Note: PASD motherboards uses the Line In 2 as the input for * front panel mic (mic 2) */ /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* * Set up output mixers (0x0c - 0x0f) @@ -6621,6 +7123,10 @@ static struct snd_kcontrol_new alc883_capture_mixer[] = { { } /* end */ }; +#ifdef CONFIG_SND_HDA_POWER_SAVE +#define alc883_loopbacks alc880_loopbacks +#endif + /* pcm configuration: identiacal with ALC880 */ #define alc883_pcm_analog_playback alc880_pcm_analog_playback #define alc883_pcm_analog_capture alc880_pcm_analog_capture @@ -6638,12 +7144,14 @@ static const char *alc883_models[ALC883_MODEL_LAST] = { [ALC883_TARGA_DIG] = "targa-dig", [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig", [ALC883_ACER] = "acer", + [ALC883_ACER_ASPIRE] = "acer-aspire", [ALC883_MEDION] = "medion", [ALC883_MEDION_MD2] = "medion-md2", [ALC883_LAPTOP_EAPD] = "laptop-eapd", [ALC883_LENOVO_101E_2ch] = "lenovo-101e", [ALC883_LENOVO_NB0763] = "lenovo-nb0763", [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig", + [ALC883_HAIER_W66] = "haier-w66", [ALC888_6ST_HP] = "6stack-hp", [ALC888_3ST_HP] = "3stack-hp", [ALC883_AUTO] = "auto", @@ -6669,10 +7177,14 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG), SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG), SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG), + SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG), SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG), SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG), SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG), SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG), + SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE), + SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE), + SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE), SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER), SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch), SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION), @@ -6685,6 +7197,10 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP), SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP), SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2), + SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66), + SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763), + SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG), + SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG), {} }; @@ -6771,8 +7287,7 @@ static struct alc_config_preset alc883_presets[] = { .init_hook = alc883_tagra_automute, }, [ALC883_ACER] = { - .mixers = { alc883_base_mixer, - alc883_chmode_mixer }, + .mixers = { alc883_base_mixer }, /* On TravelMate laptops, GPIO 0 enables the internal speaker * and the headphone jack. Turn this on and rely on the * standard mute methods whenever the user wants to turn @@ -6787,6 +7302,20 @@ static struct alc_config_preset alc883_presets[] = { .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_capture_source, }, + [ALC883_ACER_ASPIRE] = { + .mixers = { alc883_acer_aspire_mixer }, + .init_verbs = { alc883_init_verbs, alc883_acer_eapd_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), + .adc_nids = alc883_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), + .channel_mode = alc883_3ST_2ch_modes, + .input_mux = &alc883_capture_source, + .unsol_event = alc883_acer_aspire_unsol_event, + .init_hook = alc883_acer_aspire_automute, + }, [ALC883_MEDION] = { .mixers = { alc883_fivestack_mixer, alc883_chmode_mixer }, @@ -6815,8 +7344,7 @@ static struct alc_config_preset alc883_presets[] = { .init_hook = alc883_medion_md2_automute, }, [ALC883_LAPTOP_EAPD] = { - .mixers = { alc883_base_mixer, - alc883_chmode_mixer }, + .mixers = { alc883_base_mixer }, .init_verbs = { alc883_init_verbs, alc882_eapd_verbs }, .num_dacs = ARRAY_SIZE(alc883_dac_nids), .dac_nids = alc883_dac_nids, @@ -6867,6 +7395,20 @@ static struct alc_config_preset alc883_presets[] = { .input_mux = &alc883_capture_source, .unsol_event = alc883_lenovo_ms7195_unsol_event, .init_hook = alc888_lenovo_ms7195_front_automute, + }, + [ALC883_HAIER_W66] = { + .mixers = { alc883_tagra_2ch_mixer}, + .init_verbs = { alc883_init_verbs, alc883_haier_w66_verbs}, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), + .adc_nids = alc883_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), + .channel_mode = alc883_3ST_2ch_modes, + .input_mux = &alc883_capture_source, + .unsol_event = alc883_haier_w66_unsol_event, + .init_hook = alc883_haier_w66_automute, }, [ALC888_6ST_HP] = { .mixers = { alc888_6st_hp_mixer, alc883_chmode_mixer }, @@ -6977,12 +7519,19 @@ static int alc883_parse_auto_config(struct hda_codec *codec) if (err < 0) return err; - else if (err > 0) - /* hack - override the init verbs */ - spec->init_verbs[0] = alc883_auto_init_verbs; + else if (!err) + return 0; /* no config found */ + + err = alc_auto_add_mic_boost(codec); + if (err < 0) + return err; + + /* hack - override the init verbs */ + spec->init_verbs[0] = alc883_auto_init_verbs; spec->mixers[spec->num_mixers] = alc883_capture_mixer; spec->num_mixers++; - return err; + + return 1; /* config found */ } /* additional initialization for auto-configuration model */ @@ -7046,6 +7595,10 @@ static int patch_alc883(struct hda_codec *codec) codec->patch_ops = alc_patch_ops; if (board_config == ALC883_AUTO) spec->init_hook = alc883_auto_init; +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (!spec->loopback.amplist) + spec->loopback.amplist = alc883_loopbacks; +#endif return 0; } @@ -7156,9 +7709,46 @@ static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = { { } /* end */ }; +/* bind hp and internal speaker mute (with plug check) */ +static int alc262_sony_master_sw_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + long *valp = ucontrol->value.integer.value; + int change; + + /* change hp mute */ + change = snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, + HDA_AMP_MUTE, + valp[0] ? 0 : HDA_AMP_MUTE); + change |= snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, + HDA_AMP_MUTE, + valp[1] ? 0 : HDA_AMP_MUTE); + if (change) { + /* change speaker according to HP jack state */ + struct alc_spec *spec = codec->spec; + unsigned int mute; + if (spec->jack_present) + mute = HDA_AMP_MUTE; + else + mute = snd_hda_codec_amp_read(codec, 0x15, 0, + HDA_OUTPUT, 0); + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); + } + return change; +} + static struct snd_kcontrol_new alc262_sony_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .info = snd_hda_mixer_amp_switch_info, + .get = snd_hda_mixer_amp_switch_get, + .put = alc262_sony_master_sw_put, + .private_value = HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT), + }, HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), @@ -7194,17 +7784,17 @@ static struct hda_verb alc262_init_verbs[] = { {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback * mixer widget * Note: PASD motherboards uses the Line In 2 as the input for * front panel mic (mic 2) */ /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* * Set up output mixers (0x0c - 0x0e) @@ -7285,34 +7875,26 @@ static struct hda_verb alc262_sony_unsol_verbs[] = { }; /* mute/unmute internal speaker according to the hp jack and mute state */ -static void alc262_hippo_automute(struct hda_codec *codec, int force) +static void alc262_hippo_automute(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; unsigned int mute; + unsigned int present; - if (force || !spec->sense_updated) { - unsigned int present; - /* need to execute and sync at first */ - snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0); - present = snd_hda_codec_read(codec, 0x15, 0, - AC_VERB_GET_PIN_SENSE, 0); - spec->jack_present = (present & 0x80000000) != 0; - spec->sense_updated = 1; - } + /* need to execute and sync at first */ + snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0); + present = snd_hda_codec_read(codec, 0x15, 0, + AC_VERB_GET_PIN_SENSE, 0); + spec->jack_present = (present & 0x80000000) != 0; if (spec->jack_present) { /* mute internal speaker */ - snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, - 0x80, 0x80); - snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, - 0x80, 0x80); + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, HDA_AMP_MUTE); } else { /* unmute internal speaker if necessary */ mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0); - snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, - 0x80, mute & 0x80); - mute = snd_hda_codec_amp_read(codec, 0x15, 1, HDA_OUTPUT, 0); - snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, - 0x80, mute & 0x80); + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); } } @@ -7322,37 +7904,27 @@ static void alc262_hippo_unsol_event(struct hda_codec *codec, { if ((res >> 26) != ALC880_HP_EVENT) return; - alc262_hippo_automute(codec, 1); + alc262_hippo_automute(codec); } -static void alc262_hippo1_automute(struct hda_codec *codec, int force) +static void alc262_hippo1_automute(struct hda_codec *codec) { - struct alc_spec *spec = codec->spec; unsigned int mute; + unsigned int present; - if (force || !spec->sense_updated) { - unsigned int present; - /* need to execute and sync at first */ - snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0); - present = snd_hda_codec_read(codec, 0x1b, 0, - AC_VERB_GET_PIN_SENSE, 0); - spec->jack_present = (present & 0x80000000) != 0; - spec->sense_updated = 1; - } - if (spec->jack_present) { + snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0); + present = snd_hda_codec_read(codec, 0x1b, 0, + AC_VERB_GET_PIN_SENSE, 0); + present = (present & 0x80000000) != 0; + if (present) { /* mute internal speaker */ - snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, - 0x80, 0x80); - snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, - 0x80, 0x80); + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, HDA_AMP_MUTE); } else { /* unmute internal speaker if necessary */ mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0); - snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, - 0x80, mute & 0x80); - mute = snd_hda_codec_amp_read(codec, 0x1b, 1, HDA_OUTPUT, 0); - snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, - 0x80, mute & 0x80); + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); } } @@ -7362,7 +7934,7 @@ static void alc262_hippo1_unsol_event(struct hda_codec *codec, { if ((res >> 26) != ALC880_HP_EVENT) return; - alc262_hippo1_automute(codec, 1); + alc262_hippo1_automute(codec); } /* @@ -7379,9 +7951,10 @@ static struct hda_verb alc262_fujitsu_unsol_verbs[] = { }; static struct hda_input_mux alc262_fujitsu_capture_source = { - .num_items = 2, + .num_items = 3, .items = { { "Mic", 0x0 }, + { "Int Mic", 0x1 }, { "CD", 0x4 }, }, }; @@ -7390,13 +7963,23 @@ static struct hda_input_mux alc262_HP_capture_source = { .num_items = 5, .items = { { "Mic", 0x0 }, - { "Front Mic", 0x3 }, + { "Front Mic", 0x1 }, { "Line", 0x2 }, { "CD", 0x4 }, { "AUX IN", 0x6 }, }, }; +static struct hda_input_mux alc262_HP_D7000_capture_source = { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Front Mic", 0x2 }, + { "Line", 0x1 }, + { "CD", 0x4 }, + }, +}; + /* mute/unmute internal speaker according to the hp jack and mute state */ static void alc262_fujitsu_automute(struct hda_codec *codec, int force) { @@ -7414,18 +7997,13 @@ static void alc262_fujitsu_automute(struct hda_codec *codec, int force) } if (spec->jack_present) { /* mute internal speaker */ - snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, - 0x80, 0x80); - snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, - 0x80, 0x80); + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, HDA_AMP_MUTE); } else { /* unmute internal speaker if necessary */ mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0); - snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, - 0x80, mute & 0x80); - mute = snd_hda_codec_amp_read(codec, 0x14, 1, HDA_OUTPUT, 0); - snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, - 0x80, mute & 0x80); + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); } } @@ -7439,23 +8017,14 @@ static void alc262_fujitsu_unsol_event(struct hda_codec *codec, } /* bind volumes of both NID 0x0c and 0x0d */ -static int alc262_fujitsu_master_vol_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - long *valp = ucontrol->value.integer.value; - int change; - - change = snd_hda_codec_amp_update(codec, 0x0c, 0, HDA_OUTPUT, 0, - 0x7f, valp[0] & 0x7f); - change |= snd_hda_codec_amp_update(codec, 0x0c, 1, HDA_OUTPUT, 0, - 0x7f, valp[1] & 0x7f); - snd_hda_codec_amp_update(codec, 0x0d, 0, HDA_OUTPUT, 0, - 0x7f, valp[0] & 0x7f); - snd_hda_codec_amp_update(codec, 0x0d, 1, HDA_OUTPUT, 0, - 0x7f, valp[1] & 0x7f); - return change; -} +static struct hda_bind_ctls alc262_fujitsu_bind_master_vol = { + .ops = &snd_hda_bind_vol, + .values = { + HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x0d, 3, 0, HDA_OUTPUT), + 0 + }, +}; /* bind hp and internal speaker mute (with plug check) */ static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol, @@ -7466,24 +8035,18 @@ static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol, int change; change = snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, - 0x80, valp[0] ? 0 : 0x80); + HDA_AMP_MUTE, + valp[0] ? 0 : HDA_AMP_MUTE); change |= snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, - 0x80, valp[1] ? 0 : 0x80); - if (change || codec->in_resume) - alc262_fujitsu_automute(codec, codec->in_resume); + HDA_AMP_MUTE, + valp[1] ? 0 : HDA_AMP_MUTE); + if (change) + alc262_fujitsu_automute(codec, 0); return change; } static struct snd_kcontrol_new alc262_fujitsu_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Volume", - .info = snd_hda_mixer_amp_volume_info, - .get = snd_hda_mixer_amp_volume_get, - .put = alc262_fujitsu_master_vol_put, - .tlv = { .c = snd_hda_mixer_amp_tlv }, - .private_value = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT), - }, + HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", @@ -7497,6 +8060,9 @@ static struct snd_kcontrol_new alc262_fujitsu_mixer[] = { HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), { } /* end */ }; @@ -7611,17 +8177,17 @@ static struct hda_verb alc262_volume_init_verbs[] = { {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback * mixer widget * Note: PASD motherboards uses the Line In 2 as the input for * front panel mic (mic 2) */ /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* * Set up output mixers (0x0c - 0x0f) @@ -7672,19 +8238,19 @@ static struct hda_verb alc262_HP_BPC_init_verbs[] = { {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback * mixer widget * Note: PASD motherboards uses the Line In 2 as the input for * front panel mic (mic 2) */ /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(6)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* * Set up output mixers (0x0c - 0x0e) @@ -7759,20 +8325,20 @@ static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = { {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback * mixer widget * Note: PASD motherboards uses the Line In 2 as the input for front * panel mic (mic 2) */ /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(6)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(7)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* * Set up output mixers (0x0c - 0x0e) */ @@ -7842,6 +8408,10 @@ static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = { { } }; +#ifdef CONFIG_SND_HDA_POWER_SAVE +#define alc262_loopbacks alc880_loopbacks +#endif + /* pcm configuration: identiacal with ALC880 */ #define alc262_pcm_analog_playback alc880_pcm_analog_playback #define alc262_pcm_analog_capture alc880_pcm_analog_capture @@ -7884,6 +8454,10 @@ static int alc262_parse_auto_config(struct hda_codec *codec) spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux; + err = alc_auto_add_mic_boost(codec); + if (err < 0) + return err; + return 1; } @@ -7939,6 +8513,7 @@ static struct snd_pci_quirk alc262_cfg_tbl[] = { SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1), SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8), SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31), + SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD), SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD), SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD), SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD), @@ -7967,6 +8542,7 @@ static struct alc_config_preset alc262_presets[] = { .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, .unsol_event = alc262_hippo_unsol_event, + .init_hook = alc262_hippo_automute, }, [ALC262_HIPPO_1] = { .mixers = { alc262_hippo1_mixer }, @@ -7979,10 +8555,12 @@ static struct alc_config_preset alc262_presets[] = { .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, .unsol_event = alc262_hippo1_unsol_event, + .init_hook = alc262_hippo1_automute, }, [ALC262_FUJITSU] = { .mixers = { alc262_fujitsu_mixer }, - .init_verbs = { alc262_init_verbs, alc262_fujitsu_unsol_verbs }, + .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs, + alc262_fujitsu_unsol_verbs }, .num_dacs = ARRAY_SIZE(alc262_dac_nids), .dac_nids = alc262_dac_nids, .hp_nid = 0x03, @@ -8010,7 +8588,7 @@ static struct alc_config_preset alc262_presets[] = { .hp_nid = 0x03, .num_channel_mode = ARRAY_SIZE(alc262_modes), .channel_mode = alc262_modes, - .input_mux = &alc262_HP_capture_source, + .input_mux = &alc262_HP_D7000_capture_source, }, [ALC262_HP_BPC_D7000_WL] = { .mixers = { alc262_HP_BPC_WildWest_mixer, @@ -8021,7 +8599,7 @@ static struct alc_config_preset alc262_presets[] = { .hp_nid = 0x03, .num_channel_mode = ARRAY_SIZE(alc262_modes), .channel_mode = alc262_modes, - .input_mux = &alc262_HP_capture_source, + .input_mux = &alc262_HP_D7000_capture_source, }, [ALC262_BENQ_ED8] = { .mixers = { alc262_base_mixer }, @@ -8043,6 +8621,7 @@ static struct alc_config_preset alc262_presets[] = { .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, .unsol_event = alc262_hippo_unsol_event, + .init_hook = alc262_hippo_automute, }, [ALC262_BENQ_T31] = { .mixers = { alc262_benq_t31_mixer }, @@ -8054,6 +8633,7 @@ static struct alc_config_preset alc262_presets[] = { .channel_mode = alc262_modes, .input_mux = &alc262_capture_source, .unsol_event = alc262_hippo_unsol_event, + .init_hook = alc262_hippo_automute, }, }; @@ -8139,6 +8719,10 @@ static int patch_alc262(struct hda_codec *codec) codec->patch_ops = alc_patch_ops; if (board_config == ALC262_AUTO) spec->init_hook = alc262_auto_init; +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (!spec->loopback.amplist) + spec->loopback.amplist = alc262_loopbacks; +#endif return 0; } @@ -8170,9 +8754,125 @@ static struct snd_kcontrol_new alc268_base_mixer[] = { HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT), + { } +}; + +static struct hda_verb alc268_eapd_verbs[] = { + {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, + {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, + { } +}; + +/* Toshiba specific */ +#define alc268_toshiba_automute alc262_hippo_automute + +static struct hda_verb alc268_toshiba_verbs[] = { + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + { } /* end */ +}; + +/* Acer specific */ +/* bind volumes of both NID 0x02 and 0x03 */ +static struct hda_bind_ctls alc268_acer_bind_master_vol = { + .ops = &snd_hda_bind_vol, + .values = { + HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT), + 0 + }, +}; + +/* mute/unmute internal speaker according to the hp jack and mute state */ +static void alc268_acer_automute(struct hda_codec *codec, int force) +{ + struct alc_spec *spec = codec->spec; + unsigned int mute; + + if (force || !spec->sense_updated) { + unsigned int present; + present = snd_hda_codec_read(codec, 0x14, 0, + AC_VERB_GET_PIN_SENSE, 0); + spec->jack_present = (present & 0x80000000) != 0; + spec->sense_updated = 1; + } + if (spec->jack_present) + mute = HDA_AMP_MUTE; /* mute internal speaker */ + else /* unmute internal speaker if necessary */ + mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0); + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, mute); +} + + +/* bind hp and internal speaker mute (with plug check) */ +static int alc268_acer_master_sw_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + long *valp = ucontrol->value.integer.value; + int change; + + change = snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, + HDA_AMP_MUTE, + valp[0] ? 0 : HDA_AMP_MUTE); + change |= snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, + HDA_AMP_MUTE, + valp[1] ? 0 : HDA_AMP_MUTE); + if (change) + alc268_acer_automute(codec, 0); + return change; +} + +static struct snd_kcontrol_new alc268_acer_mixer[] = { + /* output mixer control */ + HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .info = snd_hda_mixer_amp_switch_info, + .get = snd_hda_mixer_amp_switch_get, + .put = alc268_acer_master_sw_put, + .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), + }, + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT), { } }; +static struct hda_verb alc268_acer_verbs[] = { + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + { } +}; + +/* unsolicited event for HP jack sensing */ +static void alc268_toshiba_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) != ALC880_HP_EVENT) + return; + alc268_toshiba_automute(codec); +} + +static void alc268_acer_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) != ALC880_HP_EVENT) + return; + alc268_acer_automute(codec, 1); +} + +static void alc268_acer_init_hook(struct hda_codec *codec) +{ + alc268_acer_automute(codec, 1); +} + /* * generic initialization of ADC, input mixers and output mixers */ @@ -8282,14 +8982,16 @@ static int alc268_mux_enum_put(struct snd_kcontrol *kcontrol, idx = ucontrol->value.enumerated.item[0]; if (idx >= imux->num_items) idx = imux->num_items - 1; - if (*cur_val == idx && !codec->in_resume) + if (*cur_val == idx) return 0; for (i = 0; i < imux->num_items; i++) { - unsigned int v = (i == idx) ? 0x7000 : 0x7080; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, - v | (imux->items[i].index << 8)); - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, - idx ); + unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE; + snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, + imux->items[i].index, + HDA_AMP_MUTE, v); + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_CONNECT_SEL, + idx ); } *cur_val = idx; return 1; @@ -8530,6 +9232,10 @@ static int alc268_parse_auto_config(struct hda_codec *codec) spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux; + err = alc_auto_add_mic_boost(codec); + if (err < 0) + return err; + return 1; } @@ -8551,11 +9257,19 @@ static void alc268_auto_init(struct hda_codec *codec) */ static const char *alc268_models[ALC268_MODEL_LAST] = { [ALC268_3ST] = "3stack", + [ALC268_TOSHIBA] = "toshiba", + [ALC268_ACER] = "acer", [ALC268_AUTO] = "auto", }; static struct snd_pci_quirk alc268_cfg_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST), + SND_PCI_QUIRK(0x1179, 0xff10, "TOSHIBA A205", ALC268_TOSHIBA), + SND_PCI_QUIRK(0x1179, 0xff50, "TOSHIBA A305", ALC268_TOSHIBA), + SND_PCI_QUIRK(0x103c, 0x30cc, "TOSHIBA", ALC268_TOSHIBA), + SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER), + SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER), + SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER), {} }; @@ -8573,6 +9287,37 @@ static struct alc_config_preset alc268_presets[] = { .channel_mode = alc268_modes, .input_mux = &alc268_capture_source, }, + [ALC268_TOSHIBA] = { + .mixers = { alc268_base_mixer, alc268_capture_alt_mixer }, + .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, + alc268_toshiba_verbs }, + .num_dacs = ARRAY_SIZE(alc268_dac_nids), + .dac_nids = alc268_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), + .adc_nids = alc268_adc_nids_alt, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc268_modes), + .channel_mode = alc268_modes, + .input_mux = &alc268_capture_source, + .input_mux = &alc268_capture_source, + .unsol_event = alc268_toshiba_unsol_event, + .init_hook = alc268_toshiba_automute, + }, + [ALC268_ACER] = { + .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer }, + .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, + alc268_acer_verbs }, + .num_dacs = ARRAY_SIZE(alc268_dac_nids), + .dac_nids = alc268_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), + .adc_nids = alc268_adc_nids_alt, + .hp_nid = 0x02, + .num_channel_mode = ARRAY_SIZE(alc268_modes), + .channel_mode = alc268_modes, + .input_mux = &alc268_capture_source, + .unsol_event = alc268_acer_unsol_event, + .init_hook = alc268_acer_init_hook, + }, }; static int patch_alc268(struct hda_codec *codec) @@ -9279,14 +10024,10 @@ static void alc861_toshiba_automute(struct hda_codec *codec) present = snd_hda_codec_read(codec, 0x0f, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - snd_hda_codec_amp_update(codec, 0x16, 0, HDA_INPUT, 0, - 0x80, present ? 0x80 : 0); - snd_hda_codec_amp_update(codec, 0x16, 1, HDA_INPUT, 0, - 0x80, present ? 0x80 : 0); - snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_INPUT, 3, - 0x80, present ? 0 : 0x80); - snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_INPUT, 3, - 0x80, present ? 0 : 0x80); + snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3, + HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE); } static void alc861_toshiba_unsol_event(struct hda_codec *codec, @@ -9599,6 +10340,16 @@ static void alc861_auto_init(struct hda_codec *codec) alc861_auto_init_analog_input(codec); } +#ifdef CONFIG_SND_HDA_POWER_SAVE +static struct hda_amp_list alc861_loopbacks[] = { + { 0x15, HDA_INPUT, 0 }, + { 0x15, HDA_INPUT, 1 }, + { 0x15, HDA_INPUT, 2 }, + { 0x15, HDA_INPUT, 3 }, + { } /* end */ +}; +#endif + /* * configuration and preset @@ -9796,6 +10547,10 @@ static int patch_alc861(struct hda_codec *codec) codec->patch_ops = alc_patch_ops; if (board_config == ALC861_AUTO) spec->init_hook = alc861_auto_init; +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (!spec->loopback.amplist) + spec->loopback.amplist = alc861_loopbacks; +#endif return 0; } @@ -9852,6 +10607,14 @@ static struct hda_input_mux alc861vd_dallas_capture_source = { }, }; +static struct hda_input_mux alc861vd_hp_capture_source = { + .num_items = 2, + .items = { + { "Front Mic", 0x0 }, + { "ATAPI Mic", 0x1 }, + }, +}; + #define alc861vd_mux_enum_info alc_mux_enum_info #define alc861vd_mux_enum_get alc_mux_enum_get @@ -9870,12 +10633,13 @@ static int alc861vd_mux_enum_put(struct snd_kcontrol *kcontrol, idx = ucontrol->value.enumerated.item[0]; if (idx >= imux->num_items) idx = imux->num_items - 1; - if (*cur_val == idx && !codec->in_resume) + if (*cur_val == idx) return 0; for (i = 0; i < imux->num_items; i++) { - unsigned int v = (i == idx) ? 0x7000 : 0x7080; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, - v | (imux->items[i].index << 8)); + unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE; + snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, + imux->items[i].index, + HDA_AMP_MUTE, v); } *cur_val = idx; return 1; @@ -10049,17 +10813,22 @@ static struct snd_kcontrol_new alc861vd_dallas_mixer[] = { HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x05, HDA_INPUT), HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 1, - .info = alc882_mux_enum_info, - .get = alc882_mux_enum_get, - .put = alc882_mux_enum_put, - }, + { } /* end */ +}; + +/* Pin assignment: Speaker=0x14, Line-out = 0x15, + * Front Mic=0x18, ATAPI Mic = 0x19, + */ +static struct snd_kcontrol_new alc861vd_hp_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ }; @@ -10077,11 +10846,11 @@ static struct hda_verb alc861vd_volume_init_verbs[] = { * the analog-loopback mixer widget */ /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, @@ -10210,11 +10979,9 @@ static void alc861vd_lenovo_hp_automute(struct hda_codec *codec) present = snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, - 0x80, bits); + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); } static void alc861vd_lenovo_mic_automute(struct hda_codec *codec) @@ -10224,11 +10991,9 @@ static void alc861vd_lenovo_mic_automute(struct hda_codec *codec) present = snd_hda_codec_read(codec, 0x18, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x0b, 0, HDA_INPUT, 1, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x0b, 1, HDA_INPUT, 1, - 0x80, bits); + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, + HDA_AMP_MUTE, bits); } static void alc861vd_lenovo_automute(struct hda_codec *codec) @@ -10302,10 +11067,8 @@ static void alc861vd_dallas_automute(struct hda_codec *codec) present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); - snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, - 0x80, present ? 0x80 : 0); + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); } static void alc861vd_dallas_unsol_event(struct hda_codec *codec, unsigned int res) @@ -10314,6 +11077,10 @@ static void alc861vd_dallas_unsol_event(struct hda_codec *codec, unsigned int re alc861vd_dallas_automute(codec); } +#ifdef CONFIG_SND_HDA_POWER_SAVE +#define alc861vd_loopbacks alc880_loopbacks +#endif + /* pcm configuration: identiacal with ALC880 */ #define alc861vd_pcm_analog_playback alc880_pcm_analog_playback #define alc861vd_pcm_analog_capture alc880_pcm_analog_capture @@ -10325,12 +11092,13 @@ static void alc861vd_dallas_unsol_event(struct hda_codec *codec, unsigned int re */ static const char *alc861vd_models[ALC861VD_MODEL_LAST] = { [ALC660VD_3ST] = "3stack-660", - [ALC660VD_3ST_DIG]= "3stack-660-digout", + [ALC660VD_3ST_DIG] = "3stack-660-digout", [ALC861VD_3ST] = "3stack", [ALC861VD_3ST_DIG] = "3stack-digout", [ALC861VD_6ST_DIG] = "6stack-digout", [ALC861VD_LENOVO] = "lenovo", [ALC861VD_DALLAS] = "dallas", + [ALC861VD_HP] = "hp", [ALC861VD_AUTO] = "auto", }; @@ -10341,11 +11109,15 @@ static struct snd_pci_quirk alc861vd_cfg_tbl[] = { SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST), SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST), - SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS), + /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/ SND_PCI_QUIRK(0x1179, 0xff01, "DALLAS", ALC861VD_DALLAS), SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_LENOVO), SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo", ALC861VD_LENOVO), SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO), + SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO), + SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG), + SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG), + SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP), {} }; @@ -10435,7 +11207,21 @@ static struct alc_config_preset alc861vd_presets[] = { .input_mux = &alc861vd_dallas_capture_source, .unsol_event = alc861vd_dallas_unsol_event, .init_hook = alc861vd_dallas_automute, - }, + }, + [ALC861VD_HP] = { + .mixers = { alc861vd_hp_mixer }, + .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs }, + .num_dacs = ARRAY_SIZE(alc861vd_dac_nids), + .dac_nids = alc861vd_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids), + .dig_out_nid = ALC861VD_DIGOUT_NID, + .adc_nids = alc861vd_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), + .channel_mode = alc861vd_3stack_2ch_modes, + .input_mux = &alc861vd_hp_capture_source, + .unsol_event = alc861vd_dallas_unsol_event, + .init_hook = alc861vd_dallas_automute, + }, }; /* @@ -10668,6 +11454,10 @@ static int alc861vd_parse_auto_config(struct hda_codec *codec) spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux; + err = alc_auto_add_mic_boost(codec); + if (err < 0) + return err; + return 1; } @@ -10735,6 +11525,10 @@ static int patch_alc861vd(struct hda_codec *codec) if (board_config == ALC861VD_AUTO) spec->init_hook = alc861vd_auto_init; +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (!spec->loopback.amplist) + spec->loopback.amplist = alc861vd_loopbacks; +#endif return 0; } @@ -10782,6 +11576,15 @@ static struct hda_input_mux alc662_lenovo_101e_capture_source = { { "Line", 0x2 }, }, }; + +static struct hda_input_mux alc662_eeepc_capture_source = { + .num_items = 2, + .items = { + { "i-Mic", 0x1 }, + { "e-Mic", 0x0 }, + }, +}; + #define alc662_mux_enum_info alc_mux_enum_info #define alc662_mux_enum_get alc_mux_enum_get @@ -10792,7 +11595,7 @@ static int alc662_mux_enum_put(struct snd_kcontrol *kcontrol, struct alc_spec *spec = codec->spec; const struct hda_input_mux *imux = spec->input_mux; unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - static hda_nid_t capture_mixers[3] = { 0x24, 0x23, 0x22 }; + static hda_nid_t capture_mixers[2] = { 0x23, 0x22 }; hda_nid_t nid = capture_mixers[adc_idx]; unsigned int *cur_val = &spec->cur_mux[adc_idx]; unsigned int i, idx; @@ -10800,12 +11603,13 @@ static int alc662_mux_enum_put(struct snd_kcontrol *kcontrol, idx = ucontrol->value.enumerated.item[0]; if (idx >= imux->num_items) idx = imux->num_items - 1; - if (*cur_val == idx && !codec->in_resume) + if (*cur_val == idx) return 0; for (i = 0; i < imux->num_items; i++) { - unsigned int v = (i == idx) ? 0x7000 : 0x7080; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, - v | (imux->items[i].index << 8)); + unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE; + snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, + imux->items[i].index, + HDA_AMP_MUTE, v); } *cur_val = idx; return 1; @@ -10997,6 +11801,22 @@ static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = { { } /* end */ }; +static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = { + HDA_CODEC_MUTE("iSpeaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME("LineOut Playback Volume", 0x02, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("LineOut Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME("e-Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("e-Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("e-Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + + HDA_CODEC_VOLUME("i-Mic Boost", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("i-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("i-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + static struct snd_kcontrol_new alc662_chmode_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -11014,18 +11834,18 @@ static struct hda_verb alc662_init_verbs[] = { {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front mixer: unmute input/output amp left and right (volume = 0) */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, /* Front Pin: output 0 (0x0c) */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, @@ -11062,13 +11882,24 @@ static struct hda_verb alc662_init_verbs[] = { {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, { } }; static struct hda_verb alc662_sue_init_verbs[] = { {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT}, {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT}, - {} + {} +}; + +static struct hda_verb alc662_eeepc_sue_init_verbs[] = { + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} }; /* @@ -11087,11 +11918,11 @@ static struct hda_verb alc662_auto_init_verbs[] = { * panel mic (mic 2) */ /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* * Set up output mixers (0x0c - 0x0f) @@ -11103,23 +11934,19 @@ static struct hda_verb alc662_auto_init_verbs[] = { /* set up input amps for analog loopback */ /* Amp Indices: DAC = 0, mixer = 1 */ - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, /* FIXME: use matrix-type input source selection */ /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ /* Input mixer */ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - /*{0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},*/ - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, { } }; @@ -11150,11 +11977,9 @@ static void alc662_lenovo_101e_ispeaker_automute(struct hda_codec *codec) present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, - 0x80, bits); + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); } static void alc662_lenovo_101e_all_automute(struct hda_codec *codec) @@ -11164,15 +11989,11 @@ static void alc662_lenovo_101e_all_automute(struct hda_codec *codec) present = snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? 0x80 : 0; - snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0, - 0x80, bits); - snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0, - 0x80, bits); + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); } static void alc662_lenovo_101e_unsol_event(struct hda_codec *codec, @@ -11184,6 +12005,43 @@ static void alc662_lenovo_101e_unsol_event(struct hda_codec *codec, alc662_lenovo_101e_ispeaker_automute(codec); } +static void alc662_eeepc_mic_automute(struct hda_codec *codec) +{ + unsigned int present; + + present = snd_hda_codec_read(codec, 0x18, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE, + 0x7000 | (0x00 << 8) | (present ? 0 : 0x80)); + snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE, + 0x7000 | (0x00 << 8) | (present ? 0 : 0x80)); + snd_hda_codec_write(codec, 0x22, 0, AC_VERB_SET_AMP_GAIN_MUTE, + 0x7000 | (0x01 << 8) | (present ? 0x80 : 0)); + snd_hda_codec_write(codec, 0x23, 0, AC_VERB_SET_AMP_GAIN_MUTE, + 0x7000 | (0x01 << 8) | (present ? 0x80 : 0)); +} + +/* unsolicited event for HP jack sensing */ +static void alc662_eeepc_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) == ALC880_HP_EVENT) + alc262_hippo1_automute( codec ); + + if ((res >> 26) == ALC880_MIC_EVENT) + alc662_eeepc_mic_automute(codec); +} + +static void alc662_eeepc_inithook(struct hda_codec *codec) +{ + alc262_hippo1_automute( codec ); + alc662_eeepc_mic_automute(codec); +} + +#ifdef CONFIG_SND_HDA_POWER_SAVE +#define alc662_loopbacks alc880_loopbacks +#endif + /* pcm configuration: identiacal with ALC880 */ #define alc662_pcm_analog_playback alc880_pcm_analog_playback @@ -11205,12 +12063,13 @@ static const char *alc662_models[ALC662_MODEL_LAST] = { static struct snd_pci_quirk alc662_cfg_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E), + SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701), {} }; static struct alc_config_preset alc662_presets[] = { [ALC662_3ST_2ch_DIG] = { - .mixers = { alc662_3ST_2ch_mixer }, + .mixers = { alc662_3ST_2ch_mixer, alc662_capture_mixer }, .init_verbs = { alc662_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, @@ -11223,7 +12082,8 @@ static struct alc_config_preset alc662_presets[] = { .input_mux = &alc662_capture_source, }, [ALC662_3ST_6ch_DIG] = { - .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer }, + .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer, + alc662_capture_mixer }, .init_verbs = { alc662_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, @@ -11237,7 +12097,8 @@ static struct alc_config_preset alc662_presets[] = { .input_mux = &alc662_capture_source, }, [ALC662_3ST_6ch] = { - .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer }, + .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer, + alc662_capture_mixer }, .init_verbs = { alc662_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, @@ -11249,7 +12110,8 @@ static struct alc_config_preset alc662_presets[] = { .input_mux = &alc662_capture_source, }, [ALC662_5ST_DIG] = { - .mixers = { alc662_base_mixer, alc662_chmode_mixer }, + .mixers = { alc662_base_mixer, alc662_chmode_mixer, + alc662_capture_mixer }, .init_verbs = { alc662_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, @@ -11262,7 +12124,7 @@ static struct alc_config_preset alc662_presets[] = { .input_mux = &alc662_capture_source, }, [ALC662_LENOVO_101E] = { - .mixers = { alc662_lenovo_101e_mixer }, + .mixers = { alc662_lenovo_101e_mixer, alc662_capture_mixer }, .init_verbs = { alc662_init_verbs, alc662_sue_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, @@ -11274,6 +12136,20 @@ static struct alc_config_preset alc662_presets[] = { .unsol_event = alc662_lenovo_101e_unsol_event, .init_hook = alc662_lenovo_101e_all_automute, }, + [ALC662_ASUS_EEEPC_P701] = { + .mixers = { alc662_eeepc_p701_mixer, alc662_capture_mixer }, + .init_verbs = { alc662_init_verbs, + alc662_eeepc_sue_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .dac_nids = alc662_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids), + .adc_nids = alc662_adc_nids, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .input_mux = &alc662_eeepc_capture_source, + .unsol_event = alc662_eeepc_unsol_event, + .init_hook = alc662_eeepc_inithook, + }, }; @@ -11296,7 +12172,7 @@ static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec, for (i = 0; i < cfg->line_outs; i++) { if (!spec->multiout.dac_nids[i]) continue; - nid = alc880_idx_to_mixer(i); + nid = alc880_idx_to_dac(i); if (i == 2) { /* Center/LFE */ err = add_control(spec, ALC_CTL_WIDGET_VOL, @@ -11586,6 +12462,10 @@ static int patch_alc662(struct hda_codec *codec) codec->patch_ops = alc_patch_ops; if (board_config == ALC662_AUTO) spec->init_hook = alc662_auto_init; +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (!spec->loopback.amplist) + spec->loopback.amplist = alc662_loopbacks; +#endif return 0; } diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c index 6d2ecc38905..2a4b9609aa5 100644 --- a/sound/pci/hda/patch_si3054.c +++ b/sound/pci/hda/patch_si3054.c @@ -78,6 +78,8 @@ /* si3054 codec registers (nodes) access macros */ #define GET_REG(codec,reg) (snd_hda_codec_read(codec,reg,0,SI3054_VERB_READ_NODE,0)) #define SET_REG(codec,reg,val) (snd_hda_codec_write(codec,reg,0,SI3054_VERB_WRITE_NODE,val)) +#define SET_REG_CACHE(codec,reg,val) \ + snd_hda_codec_write_cache(codec,reg,0,SI3054_VERB_WRITE_NODE,val) struct si3054_spec { @@ -94,15 +96,7 @@ struct si3054_spec { #define PRIVATE_REG(val) ((val>>16)&0xffff) #define PRIVATE_MASK(val) (val&0xffff) -static int si3054_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 si3054_switch_info snd_ctl_boolean_mono_info static int si3054_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *uvalue) @@ -121,9 +115,9 @@ static int si3054_switch_put(struct snd_kcontrol *kcontrol, u16 reg = PRIVATE_REG(kcontrol->private_value); u16 mask = PRIVATE_MASK(kcontrol->private_value); if (uvalue->value.integer.value[0]) - SET_REG(codec, reg, (GET_REG(codec, reg)) | mask); + SET_REG_CACHE(codec, reg, (GET_REG(codec, reg)) | mask); else - SET_REG(codec, reg, (GET_REG(codec, reg)) & ~mask); + SET_REG_CACHE(codec, reg, (GET_REG(codec, reg)) & ~mask); return 0; } @@ -275,10 +269,6 @@ static struct hda_codec_ops si3054_patch_ops = { .build_pcms = si3054_build_pcms, .init = si3054_init, .free = si3054_free, -#ifdef CONFIG_PM - //.suspend = si3054_suspend, - .resume = si3054_init, -#endif }; static int patch_si3054(struct hda_codec *codec) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 3f25de72966..bf950195107 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -39,12 +39,25 @@ enum { STAC_REF, + STAC_9200_DELL_D21, + STAC_9200_DELL_D22, + STAC_9200_DELL_D23, + STAC_9200_DELL_M21, + STAC_9200_DELL_M22, + STAC_9200_DELL_M23, + STAC_9200_DELL_M24, + STAC_9200_DELL_M25, + STAC_9200_DELL_M26, + STAC_9200_DELL_M27, + STAC_9200_GATEWAY, STAC_9200_MODELS }; enum { STAC_9205_REF, - STAC_M43xx, + STAC_9205_DELL_M42, + STAC_9205_DELL_M43, + STAC_9205_DELL_M44, STAC_9205_MODELS }; @@ -60,19 +73,22 @@ enum { STAC_D945_REF, STAC_D945GTP3, STAC_D945GTP5, - STAC_922X_DELL, STAC_INTEL_MAC_V1, STAC_INTEL_MAC_V2, STAC_INTEL_MAC_V3, STAC_INTEL_MAC_V4, STAC_INTEL_MAC_V5, - /* for backward compitability */ + /* for backward compatibility */ STAC_MACMINI, STAC_MACBOOK, STAC_MACBOOK_PRO_V1, STAC_MACBOOK_PRO_V2, STAC_IMAC_INTEL, STAC_IMAC_INTEL_20, + STAC_922X_DELL_D81, + STAC_922X_DELL_D82, + STAC_922X_DELL_M81, + STAC_922X_DELL_M82, STAC_922X_MODELS }; @@ -80,6 +96,7 @@ enum { STAC_D965_REF, STAC_D965_3ST, STAC_D965_5ST, + STAC_DELL_3ST, STAC_927X_MODELS }; @@ -95,6 +112,8 @@ struct sigmatel_spec { unsigned int hp_detect: 1; unsigned int gpio_mute: 1; + unsigned int gpio_mask, gpio_data; + /* playback */ struct hda_multi_out multiout; hda_nid_t dac_nids[5]; @@ -127,6 +146,8 @@ struct sigmatel_spec { /* i/o switches */ unsigned int io_switch[2]; + unsigned int clfe_swap; + unsigned int aloopback; struct hda_pcm pcm_rec[2]; /* PCM information */ @@ -162,8 +183,9 @@ static hda_nid_t stac925x_dac_nids[1] = { 0x02, }; -static hda_nid_t stac925x_dmic_nids[1] = { - 0x15, +#define STAC925X_NUM_DMICS 1 +static hda_nid_t stac925x_dmic_nids[STAC925X_NUM_DMICS + 1] = { + 0x15, 0 }; static hda_nid_t stac922x_adc_nids[2] = { @@ -190,8 +212,9 @@ static hda_nid_t stac9205_mux_nids[2] = { 0x19, 0x1a }; -static hda_nid_t stac9205_dmic_nids[2] = { - 0x17, 0x18, +#define STAC9205_NUM_DMICS 2 +static hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = { + 0x17, 0x18, 0 }; static hda_nid_t stac9200_pin_nids[8] = { @@ -276,12 +299,97 @@ static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]); } +#define stac92xx_aloopback_info snd_ctl_boolean_mono_info + +static int stac92xx_aloopback_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct sigmatel_spec *spec = codec->spec; + + ucontrol->value.integer.value[0] = spec->aloopback; + return 0; +} + +static int stac92xx_aloopback_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct sigmatel_spec *spec = codec->spec; + unsigned int dac_mode; + + if (spec->aloopback == ucontrol->value.integer.value[0]) + return 0; + + spec->aloopback = ucontrol->value.integer.value[0]; + + + dac_mode = snd_hda_codec_read(codec, codec->afg, 0, + kcontrol->private_value & 0xFFFF, 0x0); + + if (spec->aloopback) { + snd_hda_power_up(codec); + dac_mode |= 0x40; + } else { + snd_hda_power_down(codec); + dac_mode &= ~0x40; + } + + snd_hda_codec_write_cache(codec, codec->afg, 0, + kcontrol->private_value >> 16, dac_mode); + + return 1; +} + +static int stac92xx_volknob_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 127; + return 0; +} + +static int stac92xx_volknob_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = kcontrol->private_value & 0xff; + return 0; +} + +static int stac92xx_volknob_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + unsigned int val = kcontrol->private_value & 0xff; + + if (val == ucontrol->value.integer.value[0]) + return 0; + + val = ucontrol->value.integer.value[0]; + kcontrol->private_value &= ~0xff; + kcontrol->private_value |= val; + + snd_hda_codec_write_cache(codec, kcontrol->private_value >> 16, 0, + AC_VERB_SET_VOLUME_KNOB_CONTROL, val | 0x80); + return 1; +} + + static struct hda_verb stac9200_core_init[] = { /* set dac0mux for dac converter */ { 0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, {} }; +static struct hda_verb stac9200_eapd_init[] = { + /* set dac0mux for dac converter */ + {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x08, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, + {} +}; + static struct hda_verb stac925x_core_init[] = { /* set dac0mux for dac converter */ { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00}, @@ -316,17 +424,43 @@ static struct hda_verb stac9205_core_init[] = { {} }; +#define STAC_INPUT_SOURCE(cnt) \ + { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = "Input Source", \ + .count = cnt, \ + .info = stac92xx_mux_enum_info, \ + .get = stac92xx_mux_enum_get, \ + .put = stac92xx_mux_enum_put, \ + } + +#define STAC_ANALOG_LOOPBACK(verb_read,verb_write) \ + { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = "Analog Loopback", \ + .count = 1, \ + .info = stac92xx_aloopback_info, \ + .get = stac92xx_aloopback_get, \ + .put = stac92xx_aloopback_put, \ + .private_value = verb_read | (verb_write << 16), \ + } + +#define STAC_VOLKNOB(knob_nid) \ + { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = "Master Playback Volume", \ + .count = 1, \ + .info = stac92xx_volknob_info, \ + .get = stac92xx_volknob_get, \ + .put = stac92xx_volknob_put, \ + .private_value = 127 | (knob_nid << 16), \ + } + + static struct snd_kcontrol_new stac9200_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT), HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Input Source", - .count = 1, - .info = stac92xx_mux_enum_info, - .get = stac92xx_mux_enum_get, - .put = stac92xx_mux_enum_put, - }, + STAC_INPUT_SOURCE(1), HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT), HDA_CODEC_VOLUME("Capture Mux Volume", 0x0c, 0, HDA_OUTPUT), @@ -334,86 +468,68 @@ static struct snd_kcontrol_new stac9200_mixer[] = { }; static struct snd_kcontrol_new stac925x_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Input Source", - .count = 1, - .info = stac92xx_mux_enum_info, - .get = stac92xx_mux_enum_get, - .put = stac92xx_mux_enum_put, - }, + STAC_INPUT_SOURCE(1), HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_OUTPUT), HDA_CODEC_VOLUME("Capture Mux Volume", 0x0f, 0, HDA_OUTPUT), { } /* end */ }; -/* This needs to be generated dynamically based on sequence */ -static struct snd_kcontrol_new stac922x_mixer[] = { +static struct snd_kcontrol_new stac9205_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Input Source", + .name = "Digital Input Source", .count = 1, - .info = stac92xx_mux_enum_info, - .get = stac92xx_mux_enum_get, - .put = stac92xx_mux_enum_put, + .info = stac92xx_dmux_enum_info, + .get = stac92xx_dmux_enum_get, + .put = stac92xx_dmux_enum_put, }, - HDA_CODEC_VOLUME("Capture Volume", 0x17, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x17, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mux Capture Volume", 0x12, 0x0, HDA_OUTPUT), + STAC_INPUT_SOURCE(2), + STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0), + STAC_VOLKNOB(0x24), + + HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1d, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x19, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1c, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1e, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x1A, 0x0, HDA_OUTPUT), + { } /* end */ }; /* This needs to be generated dynamically based on sequence */ -static struct snd_kcontrol_new stac9227_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Input Source", - .count = 1, - .info = stac92xx_mux_enum_info, - .get = stac92xx_mux_enum_get, - .put = stac92xx_mux_enum_put, - }, - HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x1b, 0x0, HDA_OUTPUT), +static struct snd_kcontrol_new stac922x_mixer[] = { + STAC_INPUT_SOURCE(2), + STAC_VOLKNOB(0x16), + HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x12, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x13, 0x0, HDA_OUTPUT), { } /* end */ }; + static struct snd_kcontrol_new stac927x_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Input Source", - .count = 1, - .info = stac92xx_mux_enum_info, - .get = stac92xx_mux_enum_get, - .put = stac92xx_mux_enum_put, - }, - HDA_CODEC_VOLUME("InMux Capture Volume", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("InVol Capture Volume", 0x18, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("ADCMux Capture Switch", 0x1b, 0x0, HDA_OUTPUT), - { } /* end */ -}; + STAC_INPUT_SOURCE(3), + STAC_VOLKNOB(0x24), + STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB), -static struct snd_kcontrol_new stac9205_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Digital Input Source", - .count = 1, - .info = stac92xx_dmux_enum_info, - .get = stac92xx_dmux_enum_get, - .put = stac92xx_dmux_enum_put, - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Input Source", - .count = 1, - .info = stac92xx_mux_enum_info, - .get = stac92xx_mux_enum_get, - .put = stac92xx_mux_enum_put, - }, - HDA_CODEC_VOLUME("InMux Capture Volume", 0x19, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("InVol Capture Volume", 0x1b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("ADCMux Capture Switch", 0x1d, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x18, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x15, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x19, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1c, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x16, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME_IDX("Capture Volume", 0x2, 0x1A, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 0x2, 0x1d, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x2, 0x17, 0x0, HDA_OUTPUT), { } /* end */ }; @@ -451,12 +567,145 @@ static unsigned int ref9200_pin_configs[8] = { 0x02a19020, 0x01a19021, 0x90100140, 0x01813122, }; +/* + STAC 9200 pin configs for + 102801A8 + 102801DE + 102801E8 +*/ +static unsigned int dell9200_d21_pin_configs[8] = { + 0x400001f0, 0x400001f1, 0x02214030, 0x01014010, + 0x02a19020, 0x01a19021, 0x90100140, 0x01813122, +}; + +/* + STAC 9200 pin configs for + 102801C0 + 102801C1 +*/ +static unsigned int dell9200_d22_pin_configs[8] = { + 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010, + 0x01813020, 0x02a19021, 0x90100140, 0x400001f2, +}; + +/* + STAC 9200 pin configs for + 102801C4 (Dell Dimension E310) + 102801C5 + 102801C7 + 102801D9 + 102801DA + 102801E3 +*/ +static unsigned int dell9200_d23_pin_configs[8] = { + 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010, + 0x01813020, 0x01a19021, 0x90100140, 0x400001f2, +}; + + +/* + STAC 9200-32 pin configs for + 102801B5 (Dell Inspiron 630m) + 102801D8 (Dell Inspiron 640m) +*/ +static unsigned int dell9200_m21_pin_configs[8] = { + 0x40c003fa, 0x03441340, 0x0321121f, 0x90170310, + 0x408003fb, 0x03a11020, 0x401003fc, 0x403003fd, +}; + +/* + STAC 9200-32 pin configs for + 102801C2 (Dell Latitude D620) + 102801C8 + 102801CC (Dell Latitude D820) + 102801D4 + 102801D6 +*/ +static unsigned int dell9200_m22_pin_configs[8] = { + 0x40c003fa, 0x0144131f, 0x0321121f, 0x90170310, + 0x90a70321, 0x03a11020, 0x401003fb, 0x40f000fc, +}; + +/* + STAC 9200-32 pin configs for + 102801CE (Dell XPS M1710) + 102801CF (Dell Precision M90) +*/ +static unsigned int dell9200_m23_pin_configs[8] = { + 0x40c003fa, 0x01441340, 0x0421421f, 0x90170310, + 0x408003fb, 0x04a1102e, 0x90170311, 0x403003fc, +}; + +/* + STAC 9200-32 pin configs for + 102801C9 + 102801CA + 102801CB (Dell Latitude 120L) + 102801D3 +*/ +static unsigned int dell9200_m24_pin_configs[8] = { + 0x40c003fa, 0x404003fb, 0x0321121f, 0x90170310, + 0x408003fc, 0x03a11020, 0x401003fd, 0x403003fe, +}; + +/* + STAC 9200-32 pin configs for + 102801BD (Dell Inspiron E1505n) + 102801EE + 102801EF +*/ +static unsigned int dell9200_m25_pin_configs[8] = { + 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310, + 0x408003fb, 0x04a11020, 0x401003fc, 0x403003fd, +}; + +/* + STAC 9200-32 pin configs for + 102801F5 (Dell Inspiron 1501) + 102801F6 +*/ +static unsigned int dell9200_m26_pin_configs[8] = { + 0x40c003fa, 0x404003fb, 0x0421121f, 0x90170310, + 0x408003fc, 0x04a11020, 0x401003fd, 0x403003fe, +}; + +/* + STAC 9200-32 + 102801CD (Dell Inspiron E1705/9400) +*/ +static unsigned int dell9200_m27_pin_configs[8] = { + 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310, + 0x90170310, 0x04a11020, 0x90170310, 0x40f003fc, +}; + + static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = { [STAC_REF] = ref9200_pin_configs, + [STAC_9200_DELL_D21] = dell9200_d21_pin_configs, + [STAC_9200_DELL_D22] = dell9200_d22_pin_configs, + [STAC_9200_DELL_D23] = dell9200_d23_pin_configs, + [STAC_9200_DELL_M21] = dell9200_m21_pin_configs, + [STAC_9200_DELL_M22] = dell9200_m22_pin_configs, + [STAC_9200_DELL_M23] = dell9200_m23_pin_configs, + [STAC_9200_DELL_M24] = dell9200_m24_pin_configs, + [STAC_9200_DELL_M25] = dell9200_m25_pin_configs, + [STAC_9200_DELL_M26] = dell9200_m26_pin_configs, + [STAC_9200_DELL_M27] = dell9200_m27_pin_configs, }; static const char *stac9200_models[STAC_9200_MODELS] = { [STAC_REF] = "ref", + [STAC_9200_DELL_D21] = "dell-d21", + [STAC_9200_DELL_D22] = "dell-d22", + [STAC_9200_DELL_D23] = "dell-d23", + [STAC_9200_DELL_M21] = "dell-m21", + [STAC_9200_DELL_M22] = "dell-m22", + [STAC_9200_DELL_M23] = "dell-m23", + [STAC_9200_DELL_M24] = "dell-m24", + [STAC_9200_DELL_M25] = "dell-m25", + [STAC_9200_DELL_M26] = "dell-m26", + [STAC_9200_DELL_M27] = "dell-m27", + [STAC_9200_GATEWAY] = "gateway", }; static struct snd_pci_quirk stac9200_cfg_tbl[] = { @@ -464,30 +713,72 @@ static struct snd_pci_quirk stac9200_cfg_tbl[] = { SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF), /* Dell laptops have BIOS problem */ + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a8, + "unknown Dell", STAC_9200_DELL_D21), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01b5, - "Dell Inspiron 630m", STAC_REF), + "Dell Inspiron 630m", STAC_9200_DELL_M21), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bd, + "Dell Inspiron E1505n", STAC_9200_DELL_M25), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c0, + "unknown Dell", STAC_9200_DELL_D22), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c1, + "unknown Dell", STAC_9200_DELL_D22), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c2, - "Dell Latitude D620", STAC_REF), + "Dell Latitude D620", STAC_9200_DELL_M22), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c5, + "unknown Dell", STAC_9200_DELL_D23), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c7, + "unknown Dell", STAC_9200_DELL_D23), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c8, + "unknown Dell", STAC_9200_DELL_M22), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c9, + "unknown Dell", STAC_9200_DELL_M24), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ca, + "unknown Dell", STAC_9200_DELL_M24), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cb, - "Dell Latitude 120L", STAC_REF), + "Dell Latitude 120L", STAC_9200_DELL_M24), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cc, - "Dell Latitude D820", STAC_REF), + "Dell Latitude D820", STAC_9200_DELL_M22), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cd, - "Dell Inspiron E1705/9400", STAC_REF), + "Dell Inspiron E1705/9400", STAC_9200_DELL_M27), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ce, - "Dell XPS M1710", STAC_REF), + "Dell XPS M1710", STAC_9200_DELL_M23), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cf, - "Dell Precision M90", STAC_REF), + "Dell Precision M90", STAC_9200_DELL_M23), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d3, + "unknown Dell", STAC_9200_DELL_M22), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d4, + "unknown Dell", STAC_9200_DELL_M22), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d6, - "unknown Dell", STAC_REF), + "unknown Dell", STAC_9200_DELL_M22), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d8, - "Dell Inspiron 640m", STAC_REF), + "Dell Inspiron 640m", STAC_9200_DELL_M21), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d9, + "unknown Dell", STAC_9200_DELL_D23), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01da, + "unknown Dell", STAC_9200_DELL_D23), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01de, + "unknown Dell", STAC_9200_DELL_D21), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e3, + "unknown Dell", STAC_9200_DELL_D23), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e8, + "unknown Dell", STAC_9200_DELL_D21), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ee, + "unknown Dell", STAC_9200_DELL_M25), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ef, + "unknown Dell", STAC_9200_DELL_M25), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f5, - "Dell Inspiron 1501", STAC_REF), - + "Dell Inspiron 1501", STAC_9200_DELL_M26), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f6, + "unknown Dell", STAC_9200_DELL_M26), /* Panasonic */ SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-74", STAC_REF), - + /* Gateway machines needs EAPD to be set on resume */ + SND_PCI_QUIRK(0x107b, 0x0205, "Gateway S-7110M", STAC_9200_GATEWAY), + SND_PCI_QUIRK(0x107b, 0x0317, "Gateway MT3423, MX341*", + STAC_9200_GATEWAY), + SND_PCI_QUIRK(0x107b, 0x0318, "Gateway ML3019, MT3707", + STAC_9200_GATEWAY), {} /* terminator */ }; @@ -543,6 +834,51 @@ static unsigned int ref922x_pin_configs[10] = { 0x40000100, 0x40000100, }; +/* + STAC 922X pin configs for + 102801A7 + 102801AB + 102801A9 + 102801D1 + 102801D2 +*/ +static unsigned int dell_922x_d81_pin_configs[10] = { + 0x02214030, 0x01a19021, 0x01111012, 0x01114010, + 0x02a19020, 0x01117011, 0x400001f0, 0x400001f1, + 0x01813122, 0x400001f2, +}; + +/* + STAC 922X pin configs for + 102801AC + 102801D0 +*/ +static unsigned int dell_922x_d82_pin_configs[10] = { + 0x02214030, 0x01a19021, 0x01111012, 0x01114010, + 0x02a19020, 0x01117011, 0x01451140, 0x400001f0, + 0x01813122, 0x400001f1, +}; + +/* + STAC 922X pin configs for + 102801BF +*/ +static unsigned int dell_922x_m81_pin_configs[10] = { + 0x0321101f, 0x01112024, 0x01111222, 0x91174220, + 0x03a11050, 0x01116221, 0x90a70330, 0x01452340, + 0x40C003f1, 0x405003f0, +}; + +/* + STAC 9221 A1 pin configs for + 102801D7 (Dell XPS M1210) +*/ +static unsigned int dell_922x_m82_pin_configs[10] = { + 0x0221121f, 0x408103ff, 0x02111212, 0x90100310, + 0x408003f1, 0x02111211, 0x03451340, 0x40c003f2, + 0x508003f3, 0x405003f4, +}; + static unsigned int d945gtp3_pin_configs[10] = { 0x0221401f, 0x01a19022, 0x01813021, 0x01014010, 0x40000100, 0x40000100, 0x40000100, 0x40000100, @@ -585,48 +921,49 @@ static unsigned int intel_mac_v5_pin_configs[10] = { 0x400000fc, 0x400000fb, }; -static unsigned int stac922x_dell_pin_configs[10] = { - 0x0221121e, 0x408103ff, 0x02a1123e, 0x90100310, - 0x408003f1, 0x0221122f, 0x03451340, 0x40c003f2, - 0x50a003f3, 0x405003f4 -}; static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = { [STAC_D945_REF] = ref922x_pin_configs, [STAC_D945GTP3] = d945gtp3_pin_configs, [STAC_D945GTP5] = d945gtp5_pin_configs, - [STAC_922X_DELL] = stac922x_dell_pin_configs, [STAC_INTEL_MAC_V1] = intel_mac_v1_pin_configs, [STAC_INTEL_MAC_V2] = intel_mac_v2_pin_configs, [STAC_INTEL_MAC_V3] = intel_mac_v3_pin_configs, [STAC_INTEL_MAC_V4] = intel_mac_v4_pin_configs, [STAC_INTEL_MAC_V5] = intel_mac_v5_pin_configs, - /* for backward compitability */ + /* for backward compatibility */ [STAC_MACMINI] = intel_mac_v3_pin_configs, [STAC_MACBOOK] = intel_mac_v5_pin_configs, [STAC_MACBOOK_PRO_V1] = intel_mac_v3_pin_configs, [STAC_MACBOOK_PRO_V2] = intel_mac_v3_pin_configs, [STAC_IMAC_INTEL] = intel_mac_v2_pin_configs, [STAC_IMAC_INTEL_20] = intel_mac_v3_pin_configs, + [STAC_922X_DELL_D81] = dell_922x_d81_pin_configs, + [STAC_922X_DELL_D82] = dell_922x_d82_pin_configs, + [STAC_922X_DELL_M81] = dell_922x_m81_pin_configs, + [STAC_922X_DELL_M82] = dell_922x_m82_pin_configs, }; static const char *stac922x_models[STAC_922X_MODELS] = { [STAC_D945_REF] = "ref", [STAC_D945GTP5] = "5stack", [STAC_D945GTP3] = "3stack", - [STAC_922X_DELL] = "dell", [STAC_INTEL_MAC_V1] = "intel-mac-v1", [STAC_INTEL_MAC_V2] = "intel-mac-v2", [STAC_INTEL_MAC_V3] = "intel-mac-v3", [STAC_INTEL_MAC_V4] = "intel-mac-v4", [STAC_INTEL_MAC_V5] = "intel-mac-v5", - /* for backward compitability */ + /* for backward compatibility */ [STAC_MACMINI] = "macmini", [STAC_MACBOOK] = "macbook", [STAC_MACBOOK_PRO_V1] = "macbook-pro-v1", [STAC_MACBOOK_PRO_V2] = "macbook-pro", [STAC_IMAC_INTEL] = "imac-intel", [STAC_IMAC_INTEL_20] = "imac-intel-20", + [STAC_922X_DELL_D81] = "dell-d81", + [STAC_922X_DELL_D82] = "dell-d82", + [STAC_922X_DELL_M81] = "dell-m81", + [STAC_922X_DELL_M82] = "dell-m82", }; static struct snd_pci_quirk stac922x_cfg_tbl[] = { @@ -690,9 +1027,25 @@ static struct snd_pci_quirk stac922x_cfg_tbl[] = { /* Apple Mac Mini (early 2006) */ SND_PCI_QUIRK(0x8384, 0x7680, "Mac Mini", STAC_INTEL_MAC_V3), - /* Dell */ - SND_PCI_QUIRK(0x1028, 0x01d7, "Dell XPS M1210", STAC_922X_DELL), - + /* Dell systems */ + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a7, + "unknown Dell", STAC_922X_DELL_D81), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a9, + "unknown Dell", STAC_922X_DELL_D81), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ab, + "unknown Dell", STAC_922X_DELL_D81), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ac, + "unknown Dell", STAC_922X_DELL_D82), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bf, + "unknown Dell", STAC_922X_DELL_M81), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d0, + "unknown Dell", STAC_922X_DELL_D82), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d1, + "unknown Dell", STAC_922X_DELL_D81), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d2, + "unknown Dell", STAC_922X_DELL_D81), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d7, + "Dell XPS M1210", STAC_922X_DELL_M82), {} /* terminator */ }; @@ -717,16 +1070,25 @@ static unsigned int d965_5st_pin_configs[14] = { 0x40000100, 0x40000100 }; +static unsigned int dell_3st_pin_configs[14] = { + 0x02211230, 0x02a11220, 0x01a19040, 0x01114210, + 0x01111212, 0x01116211, 0x01813050, 0x01112214, + 0x403003fa, 0x40000100, 0x40000100, 0x404003fb, + 0x40c003fc, 0x40000100 +}; + static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = { [STAC_D965_REF] = ref927x_pin_configs, [STAC_D965_3ST] = d965_3st_pin_configs, [STAC_D965_5ST] = d965_5st_pin_configs, + [STAC_DELL_3ST] = dell_3st_pin_configs, }; static const char *stac927x_models[STAC_927X_MODELS] = { [STAC_D965_REF] = "ref", [STAC_D965_3ST] = "3stack", [STAC_D965_5ST] = "5stack", + [STAC_DELL_3ST] = "dell-3stack", }; static struct snd_pci_quirk stac927x_cfg_tbl[] = { @@ -753,7 +1115,13 @@ static struct snd_pci_quirk stac927x_cfg_tbl[] = { SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2003, "Intel D965", STAC_D965_3ST), SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST), SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f3, "Dell Inspiron 1420", STAC_D965_3ST), + /* Dell 3 stack systems */ + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01dd, "Dell Dimension E520", STAC_DELL_3ST), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ed, "Dell ", STAC_DELL_3ST), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f4, "Dell ", STAC_DELL_3ST), /* 965 based 5 stack systems */ + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0209, "Dell XPS 1330", STAC_D965_5ST), SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2301, "Intel D965", STAC_D965_5ST), SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2302, "Intel D965", STAC_D965_5ST), SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2303, "Intel D965", STAC_D965_5ST), @@ -772,23 +1140,97 @@ static unsigned int ref9205_pin_configs[12] = { 0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030 }; +/* + STAC 9205 pin configs for + 102801F1 + 102801F2 + 102801FC + 102801FD + 10280204 + 1028021F +*/ +static unsigned int dell_9205_m42_pin_configs[12] = { + 0x0321101F, 0x03A11020, 0x400003FA, 0x90170310, + 0x400003FB, 0x400003FC, 0x400003FD, 0x40F000F9, + 0x90A60330, 0x400003FF, 0x0144131F, 0x40C003FE, +}; + +/* + STAC 9205 pin configs for + 102801F9 + 102801FA + 102801FE + 102801FF (Dell Precision M4300) + 10280206 + 10280200 + 10280201 +*/ +static unsigned int dell_9205_m43_pin_configs[12] = { + 0x0321101f, 0x03a11020, 0x90a70330, 0x90170310, + 0x400000fe, 0x400000ff, 0x400000fd, 0x40f000f9, + 0x400000fa, 0x400000fc, 0x0144131f, 0x40c003f8, +}; + +static unsigned int dell_9205_m44_pin_configs[12] = { + 0x0421101f, 0x04a11020, 0x400003fa, 0x90170310, + 0x400003fb, 0x400003fc, 0x400003fd, 0x400003f9, + 0x90a60330, 0x400003ff, 0x01441340, 0x40c003fe, +}; + static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = { - [STAC_REF] = ref9205_pin_configs, - [STAC_M43xx] = NULL, + [STAC_9205_REF] = ref9205_pin_configs, + [STAC_9205_DELL_M42] = dell_9205_m42_pin_configs, + [STAC_9205_DELL_M43] = dell_9205_m43_pin_configs, + [STAC_9205_DELL_M44] = dell_9205_m44_pin_configs, }; static const char *stac9205_models[STAC_9205_MODELS] = { [STAC_9205_REF] = "ref", + [STAC_9205_DELL_M42] = "dell-m42", + [STAC_9205_DELL_M43] = "dell-m43", + [STAC_9205_DELL_M44] = "dell-m44", }; static struct snd_pci_quirk stac9205_cfg_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_9205_REF), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x01f8, - "Dell Precision", STAC_M43xx), - SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x01ff, - "Dell Precision", STAC_M43xx), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1, + "unknown Dell", STAC_9205_DELL_M42), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2, + "unknown Dell", STAC_9205_DELL_M42), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f8, + "Dell Precision", STAC_9205_DELL_M43), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021c, + "Dell Precision", STAC_9205_DELL_M43), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f9, + "Dell Precision", STAC_9205_DELL_M43), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021b, + "Dell Precision", STAC_9205_DELL_M43), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fa, + "Dell Precision", STAC_9205_DELL_M43), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc, + "unknown Dell", STAC_9205_DELL_M42), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd, + "unknown Dell", STAC_9205_DELL_M42), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fe, + "Dell Precision", STAC_9205_DELL_M43), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ff, + "Dell Precision M4300", STAC_9205_DELL_M43), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0206, + "Dell Precision", STAC_9205_DELL_M43), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1, + "Dell Inspiron", STAC_9205_DELL_M44), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2, + "Dell Inspiron", STAC_9205_DELL_M44), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc, + "Dell Inspiron", STAC_9205_DELL_M44), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd, + "Dell Inspiron", STAC_9205_DELL_M44), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0204, + "unknown Dell", STAC_9205_DELL_M42), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f, + "Dell Inspiron", STAC_9205_DELL_M44), {} /* terminator */ }; @@ -854,20 +1296,20 @@ static void stac92xx_set_config_regs(struct hda_codec *codec) spec->pin_configs[i]); } -static void stac92xx_enable_gpio_mask(struct hda_codec *codec, - int gpio_mask, int gpio_data) +static void stac92xx_enable_gpio_mask(struct hda_codec *codec) { + struct sigmatel_spec *spec = codec->spec; /* Configure GPIOx as output */ - snd_hda_codec_write(codec, codec->afg, 0, - AC_VERB_SET_GPIO_DIRECTION, gpio_mask); + snd_hda_codec_write_cache(codec, codec->afg, 0, + AC_VERB_SET_GPIO_DIRECTION, spec->gpio_mask); /* Configure GPIOx as CMOS */ - snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0x00000000); + snd_hda_codec_write_cache(codec, codec->afg, 0, 0x7e7, 0x00000000); /* Assert GPIOx */ - snd_hda_codec_write(codec, codec->afg, 0, - AC_VERB_SET_GPIO_DATA, gpio_data); + snd_hda_codec_write_cache(codec, codec->afg, 0, + AC_VERB_SET_GPIO_DATA, spec->gpio_data); /* Enable GPIOx */ - snd_hda_codec_write(codec, codec->afg, 0, - AC_VERB_SET_GPIO_MASK, gpio_mask); + snd_hda_codec_write_cache(codec, codec->afg, 0, + AC_VERB_SET_GPIO_MASK, spec->gpio_mask); } /* @@ -1000,10 +1442,9 @@ static struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = { }; static struct hda_pcm_stream stac92xx_pcm_analog_capture = { - .substreams = 2, .channels_min = 2, .channels_max = 2, - /* NID is set in stac92xx_build_pcms */ + /* NID + .substreams is set in stac92xx_build_pcms */ .ops = { .prepare = stac92xx_capture_pcm_prepare, .cleanup = stac92xx_capture_pcm_cleanup @@ -1022,6 +1463,7 @@ static int stac92xx_build_pcms(struct hda_codec *codec) info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback; info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture; info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; + info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adcs; if (spec->alt_switch) { codec->num_pcms++; @@ -1066,17 +1508,11 @@ static unsigned int stac92xx_get_vref(struct hda_codec *codec, hda_nid_t nid) static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type) { - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type); + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type); } -static int stac92xx_io_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 stac92xx_io_switch_info snd_ctl_boolean_mono_info static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1109,6 +1545,36 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ return 1; } +#define stac92xx_clfe_switch_info snd_ctl_boolean_mono_info + +static int stac92xx_clfe_switch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct sigmatel_spec *spec = codec->spec; + + ucontrol->value.integer.value[0] = spec->clfe_swap; + return 0; +} + +static int stac92xx_clfe_switch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct sigmatel_spec *spec = codec->spec; + hda_nid_t nid = kcontrol->private_value & 0xff; + + if (spec->clfe_swap == ucontrol->value.integer.value[0]) + return 0; + + spec->clfe_swap = ucontrol->value.integer.value[0]; + + snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE, + spec->clfe_swap ? 0x4 : 0x0); + + return 1; +} + #define STAC_CODEC_IO_SWITCH(xname, xpval) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ .name = xname, \ @@ -1119,17 +1585,28 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ .private_value = xpval, \ } +#define STAC_CODEC_CLFE_SWITCH(xname, xpval) \ + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .index = 0, \ + .info = stac92xx_clfe_switch_info, \ + .get = stac92xx_clfe_switch_get, \ + .put = stac92xx_clfe_switch_put, \ + .private_value = xpval, \ + } enum { STAC_CTL_WIDGET_VOL, STAC_CTL_WIDGET_MUTE, STAC_CTL_WIDGET_IO_SWITCH, + STAC_CTL_WIDGET_CLFE_SWITCH }; static struct snd_kcontrol_new stac92xx_control_templates[] = { HDA_CODEC_VOLUME(NULL, 0, 0, 0), HDA_CODEC_MUTE(NULL, 0, 0, 0), STAC_CODEC_IO_SWITCH(NULL, 0), + STAC_CODEC_CLFE_SWITCH(NULL, 0), }; /* add dynamic controls */ @@ -1182,7 +1659,8 @@ static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cf case 3: /* add line-in as side */ if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 3) { - cfg->line_out_pins[3] = cfg->input_pins[AUTO_PIN_LINE]; + cfg->line_out_pins[cfg->line_outs] = + cfg->input_pins[AUTO_PIN_LINE]; spec->line_switch = 1; cfg->line_outs++; } @@ -1190,12 +1668,14 @@ static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cf case 2: /* add line-in as clfe and mic as side */ if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 2) { - cfg->line_out_pins[2] = cfg->input_pins[AUTO_PIN_LINE]; + cfg->line_out_pins[cfg->line_outs] = + cfg->input_pins[AUTO_PIN_LINE]; spec->line_switch = 1; cfg->line_outs++; } if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 3) { - cfg->line_out_pins[3] = cfg->input_pins[AUTO_PIN_MIC]; + cfg->line_out_pins[cfg->line_outs] = + cfg->input_pins[AUTO_PIN_MIC]; spec->mic_switch = 1; cfg->line_outs++; } @@ -1203,12 +1683,14 @@ static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cf case 1: /* add line-in as surr and mic as clfe */ if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 1) { - cfg->line_out_pins[1] = cfg->input_pins[AUTO_PIN_LINE]; + cfg->line_out_pins[cfg->line_outs] = + cfg->input_pins[AUTO_PIN_LINE]; spec->line_switch = 1; cfg->line_outs++; } if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 2) { - cfg->line_out_pins[2] = cfg->input_pins[AUTO_PIN_MIC]; + cfg->line_out_pins[cfg->line_outs] = + cfg->input_pins[AUTO_PIN_MIC]; spec->mic_switch = 1; cfg->line_outs++; } @@ -1282,8 +1764,8 @@ static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec, spec->multiout.num_dacs++; if (conn_len > 1) { /* select this DAC in the pin's input mux */ - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_CONNECT_SEL, j); + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_CONNECT_SEL, j); } } @@ -1318,7 +1800,7 @@ static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_ } /* add playback controls from the parsed DAC table */ -static int stac92xx_auto_create_multi_out_ctls(struct sigmatel_spec *spec, +static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { static const char *chname[4] = { @@ -1327,6 +1809,10 @@ static int stac92xx_auto_create_multi_out_ctls(struct sigmatel_spec *spec, hda_nid_t nid; int i, err; + struct sigmatel_spec *spec = codec->spec; + unsigned int wid_caps; + + for (i = 0; i < cfg->line_outs; i++) { if (!spec->multiout.dac_nids[i]) continue; @@ -1341,6 +1827,18 @@ static int stac92xx_auto_create_multi_out_ctls(struct sigmatel_spec *spec, err = create_controls(spec, "LFE", nid, 2); if (err < 0) return err; + + wid_caps = get_wcaps(codec, nid); + + if (wid_caps & AC_WCAP_LR_SWAP) { + err = stac92xx_add_control(spec, + STAC_CTL_WIDGET_CLFE_SWITCH, + "Swap Center/LFE Playback Switch", nid); + + if (err < 0) + return err; + } + } else { err = create_controls(spec, chname[i], nid, 3); if (err < 0) @@ -1536,9 +2034,9 @@ static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const * NID lists. Hopefully this won't get confused. */ for (i = 0; i < spec->num_muxes; i++) { - snd_hda_codec_write(codec, spec->mux_nids[i], 0, - AC_VERB_SET_CONNECT_SEL, - imux->items[0].index); + snd_hda_codec_write_cache(codec, spec->mux_nids[i], 0, + AC_VERB_SET_CONNECT_SEL, + imux->items[0].index); } } @@ -1593,9 +2091,19 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0) return err; - if ((err = stac92xx_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 || - (err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg)) < 0 || - (err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0) + err = stac92xx_auto_create_multi_out_ctls(codec, &spec->autocfg); + + if (err < 0) + return err; + + err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg); + + if (err < 0) + return err; + + err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg); + + if (err < 0) return err; if (spec->num_dmics > 0) @@ -1764,9 +2272,9 @@ static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid, unsigned int event) { if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - (AC_USRSP_EN | event)); + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_UNSOLICITED_ENABLE, + (AC_USRSP_EN | event)); } static int stac92xx_init(struct hda_codec *codec) @@ -1870,7 +2378,7 @@ static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid, if (flag & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN)) pin_ctl &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN); - snd_hda_codec_write(codec, nid, 0, + snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_ctl | flag); } @@ -1880,7 +2388,7 @@ static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid, { unsigned int pin_ctl = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00); - snd_hda_codec_write(codec, nid, 0, + snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_ctl & ~flag); } @@ -1936,22 +2444,22 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) } } -#ifdef CONFIG_PM +#ifdef SND_HDA_NEEDS_RESUME static int stac92xx_resume(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; - int i; - stac92xx_init(codec); stac92xx_set_config_regs(codec); - snd_hda_resume_ctls(codec, spec->mixer); - for (i = 0; i < spec->num_mixers; i++) - snd_hda_resume_ctls(codec, spec->mixers[i]); - if (spec->multiout.dig_out_nid) - snd_hda_resume_spdif_out(codec); - if (spec->dig_in_nid) - snd_hda_resume_spdif_in(codec); - + snd_hda_sequence_write(codec, spec->init); + if (spec->gpio_mute) { + stac922x_gpio_mute(codec, 0, 0); + stac922x_gpio_mute(codec, 1, 0); + } + snd_hda_codec_resume_amp(codec); + snd_hda_codec_resume_cache(codec); + /* invoke unsolicited event to reset the HP state */ + if (spec->hp_detect) + codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26); return 0; } #endif @@ -1962,7 +2470,7 @@ static struct hda_codec_ops stac92xx_patch_ops = { .init = stac92xx_init, .free = stac92xx_free, .unsol_event = stac92xx_unsol_event, -#ifdef CONFIG_PM +#ifdef SND_HDA_NEEDS_RESUME .resume = stac92xx_resume, #endif }; @@ -2002,8 +2510,12 @@ static int patch_stac9200(struct hda_codec *codec) spec->mux_nids = stac9200_mux_nids; spec->num_muxes = 1; spec->num_dmics = 0; + spec->num_adcs = 1; - spec->init = stac9200_core_init; + if (spec->board_config == STAC_9200_GATEWAY) + spec->init = stac9200_eapd_init; + else + spec->init = stac9200_core_init; spec->mixer = stac9200_mixer; err = stac9200_parse_auto_config(codec); @@ -2053,12 +2565,13 @@ static int patch_stac925x(struct hda_codec *codec) spec->adc_nids = stac925x_adc_nids; spec->mux_nids = stac925x_mux_nids; spec->num_muxes = 1; + spec->num_adcs = 1; switch (codec->vendor_id) { case 0x83847632: /* STAC9202 */ case 0x83847633: /* STAC9202D */ case 0x83847636: /* STAC9251 */ case 0x83847637: /* STAC9251D */ - spec->num_dmics = 1; + spec->num_dmics = STAC925X_NUM_DMICS; spec->dmic_nids = stac925x_dmic_nids; break; default: @@ -2156,6 +2669,7 @@ static int patch_stac922x(struct hda_codec *codec) spec->adc_nids = stac922x_adc_nids; spec->mux_nids = stac922x_mux_nids; spec->num_muxes = ARRAY_SIZE(stac922x_mux_nids); + spec->num_adcs = ARRAY_SIZE(stac922x_adc_nids); spec->num_dmics = 0; spec->init = stac922x_core_init; @@ -2224,22 +2738,25 @@ static int patch_stac927x(struct hda_codec *codec) spec->adc_nids = stac927x_adc_nids; spec->mux_nids = stac927x_mux_nids; spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids); + spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids); spec->num_dmics = 0; spec->init = d965_core_init; - spec->mixer = stac9227_mixer; + spec->mixer = stac927x_mixer; break; case STAC_D965_5ST: spec->adc_nids = stac927x_adc_nids; spec->mux_nids = stac927x_mux_nids; spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids); + spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids); spec->num_dmics = 0; spec->init = d965_core_init; - spec->mixer = stac9227_mixer; + spec->mixer = stac927x_mixer; break; default: spec->adc_nids = stac927x_adc_nids; spec->mux_nids = stac927x_mux_nids; spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids); + spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids); spec->num_dmics = 0; spec->init = stac927x_core_init; spec->mixer = stac927x_mixer; @@ -2247,7 +2764,8 @@ static int patch_stac927x(struct hda_codec *codec) spec->multiout.dac_nids = spec->dac_nids; /* GPIO0 High = Enable EAPD */ - stac92xx_enable_gpio_mask(codec, 0x00000001, 0x00000001); + spec->gpio_mask = spec->gpio_data = 0x00000001; + stac92xx_enable_gpio_mask(codec); err = stac92xx_parse_auto_config(codec, 0x1e, 0x20); if (!err) { @@ -2272,7 +2790,7 @@ static int patch_stac927x(struct hda_codec *codec) static int patch_stac9205(struct hda_codec *codec) { struct sigmatel_spec *spec; - int err, gpio_mask, gpio_data; + int err; spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) @@ -2299,10 +2817,11 @@ static int patch_stac9205(struct hda_codec *codec) } spec->adc_nids = stac9205_adc_nids; + spec->num_adcs = ARRAY_SIZE(stac9205_adc_nids); spec->mux_nids = stac9205_mux_nids; spec->num_muxes = ARRAY_SIZE(stac9205_mux_nids); spec->dmic_nids = stac9205_dmic_nids; - spec->num_dmics = ARRAY_SIZE(stac9205_dmic_nids); + spec->num_dmics = STAC9205_NUM_DMICS; spec->dmux_nid = 0x1d; spec->init = stac9205_core_init; @@ -2310,20 +2829,25 @@ static int patch_stac9205(struct hda_codec *codec) spec->multiout.dac_nids = spec->dac_nids; - if (spec->board_config == STAC_M43xx) { + switch (spec->board_config){ + case STAC_9205_DELL_M43: /* Enable SPDIF in/out */ stac92xx_set_config_reg(codec, 0x1f, 0x01441030); stac92xx_set_config_reg(codec, 0x20, 0x1c410030); - gpio_mask = 0x00000007; /* GPIO0-2 */ + spec->gpio_mask = 0x00000007; /* GPIO0-2 */ /* GPIO0 High = EAPD, GPIO1 Low = DRM, * GPIO2 High = Headphone Mute */ - gpio_data = 0x00000005; - } else - gpio_mask = gpio_data = 0x00000001; /* GPIO0 High = EAPD */ + spec->gpio_data = 0x00000005; + break; + default: + /* GPIO0 High = EAPD */ + spec->gpio_mask = spec->gpio_data = 0x00000001; + break; + } - stac92xx_enable_gpio_mask(codec, gpio_mask, gpio_data); + stac92xx_enable_gpio_mask(codec); err = stac92xx_parse_auto_config(codec, 0x1f, 0x20); if (!err) { if (spec->board_config < 0) { @@ -2355,7 +2879,7 @@ static hda_nid_t vaio_adcs[] = { 0x8 /*,0x6*/ }; static hda_nid_t vaio_mux_nids[] = { 0x15 }; static struct hda_input_mux vaio_mux = { - .num_items = 2, + .num_items = 3, .items = { /* { "HP", 0x0 }, */ { "Mic Jack", 0x1 }, @@ -2366,6 +2890,7 @@ static struct hda_input_mux vaio_mux = { static struct hda_verb vaio_init[] = { {0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */ + {0x0a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | STAC_HP_EVENT}, {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */ {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */ {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */ @@ -2397,61 +2922,28 @@ static struct hda_verb vaio_ar_init[] = { }; /* bind volumes of both NID 0x02 and 0x05 */ -static int vaio_master_vol_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - long *valp = ucontrol->value.integer.value; - int change; - - change = snd_hda_codec_amp_update(codec, 0x02, 0, HDA_OUTPUT, 0, - 0x7f, valp[0] & 0x7f); - change |= snd_hda_codec_amp_update(codec, 0x02, 1, HDA_OUTPUT, 0, - 0x7f, valp[1] & 0x7f); - snd_hda_codec_amp_update(codec, 0x05, 0, HDA_OUTPUT, 0, - 0x7f, valp[0] & 0x7f); - snd_hda_codec_amp_update(codec, 0x05, 1, HDA_OUTPUT, 0, - 0x7f, valp[1] & 0x7f); - return change; -} +static struct hda_bind_ctls vaio_bind_master_vol = { + .ops = &snd_hda_bind_vol, + .values = { + HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT), + 0 + }, +}; /* bind volumes of both NID 0x02 and 0x05 */ -static int vaio_master_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - long *valp = ucontrol->value.integer.value; - int change; - - change = snd_hda_codec_amp_update(codec, 0x02, 0, HDA_OUTPUT, 0, - 0x80, (valp[0] ? 0 : 0x80)); - change |= snd_hda_codec_amp_update(codec, 0x02, 1, HDA_OUTPUT, 0, - 0x80, (valp[1] ? 0 : 0x80)); - snd_hda_codec_amp_update(codec, 0x05, 0, HDA_OUTPUT, 0, - 0x80, (valp[0] ? 0 : 0x80)); - snd_hda_codec_amp_update(codec, 0x05, 1, HDA_OUTPUT, 0, - 0x80, (valp[1] ? 0 : 0x80)); - return change; -} +static struct hda_bind_ctls vaio_bind_master_sw = { + .ops = &snd_hda_bind_sw, + .values = { + HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT), + 0, + }, +}; static struct snd_kcontrol_new vaio_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Volume", - .info = snd_hda_mixer_amp_volume_info, - .get = snd_hda_mixer_amp_volume_get, - .put = vaio_master_vol_put, - .tlv = { .c = snd_hda_mixer_amp_tlv }, - .private_value = HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .info = snd_hda_mixer_amp_switch_info, - .get = snd_hda_mixer_amp_switch_get, - .put = vaio_master_sw_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), - }, + HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol), + HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw), /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */ HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT), @@ -2467,22 +2959,8 @@ static struct snd_kcontrol_new vaio_mixer[] = { }; static struct snd_kcontrol_new vaio_ar_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Volume", - .info = snd_hda_mixer_amp_volume_info, - .get = snd_hda_mixer_amp_volume_get, - .put = vaio_master_vol_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .info = snd_hda_mixer_amp_switch_info, - .get = snd_hda_mixer_amp_switch_get, - .put = vaio_master_sw_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), - }, + HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol), + HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw), /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */ HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT), @@ -2504,6 +2982,49 @@ static struct hda_codec_ops stac9872_patch_ops = { .build_pcms = stac92xx_build_pcms, .init = stac92xx_init, .free = stac92xx_free, +#ifdef SND_HDA_NEEDS_RESUME + .resume = stac92xx_resume, +#endif +}; + +static int stac9872_vaio_init(struct hda_codec *codec) +{ + int err; + + err = stac92xx_init(codec); + if (err < 0) + return err; + if (codec->patch_ops.unsol_event) + codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26); + return 0; +} + +static void stac9872_vaio_hp_detect(struct hda_codec *codec, unsigned int res) +{ + if (get_pin_presence(codec, 0x0a)) { + stac92xx_reset_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN); + stac92xx_set_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN); + } else { + stac92xx_reset_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN); + stac92xx_set_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN); + } +} + +static void stac9872_vaio_unsol_event(struct hda_codec *codec, unsigned int res) +{ + switch (res >> 26) { + case STAC_HP_EVENT: + stac9872_vaio_hp_detect(codec, res); + break; + } +} + +static struct hda_codec_ops stac9872_vaio_patch_ops = { + .build_controls = stac92xx_build_controls, + .build_pcms = stac92xx_build_pcms, + .init = stac9872_vaio_init, + .free = stac92xx_free, + .unsol_event = stac9872_vaio_unsol_event, #ifdef CONFIG_PM .resume = stac92xx_resume, #endif @@ -2564,6 +3085,7 @@ static int patch_stac9872(struct hda_codec *codec) spec->adc_nids = vaio_adcs; spec->input_mux = &vaio_mux; spec->mux_nids = vaio_mux_nids; + codec->patch_ops = stac9872_vaio_patch_ops; break; case CXD9872AKD_VAIO: @@ -2577,10 +3099,10 @@ static int patch_stac9872(struct hda_codec *codec) spec->adc_nids = vaio_adcs; spec->input_mux = &vaio_mux; spec->mux_nids = vaio_mux_nids; + codec->patch_ops = stac9872_patch_ops; break; } - codec->patch_ops = stac9872_patch_ops; return 0; } diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index ba32d1e52cb..33b5e1ffa81 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -115,6 +115,10 @@ struct via_spec { struct snd_kcontrol_new *kctl_alloc; struct hda_input_mux private_imux; hda_nid_t private_dac_nids[4]; + +#ifdef CONFIG_SND_HDA_POWER_SAVE + struct hda_loopback_check loopback; +#endif }; static hda_nid_t vt1708_adc_nids[2] = { @@ -305,15 +309,15 @@ static struct hda_verb vt1708_volume_init_verbs[] = { {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback * mixer widget */ /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* master */ + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* * Set up output mixers (0x19 - 0x1b) @@ -543,24 +547,11 @@ static int via_init(struct hda_codec *codec) return 0; } -#ifdef CONFIG_PM -/* - * resume - */ -static int via_resume(struct hda_codec *codec) +#ifdef CONFIG_SND_HDA_POWER_SAVE +static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid) { struct via_spec *spec = codec->spec; - int i; - - via_init(codec); - for (i = 0; i < spec->num_mixers; i++) - snd_hda_resume_ctls(codec, spec->mixers[i]); - if (spec->multiout.dig_out_nid) - snd_hda_resume_spdif_out(codec); - if (spec->dig_in_nid) - snd_hda_resume_spdif_in(codec); - - return 0; + return snd_hda_check_amp_list_power(codec, &spec->loopback, nid); } #endif @@ -571,8 +562,8 @@ static struct hda_codec_ops via_patch_ops = { .build_pcms = via_build_pcms, .init = via_init, .free = via_free, -#ifdef CONFIG_PM - .resume = via_resume, +#ifdef CONFIG_SND_HDA_POWER_SAVE + .check_power_status = via_check_power_status, #endif }; @@ -762,6 +753,16 @@ static int vt1708_auto_create_analog_input_ctls(struct via_spec *spec, return 0; } +#ifdef CONFIG_SND_HDA_POWER_SAVE +static struct hda_amp_list vt1708_loopbacks[] = { + { 0x17, HDA_INPUT, 1 }, + { 0x17, HDA_INPUT, 2 }, + { 0x17, HDA_INPUT, 3 }, + { 0x17, HDA_INPUT, 4 }, + { } /* end */ +}; +#endif + static int vt1708_parse_auto_config(struct hda_codec *codec) { struct via_spec *spec = codec->spec; @@ -855,6 +856,9 @@ static int patch_vt1708(struct hda_codec *codec) codec->patch_ops = via_patch_ops; codec->patch_ops.init = via_auto_init; +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = vt1708_loopbacks; +#endif return 0; } @@ -895,15 +899,15 @@ static struct hda_verb vt1709_10ch_volume_init_verbs[] = { {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback * mixer widget */ /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* unmute master */ + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* * Set up output selector (0x1a, 0x1b, 0x29) @@ -1251,6 +1255,16 @@ static int vt1709_parse_auto_config(struct hda_codec *codec) return 1; } +#ifdef CONFIG_SND_HDA_POWER_SAVE +static struct hda_amp_list vt1709_loopbacks[] = { + { 0x18, HDA_INPUT, 1 }, + { 0x18, HDA_INPUT, 2 }, + { 0x18, HDA_INPUT, 3 }, + { 0x18, HDA_INPUT, 4 }, + { } /* end */ +}; +#endif + static int patch_vt1709_10ch(struct hda_codec *codec) { struct via_spec *spec; @@ -1293,6 +1307,9 @@ static int patch_vt1709_10ch(struct hda_codec *codec) codec->patch_ops = via_patch_ops; codec->patch_ops.init = via_auto_init; +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = vt1709_loopbacks; +#endif return 0; } @@ -1383,6 +1400,9 @@ static int patch_vt1709_6ch(struct hda_codec *codec) codec->patch_ops = via_patch_ops; codec->patch_ops.init = via_auto_init; +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = vt1709_loopbacks; +#endif return 0; } diff --git a/sound/pci/ice1712/Makefile b/sound/pci/ice1712/Makefile index 6efdd62f683..65ce66adba5 100644 --- a/sound/pci/ice1712/Makefile +++ b/sound/pci/ice1712/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-ice17xx-ak4xxx-objs := ak4xxx.o diff --git a/sound/pci/ice1712/ak4xxx.c b/sound/pci/ice1712/ak4xxx.c index ab00cce2c39..a1aba0d7d0e 100644 --- a/sound/pci/ice1712/ak4xxx.c +++ b/sound/pci/ice1712/ak4xxx.c @@ -3,7 +3,7 @@ * * AK4524 / AK4528 / AK4529 / AK4355 / AK4381 interface * - * Copyright (c) 2000 Jaroslav Kysela <perex@suse.cz> + * Copyright (c) 2000 Jaroslav Kysela <perex@perex.cz> * * 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 @@ -30,7 +30,7 @@ #include <sound/initval.h> #include "ice1712.h" -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("ICEnsemble ICE17xx <-> AK4xxx AD/DA chip interface"); MODULE_LICENSE("GPL"); diff --git a/sound/pci/ice1712/amp.c b/sound/pci/ice1712/amp.c index 44bbb630b94..6e13d758bb5 100644 --- a/sound/pci/ice1712/amp.c +++ b/sound/pci/ice1712/amp.c @@ -3,7 +3,7 @@ * * Lowlevel functions for Advanced Micro Peripherals Ltd AUDIO2000 * - * Copyright (c) 2000 Jaroslav Kysela <perex@suse.cz> + * Copyright (c) 2000 Jaroslav Kysela <perex@perex.cz> * * 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 diff --git a/sound/pci/ice1712/amp.h b/sound/pci/ice1712/amp.h index a0fc89b4812..bf81d30d915 100644 --- a/sound/pci/ice1712/amp.h +++ b/sound/pci/ice1712/amp.h @@ -6,7 +6,7 @@ * * Lowlevel functions for Advanced Micro Peripherals Ltd AUDIO2000 * - * Copyright (c) 2000 Jaroslav Kysela <perex@suse.cz> + * Copyright (c) 2000 Jaroslav Kysela <perex@perex.cz> * * 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 diff --git a/sound/pci/ice1712/aureon.c b/sound/pci/ice1712/aureon.c index 66bacde1ead..ec0699c8995 100644 --- a/sound/pci/ice1712/aureon.c +++ b/sound/pci/ice1712/aureon.c @@ -394,7 +394,7 @@ static int aureon_ac97_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ele /* * AC'97 mute controls */ -#define aureon_ac97_mute_info aureon_mono_bool_info +#define aureon_ac97_mute_info snd_ctl_boolean_mono_info static int aureon_ac97_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -430,7 +430,7 @@ static int aureon_ac97_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el /* * AC'97 mute controls */ -#define aureon_ac97_micboost_info aureon_mono_bool_info +#define aureon_ac97_micboost_info snd_ctl_boolean_mono_info static int aureon_ac97_micboost_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -621,19 +621,12 @@ static void wm_put(struct snd_ice1712 *ice, int reg, unsigned short val) /* */ -static int aureon_mono_bool_info(struct snd_kcontrol *k, 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 aureon_mono_bool_info snd_ctl_boolean_mono_info /* * AC'97 master playback mute controls (Mute on WM8770 chip) */ -#define aureon_ac97_mmute_info aureon_mono_bool_info +#define aureon_ac97_mmute_info snd_ctl_boolean_mono_info static int aureon_ac97_mmute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -708,7 +701,7 @@ static void wm_set_vol(struct snd_ice1712 *ice, unsigned int index, unsigned sho /* * DAC mute control */ -#define wm_pcm_mute_info aureon_mono_bool_info +#define wm_pcm_mute_info snd_ctl_boolean_mono_info static int wm_pcm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -879,13 +872,7 @@ static int wm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value /* * WM8770 master mute control */ -static int wm_master_mute_info(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 wm_master_mute_info snd_ctl_boolean_stereo_info static int wm_master_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -969,14 +956,7 @@ static int wm_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val /* * ADC mute control */ -static int wm_adc_mute_info(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 wm_adc_mute_info snd_ctl_boolean_stereo_info static int wm_adc_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1210,12 +1190,7 @@ static int aureon_cs8415_rate_get (struct snd_kcontrol *kcontrol, struct snd_ctl /* * CS8415A Mute */ -static int aureon_cs8415_mute_info (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - return 0; -} +#define aureon_cs8415_mute_info snd_ctl_boolean_mono_info static int aureon_cs8415_mute_get (struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1316,7 +1291,7 @@ static int aureon_get_headphone_amp(struct snd_ice1712 *ice) return ( tmp & AUREON_HP_SEL )!= 0; } -#define aureon_hpamp_info aureon_mono_bool_info +#define aureon_hpamp_info snd_ctl_boolean_mono_info static int aureon_hpamp_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1338,7 +1313,7 @@ static int aureon_hpamp_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v * Deemphasis */ -#define aureon_deemp_info aureon_mono_bool_info +#define aureon_deemp_info snd_ctl_boolean_mono_info static int aureon_deemp_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { diff --git a/sound/pci/ice1712/delta.c b/sound/pci/ice1712/delta.c index af659800c9b..371f78461db 100644 --- a/sound/pci/ice1712/delta.c +++ b/sound/pci/ice1712/delta.c @@ -4,7 +4,7 @@ * Lowlevel functions for M-Audio Delta 1010, 44, 66, Dio2496, Audiophile * Digigram VX442 * - * Copyright (c) 2000 Jaroslav Kysela <perex@suse.cz> + * Copyright (c) 2000 Jaroslav Kysela <perex@perex.cz> * * 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 @@ -393,15 +393,8 @@ static void delta_setup_spdif(struct snd_ice1712 *ice, int rate) snd_ice1712_delta_cs8403_spdif_write(ice, tmp); } -static int snd_ice1712_delta1010lt_wordclock_status_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_ice1712_delta1010lt_wordclock_status_info \ + snd_ctl_boolean_mono_info static int snd_ice1712_delta1010lt_wordclock_status_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/pci/ice1712/delta.h b/sound/pci/ice1712/delta.h index 2697156607e..26ea05a32f5 100644 --- a/sound/pci/ice1712/delta.h +++ b/sound/pci/ice1712/delta.h @@ -7,7 +7,7 @@ * Lowlevel functions for M-Audio Delta 1010, 44, 66, Dio2496, Audiophile * Digigram VX442 * - * Copyright (c) 2000 Jaroslav Kysela <perex@suse.cz> + * Copyright (c) 2000 Jaroslav Kysela <perex@perex.cz> * * 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 diff --git a/sound/pci/ice1712/envy24ht.h b/sound/pci/ice1712/envy24ht.h index b58afcda9ed..43b9e3e858b 100644 --- a/sound/pci/ice1712/envy24ht.h +++ b/sound/pci/ice1712/envy24ht.h @@ -4,7 +4,7 @@ /* * ALSA driver for ICEnsemble VT1724 (Envy24) * - * Copyright (c) 2000 Jaroslav Kysela <perex@suse.cz> + * Copyright (c) 2000 Jaroslav Kysela <perex@perex.cz> * * 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 diff --git a/sound/pci/ice1712/ews.c b/sound/pci/ice1712/ews.c index b135389fec6..75e4e5e0f1e 100644 --- a/sound/pci/ice1712/ews.c +++ b/sound/pci/ice1712/ews.c @@ -3,7 +3,7 @@ * * Lowlevel functions for Terratec EWS88MT/D, EWX24/96, DMX 6Fire * - * Copyright (c) 2000 Jaroslav Kysela <perex@suse.cz> + * Copyright (c) 2000 Jaroslav Kysela <perex@perex.cz> * 2002 Takashi Iwai <tiwai@suse.de> * * This program is free software; you can redistribute it and/or modify @@ -700,14 +700,7 @@ static struct snd_kcontrol_new snd_ice1712_ews88mt_output_sense __devinitdata = * EWS88D specific controls */ -static int snd_ice1712_ews88d_control_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_ice1712_ews88d_control_info snd_ctl_boolean_mono_info static int snd_ice1712_ews88d_control_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -812,14 +805,7 @@ static int snd_ice1712_6fire_write_pca(struct snd_ice1712 *ice, unsigned char re return 0; } -static int snd_ice1712_6fire_control_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_ice1712_6fire_control_info snd_ctl_boolean_mono_info static int snd_ice1712_6fire_control_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { diff --git a/sound/pci/ice1712/ews.h b/sound/pci/ice1712/ews.h index a12a0b05355..e4ed1b475b0 100644 --- a/sound/pci/ice1712/ews.h +++ b/sound/pci/ice1712/ews.h @@ -6,7 +6,7 @@ * * Lowlevel functions for Terratec EWS88MT/D, EWX24/96, DMX 6Fire * - * Copyright (c) 2000 Jaroslav Kysela <perex@suse.cz> + * Copyright (c) 2000 Jaroslav Kysela <perex@perex.cz> * 2002 Takashi Iwai <tiwai@suse.de> * * This program is free software; you can redistribute it and/or modify diff --git a/sound/pci/ice1712/hoontech.c b/sound/pci/ice1712/hoontech.c index 8203562ef7e..abcfd1da658 100644 --- a/sound/pci/ice1712/hoontech.c +++ b/sound/pci/ice1712/hoontech.c @@ -3,7 +3,7 @@ * * Lowlevel functions for Hoontech STDSP24 * - * Copyright (c) 2000 Jaroslav Kysela <perex@suse.cz> + * Copyright (c) 2000 Jaroslav Kysela <perex@perex.cz> * * 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 diff --git a/sound/pci/ice1712/hoontech.h b/sound/pci/ice1712/hoontech.h index 1ee538b20fb..cc1da1e69ad 100644 --- a/sound/pci/ice1712/hoontech.h +++ b/sound/pci/ice1712/hoontech.h @@ -6,7 +6,7 @@ * * Lowlevel functions for Hoontech STDSP24 * - * Copyright (c) 2000 Jaroslav Kysela <perex@suse.cz> + * Copyright (c) 2000 Jaroslav Kysela <perex@perex.cz> * * 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 diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index 6630a0ae952..052fc3cb327 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c @@ -1,7 +1,7 @@ /* * ALSA driver for ICEnsemble ICE1712 (Envy24) * - * Copyright (c) 2000 Jaroslav Kysela <perex@suse.cz> + * Copyright (c) 2000 Jaroslav Kysela <perex@perex.cz> * * 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 @@ -73,7 +73,7 @@ #include "ews.h" #include "hoontech.h" -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("ICEnsemble ICE1712 (Envy24)"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{" @@ -256,14 +256,7 @@ static unsigned short snd_ice1712_pro_ac97_read(struct snd_ac97 *ac97, /* * consumer ac97 digital mix */ -static int snd_ice1712_digmix_route_ac97_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_ice1712_digmix_route_ac97_info snd_ctl_boolean_mono_info static int snd_ice1712_digmix_route_ac97_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1300,14 +1293,7 @@ static void snd_ice1712_update_volume(struct snd_ice1712 *ice, int index) outw(val, ICEMT(ice, MONITOR_VOLUME)); } -static int snd_ice1712_pro_mixer_switch_info(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_ice1712_pro_mixer_switch_info snd_ctl_boolean_stereo_info static int snd_ice1712_pro_mixer_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1759,16 +1745,6 @@ static struct snd_kcontrol_new snd_ice1712_spdif_stream __devinitdata = .put = snd_ice1712_spdif_stream_put }; -int snd_ice1712_gpio_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; -} - int snd_ice1712_gpio_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1968,15 +1944,7 @@ static struct snd_kcontrol_new snd_ice1712_pro_internal_clock_default __devinitd .put = snd_ice1712_pro_internal_clock_default_put }; -static int snd_ice1712_pro_rate_locking_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_ice1712_pro_rate_locking_info snd_ctl_boolean_mono_info static int snd_ice1712_pro_rate_locking_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -2007,15 +1975,7 @@ static struct snd_kcontrol_new snd_ice1712_pro_rate_locking __devinitdata = { .put = snd_ice1712_pro_rate_locking_put }; -static int snd_ice1712_pro_rate_reset_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_ice1712_pro_rate_reset_info snd_ctl_boolean_mono_info static int snd_ice1712_pro_rate_reset_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h index 6ac486d9c13..58640afa540 100644 --- a/sound/pci/ice1712/ice1712.h +++ b/sound/pci/ice1712/ice1712.h @@ -4,7 +4,7 @@ /* * ALSA driver for ICEnsemble ICE1712 (Envy24) * - * Copyright (c) 2000 Jaroslav Kysela <perex@suse.cz> + * Copyright (c) 2000 Jaroslav Kysela <perex@perex.cz> * * 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 @@ -451,11 +451,10 @@ static inline void snd_ice1712_restore_gpio_status(struct snd_ice1712 *ice) /* for bit controls */ #define ICE1712_GPIO(xiface, xname, xindex, mask, invert, xaccess) \ -{ .iface = xiface, .name = xname, .access = xaccess, .info = snd_ice1712_gpio_info, \ +{ .iface = xiface, .name = xname, .access = xaccess, .info = snd_ctl_boolean_mono_info, \ .get = snd_ice1712_gpio_get, .put = snd_ice1712_gpio_put, \ .private_value = mask | (invert << 24) } -int snd_ice1712_gpio_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); int snd_ice1712_gpio_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); int snd_ice1712_gpio_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index ee620dea7ef..0b0bbb0d96b 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -2,7 +2,7 @@ * ALSA driver for VT1724 ICEnsemble ICE1724 / VIA VT1724 (Envy24HT) * VIA VT1720 (Envy24PT) * - * Copyright (c) 2000 Jaroslav Kysela <perex@suse.cz> + * Copyright (c) 2000 Jaroslav Kysela <perex@perex.cz> * 2002 James Stafford <jstafford@ampltd.com> * 2003 Takashi Iwai <tiwai@suse.de> * @@ -52,7 +52,7 @@ #include "phase.h" #include "wtm.h" -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("VIA ICEnsemble ICE1724/1720 (Envy24HT/PT)"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{" @@ -341,10 +341,12 @@ static int snd_vt1724_pcm_trigger(struct snd_pcm_substream *substream, int cmd) what = 0; snd_pcm_group_for_each_entry(s, substream) { - const struct vt1724_pcm_reg *reg; - reg = s->runtime->private_data; - what |= reg->start; - snd_pcm_trigger_done(s, substream); + if (snd_pcm_substream_chip(s) == ice) { + const struct vt1724_pcm_reg *reg; + reg = s->runtime->private_data; + what |= reg->start; + snd_pcm_trigger_done(s, substream); + } } switch (cmd) { @@ -1479,15 +1481,7 @@ static struct snd_kcontrol_new snd_vt1724_spdif_maskp __devinitdata = .get = snd_vt1724_spdif_maskp_get, }; -static int snd_vt1724_spdif_sw_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_vt1724_spdif_sw_info snd_ctl_boolean_mono_info static int snd_vt1724_spdif_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1532,15 +1526,7 @@ static struct snd_kcontrol_new snd_vt1724_spdif_switch __devinitdata = * GPIO access from extern */ -int snd_vt1724_gpio_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_vt1724_gpio_info snd_ctl_boolean_mono_info int snd_vt1724_gpio_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1706,15 +1692,7 @@ static struct snd_kcontrol_new snd_vt1724_pro_internal_clock __devinitdata = { .put = snd_vt1724_pro_internal_clock_put }; -static int snd_vt1724_pro_rate_locking_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_vt1724_pro_rate_locking_info snd_ctl_boolean_mono_info static int snd_vt1724_pro_rate_locking_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1745,15 +1723,7 @@ static struct snd_kcontrol_new snd_vt1724_pro_rate_locking __devinitdata = { .put = snd_vt1724_pro_rate_locking_put }; -static int snd_vt1724_pro_rate_reset_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_vt1724_pro_rate_reset_info snd_ctl_boolean_mono_info static int snd_vt1724_pro_rate_reset_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/pci/ice1712/juli.c b/sound/pci/ice1712/juli.c index 3d8e74e493d..1fbe3ef8e60 100644 --- a/sound/pci/ice1712/juli.c +++ b/sound/pci/ice1712/juli.c @@ -3,7 +3,7 @@ * * Lowlevel functions for ESI Juli@ cards * - * Copyright (c) 2004 Jaroslav Kysela <perex@suse.cz> + * Copyright (c) 2004 Jaroslav Kysela <perex@perex.cz> * * 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 diff --git a/sound/pci/ice1712/phase.c b/sound/pci/ice1712/phase.c index 40a9098af77..3ac25058bb5 100644 --- a/sound/pci/ice1712/phase.c +++ b/sound/pci/ice1712/phase.c @@ -270,7 +270,7 @@ static void wm_set_vol(struct snd_ice1712 *ice, unsigned int index, unsigned sho /* * DAC mute control */ -#define wm_pcm_mute_info phase28_mono_bool_info +#define wm_pcm_mute_info snd_ctl_boolean_mono_info static int wm_pcm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -527,13 +527,7 @@ static int wm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value /* * WM8770 master mute control */ -static int wm_master_mute_info(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 wm_master_mute_info snd_ctl_boolean_stereo_info static int wm_master_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -615,20 +609,9 @@ static int wm_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val } /* - */ -static int phase28_mono_bool_info(struct snd_kcontrol *k, 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; -} - -/* * Deemphasis */ -#define phase28_deemp_info phase28_mono_bool_info +#define phase28_deemp_info snd_ctl_boolean_mono_info static int phase28_deemp_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { diff --git a/sound/pci/ice1712/pontis.c b/sound/pci/ice1712/pontis.c index 01c69453dde..faefd52c1b8 100644 --- a/sound/pci/ice1712/pontis.c +++ b/sound/pci/ice1712/pontis.c @@ -216,14 +216,7 @@ static int wm_adc_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val /* * ADC input mux mixer control */ -static int wm_adc_mux_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 wm_adc_mux_info snd_ctl_boolean_mono_info static int wm_adc_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -260,14 +253,7 @@ static int wm_adc_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val /* * Analog bypass (In -> Out) */ -static int wm_bypass_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 wm_bypass_info snd_ctl_boolean_mono_info static int wm_bypass_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -302,14 +288,7 @@ static int wm_bypass_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_valu /* * Left/Right swap */ -static int wm_chswap_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 wm_chswap_info snd_ctl_boolean_mono_info static int wm_chswap_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { diff --git a/sound/pci/ice1712/prodigy192.c b/sound/pci/ice1712/prodigy192.c index 4bae7305a79..4180f9739ec 100644 --- a/sound/pci/ice1712/prodigy192.c +++ b/sound/pci/ice1712/prodigy192.c @@ -81,14 +81,7 @@ static inline unsigned char stac9460_get(struct snd_ice1712 *ice, int reg) /* * DAC mute control */ -static int stac9460_dac_mute_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 stac9460_dac_mute_info snd_ctl_boolean_mono_info static int stac9460_dac_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -177,14 +170,7 @@ static int stac9460_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el /* * ADC mute control */ -static int stac9460_adc_mute_info(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 stac9460_adc_mute_info snd_ctl_boolean_stereo_info static int stac9460_adc_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -292,14 +278,7 @@ static int aureon_get_headphone_amp(struct snd_ice1712 *ice) return ( tmp & AUREON_HP_SEL )!= 0; } -static int aureon_bool_info(struct snd_kcontrol *k, 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 aureon_bool_info snd_ctl_boolean_mono_info static int aureon_hpamp_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { diff --git a/sound/pci/ice1712/wtm.c b/sound/pci/ice1712/wtm.c index 04e535c8542..7fcce0a506d 100644 --- a/sound/pci/ice1712/wtm.c +++ b/sound/pci/ice1712/wtm.c @@ -71,14 +71,7 @@ static inline unsigned char stac9460_2_get(struct snd_ice1712 *ice, int reg) /* * DAC mute control */ -static int stac9460_dac_mute_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; - return 0; -} +#define stac9460_dac_mute_info snd_ctl_boolean_mono_info static int stac9460_dac_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -218,15 +211,7 @@ static int stac9460_dac_vol_put(struct snd_kcontrol *kcontrol, /* * ADC mute control */ -static int stac9460_adc_mute_info(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 stac9460_adc_mute_info snd_ctl_boolean_stereo_info static int stac9460_adc_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -357,15 +342,7 @@ static int stac9460_adc_vol_put(struct snd_kcontrol *kcontrol, * MIC / LINE switch fonction */ -static int stac9460_mic_sw_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 stac9460_mic_sw_info snd_ctl_boolean_mono_info static int stac9460_mic_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index da9734073db..b4a38a3d855 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -1,7 +1,7 @@ /* * ALSA driver for Intel ICH (i8x0) chipsets * - * Copyright (c) 2000 Jaroslav Kysela <perex@suse.cz> + * Copyright (c) 2000 Jaroslav Kysela <perex@perex.cz> * * * This code also contains alpha support for SiS 735 chipsets provided @@ -43,7 +43,7 @@ #include <asm/pgtable.h> #include <asm/cacheflush.h> -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("Intel 82801AA,82901AB,i810,i820,i830,i840,i845,MX440; SiS 7012; Ali 5455"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Intel,82801AA-ICH}," diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c index c155e1f3a0e..fad806e60f3 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c @@ -1,7 +1,7 @@ /* * ALSA modem driver for Intel ICH (i8x0) chipsets * - * Copyright (c) 2000 Jaroslav Kysela <perex@suse.cz> + * Copyright (c) 2000 Jaroslav Kysela <perex@perex.cz> * * This is modified (by Sasha Khapyorsky <sashak@alsa-project.org>) version * of ALSA ICH sound driver intel8x0.c . @@ -37,7 +37,7 @@ #include <sound/info.h> #include <sound/initval.h> -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("Intel 82801AA,82901AB,i810,i820,i830,i840,i845,MX440; " "SiS 7013; NVidia MCP/2/2S/3 modems"); MODULE_LICENSE("GPL"); diff --git a/sound/pci/korg1212/Makefile b/sound/pci/korg1212/Makefile index 78c9dc6eeb2..f11ce1b1b3d 100644 --- a/sound/pci/korg1212/Makefile +++ b/sound/pci/korg1212/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-korg1212-objs := korg1212.o diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c index 5338243fb03..c4af57fb5af 100644 --- a/sound/pci/korg1212/korg1212.c +++ b/sound/pci/korg1212/korg1212.c @@ -1391,8 +1391,6 @@ static int snd_korg1212_playback_open(struct snd_pcm_substream *substream) K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_playback_open [%s]\n", stateName[korg1212->cardState]); - snd_pcm_set_sync(substream); // ??? - snd_korg1212_OpenCard(korg1212); runtime->hw = snd_korg1212_playback_info; @@ -1422,8 +1420,6 @@ static int snd_korg1212_capture_open(struct snd_pcm_substream *substream) K1212_DEBUG_PRINTK("K1212_DEBUG: snd_korg1212_capture_open [%s]\n", stateName[korg1212->cardState]); - snd_pcm_set_sync(substream); - snd_korg1212_OpenCard(korg1212); runtime->hw = snd_korg1212_capture_info; diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index 8a5ff1cb536..32245770595 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c @@ -1821,7 +1821,6 @@ snd_m3_playback_open(struct snd_pcm_substream *subs) return err; runtime->hw = snd_m3_playback; - snd_pcm_set_sync(subs); return 0; } @@ -1846,7 +1845,6 @@ snd_m3_capture_open(struct snd_pcm_substream *subs) return err; runtime->hw = snd_m3_capture; - snd_pcm_set_sync(subs); return 0; } diff --git a/sound/pci/mixart/Makefile b/sound/pci/mixart/Makefile index fe6ba0c4b56..cce159ec562 100644 --- a/sound/pci/mixart/Makefile +++ b/sound/pci/mixart/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-mixart-objs := mixart.o mixart_core.o mixart_hwdep.o mixart_mixer.o diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c index ac007cec087..880b824e24c 100644 --- a/sound/pci/mixart/mixart.c +++ b/sound/pci/mixart/mixart.c @@ -652,7 +652,7 @@ static int snd_mixart_hw_free(struct snd_pcm_substream *subs) static struct snd_pcm_hardware snd_mixart_analog_caps = { .info = ( SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START | + SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE), .formats = ( SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | @@ -673,7 +673,7 @@ static struct snd_pcm_hardware snd_mixart_analog_caps = static struct snd_pcm_hardware snd_mixart_digital_caps = { .info = ( SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START | + SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE), .formats = ( SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | @@ -1317,6 +1317,12 @@ static int __devinit snd_mixart_probe(struct pci_dev *pci, mgr->mem[i].phys = pci_resource_start(pci, i); mgr->mem[i].virt = ioremap_nocache(mgr->mem[i].phys, pci_resource_len(pci, i)); + if (!mgr->mem[i].virt) { + printk(KERN_ERR "unable to remap resource 0x%lx\n", + mgr->mem[i].phys); + snd_mixart_free(mgr); + return -EBUSY; + } } if (request_irq(pci->irq, snd_mixart_interrupt, IRQF_SHARED, diff --git a/sound/pci/mixart/mixart_mixer.c b/sound/pci/mixart/mixart_mixer.c index d7d15c036e0..0e16512d25f 100644 --- a/sound/pci/mixart/mixart_mixer.c +++ b/sound/pci/mixart/mixart_mixer.c @@ -403,14 +403,7 @@ static struct snd_kcontrol_new mixart_control_analog_level = { }; /* shared */ -static int mixart_sw_info(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 mixart_sw_info snd_ctl_boolean_stereo_info static int mixart_audio_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { diff --git a/sound/pci/nm256/Makefile b/sound/pci/nm256/Makefile index d91d8c51921..a1bd44ff850 100644 --- a/sound/pci/nm256/Makefile +++ b/sound/pci/nm256/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-nm256-objs := nm256.o diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c index c7621bd770a..276c5763f0e 100644 --- a/sound/pci/nm256/nm256.c +++ b/sound/pci/nm256/nm256.c @@ -842,7 +842,6 @@ static void snd_nm256_setup_stream(struct nm256 *chip, struct nm256_stream *s, runtime->private_data = s; s->substream = substream; - snd_pcm_set_sync(substream); snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); } diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c index f7f6a687f03..2d618bd7e62 100644 --- a/sound/pci/pcxhr/pcxhr.c +++ b/sound/pci/pcxhr/pcxhr.c @@ -646,6 +646,8 @@ static int pcxhr_trigger(struct snd_pcm_substream *subs, int cmd) if (snd_pcm_stream_linked(subs)) { struct snd_pcxhr *chip = snd_pcm_substream_chip(subs); snd_pcm_group_for_each_entry(s, subs) { + if (snd_pcm_substream_chip(s) != chip) + continue; stream = s->runtime->private_data; stream->status = PCXHR_STREAM_STATUS_SCHEDULE_RUN; @@ -662,6 +664,7 @@ static int pcxhr_trigger(struct snd_pcm_substream *subs, int cmd) if (pcxhr_update_r_buffer(stream)) return -EINVAL; + stream->status = PCXHR_STREAM_STATUS_SCHEDULE_RUN; if (pcxhr_set_stream_state(stream)) return -EINVAL; stream->status = PCXHR_STREAM_STATUS_RUNNING; @@ -902,6 +905,8 @@ static int pcxhr_open(struct snd_pcm_substream *subs) snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 4); snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 4); + snd_pcm_set_sync(subs); + mgr->ref_count_rate++; mutex_unlock(&mgr->setup_mutex); diff --git a/sound/pci/pcxhr/pcxhr_mixer.c b/sound/pci/pcxhr/pcxhr_mixer.c index d9cc8d2beb6..5f8d42633b0 100644 --- a/sound/pci/pcxhr/pcxhr_mixer.c +++ b/sound/pci/pcxhr/pcxhr_mixer.c @@ -44,8 +44,8 @@ #define PCXHR_ANALOG_PLAYBACK_LEVEL_MAX 128 /* 0.0 dB */ #define PCXHR_ANALOG_PLAYBACK_ZERO_LEVEL 104 /* -24.0 dB ( 0.0 dB - fix level +24.0 dB ) */ -static const DECLARE_TLV_DB_SCALE(db_scale_analog_capture, -9600, 50, 0); -static const DECLARE_TLV_DB_SCALE(db_scale_analog_playback, -12800, 100, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_analog_capture, -9600, 50, 3150); +static const DECLARE_TLV_DB_SCALE(db_scale_analog_playback, -10400, 100, 2400); static int pcxhr_update_analog_audio_level(struct snd_pcxhr *chip, int is_capture, int channel) { @@ -144,14 +144,7 @@ static struct snd_kcontrol_new pcxhr_control_analog_level = { }; /* shared */ -static int pcxhr_sw_info(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 pcxhr_sw_info snd_ctl_boolean_stereo_info static int pcxhr_audio_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -195,7 +188,7 @@ static struct snd_kcontrol_new pcxhr_control_output_switch = { #define PCXHR_DIGITAL_LEVEL_MAX 0x1ff /* +18 dB */ #define PCXHR_DIGITAL_ZERO_LEVEL 0x1b7 /* 0 dB */ -static const DECLARE_TLV_DB_SCALE(db_scale_digital, -10950, 50, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_digital, -10975, 25, 1800); #define MORE_THAN_ONE_STREAM_LEVEL 0x000001 #define VALID_STREAM_PAN_LEVEL_MASK 0x800000 diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c index 618653e2256..1475912588e 100644 --- a/sound/pci/rme32.c +++ b/sound/pci/rme32.c @@ -258,19 +258,6 @@ static inline unsigned int snd_rme32_pcm_byteptr(struct rme32 * rme32) & RME32_RCR_AUDIO_ADDR_MASK); } -static int snd_rme32_ratecode(int rate) -{ - switch (rate) { - case 32000: return SNDRV_PCM_RATE_32000; - case 44100: return SNDRV_PCM_RATE_44100; - case 48000: return SNDRV_PCM_RATE_48000; - case 64000: return SNDRV_PCM_RATE_64000; - case 88200: return SNDRV_PCM_RATE_88200; - case 96000: return SNDRV_PCM_RATE_96000; - } - return 0; -} - /* silence callback for halfduplex mode */ static int snd_rme32_playback_silence(struct snd_pcm_substream *substream, int channel, /* not used (interleaved data) */ snd_pcm_uframes_t pos, @@ -887,7 +874,7 @@ static int snd_rme32_playback_spdif_open(struct snd_pcm_substream *substream) if ((rme32->rcreg & RME32_RCR_KMODE) && (rate = snd_rme32_capture_getrate(rme32, &dummy)) > 0) { /* AutoSync */ - runtime->hw.rates = snd_rme32_ratecode(rate); + runtime->hw.rates = snd_pcm_rate_to_rate_bit(rate); runtime->hw.rate_min = rate; runtime->hw.rate_max = rate; } @@ -929,7 +916,7 @@ static int snd_rme32_capture_spdif_open(struct snd_pcm_substream *substream) if (isadat) { return -EIO; } - runtime->hw.rates = snd_rme32_ratecode(rate); + runtime->hw.rates = snd_pcm_rate_to_rate_bit(rate); runtime->hw.rate_min = rate; runtime->hw.rate_max = rate; } @@ -965,7 +952,7 @@ snd_rme32_playback_adat_open(struct snd_pcm_substream *substream) if ((rme32->rcreg & RME32_RCR_KMODE) && (rate = snd_rme32_capture_getrate(rme32, &dummy)) > 0) { /* AutoSync */ - runtime->hw.rates = snd_rme32_ratecode(rate); + runtime->hw.rates = snd_pcm_rate_to_rate_bit(rate); runtime->hw.rate_min = rate; runtime->hw.rate_max = rate; } @@ -989,7 +976,7 @@ snd_rme32_capture_adat_open(struct snd_pcm_substream *substream) if (!isadat) { return -EIO; } - runtime->hw.rates = snd_rme32_ratecode(rate); + runtime->hw.rates = snd_pcm_rate_to_rate_bit(rate); runtime->hw.rate_min = rate; runtime->hw.rate_max = rate; } @@ -1582,16 +1569,8 @@ static void __devinit snd_rme32_proc_init(struct rme32 * rme32) * control interface */ -static int -snd_rme32_info_loopback_control(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_rme32_info_loopback_control snd_ctl_boolean_mono_info + static int snd_rme32_get_loopback_control(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c index e3304b7ccbc..0b3c532c401 100644 --- a/sound/pci/rme96.c +++ b/sound/pci/rme96.c @@ -301,20 +301,6 @@ snd_rme96_capture_ptr(struct rme96 *rme96) } static int -snd_rme96_ratecode(int rate) -{ - switch (rate) { - case 32000: return SNDRV_PCM_RATE_32000; - case 44100: return SNDRV_PCM_RATE_44100; - case 48000: return SNDRV_PCM_RATE_48000; - case 64000: return SNDRV_PCM_RATE_64000; - case 88200: return SNDRV_PCM_RATE_88200; - case 96000: return SNDRV_PCM_RATE_96000; - } - return 0; -} - -static int snd_rme96_playback_silence(struct snd_pcm_substream *substream, int channel, /* not used (interleaved data) */ snd_pcm_uframes_t pos, @@ -1176,8 +1162,6 @@ snd_rme96_playback_spdif_open(struct snd_pcm_substream *substream) struct rme96 *rme96 = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; - snd_pcm_set_sync(substream); - spin_lock_irq(&rme96->lock); if (rme96->playback_substream != NULL) { spin_unlock_irq(&rme96->lock); @@ -1194,7 +1178,7 @@ snd_rme96_playback_spdif_open(struct snd_pcm_substream *substream) (rate = snd_rme96_capture_getrate(rme96, &dummy)) > 0) { /* slave clock */ - runtime->hw.rates = snd_rme96_ratecode(rate); + runtime->hw.rates = snd_pcm_rate_to_rate_bit(rate); runtime->hw.rate_min = rate; runtime->hw.rate_max = rate; } @@ -1214,8 +1198,6 @@ snd_rme96_capture_spdif_open(struct snd_pcm_substream *substream) struct rme96 *rme96 = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; - snd_pcm_set_sync(substream); - runtime->hw = snd_rme96_capture_spdif_info; if (snd_rme96_getinputtype(rme96) != RME96_INPUT_ANALOG && (rate = snd_rme96_capture_getrate(rme96, &isadat)) > 0) @@ -1223,7 +1205,7 @@ snd_rme96_capture_spdif_open(struct snd_pcm_substream *substream) if (isadat) { return -EIO; } - runtime->hw.rates = snd_rme96_ratecode(rate); + runtime->hw.rates = snd_pcm_rate_to_rate_bit(rate); runtime->hw.rate_min = rate; runtime->hw.rate_max = rate; } @@ -1247,8 +1229,6 @@ snd_rme96_playback_adat_open(struct snd_pcm_substream *substream) struct rme96 *rme96 = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; - snd_pcm_set_sync(substream); - spin_lock_irq(&rme96->lock); if (rme96->playback_substream != NULL) { spin_unlock_irq(&rme96->lock); @@ -1265,7 +1245,7 @@ snd_rme96_playback_adat_open(struct snd_pcm_substream *substream) (rate = snd_rme96_capture_getrate(rme96, &dummy)) > 0) { /* slave clock */ - runtime->hw.rates = snd_rme96_ratecode(rate); + runtime->hw.rates = snd_pcm_rate_to_rate_bit(rate); runtime->hw.rate_min = rate; runtime->hw.rate_max = rate; } @@ -1280,8 +1260,6 @@ snd_rme96_capture_adat_open(struct snd_pcm_substream *substream) struct rme96 *rme96 = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; - snd_pcm_set_sync(substream); - runtime->hw = snd_rme96_capture_adat_info; if (snd_rme96_getinputtype(rme96) == RME96_INPUT_ANALOG) { /* makes no sense to use analog input. Note that analog @@ -1292,7 +1270,7 @@ snd_rme96_capture_adat_open(struct snd_pcm_substream *substream) if (!isadat) { return -EIO; } - runtime->hw.rates = snd_rme96_ratecode(rate); + runtime->hw.rates = snd_pcm_rate_to_rate_bit(rate); runtime->hw.rate_min = rate; runtime->hw.rate_max = rate; } @@ -1826,15 +1804,8 @@ snd_rme96_proc_init(struct rme96 *rme96) * control interface */ -static int -snd_rme96_info_loopback_control(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_rme96_info_loopback_control snd_ctl_boolean_mono_info + static int snd_rme96_get_loopback_control(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { diff --git a/sound/pci/rme9652/Makefile b/sound/pci/rme9652/Makefile index d2c294e136f..dcba5604020 100644 --- a/sound/pci/rme9652/Makefile +++ b/sound/pci/rme9652/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-rme9652-objs := rme9652.o diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 3b3ef657f73..ff26a3672d4 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -606,28 +606,28 @@ static void snd_hdsp_9652_enable_mixer (struct hdsp *hdsp); static int hdsp_playback_to_output_key (struct hdsp *hdsp, int in, int out) { - switch (hdsp->firmware_rev) { - case 0xa: + switch (hdsp->io_type) { + case Multiface: + case Digiface: + default: return (64 * out) + (32 + (in)); - case 0x96: - case 0x97: - case 0x98: + case H9632: return (32 * out) + (16 + (in)); - default: + case H9652: return (52 * out) + (26 + (in)); } } static int hdsp_input_to_output_key (struct hdsp *hdsp, int in, int out) { - switch (hdsp->firmware_rev) { - case 0xa: + switch (hdsp->io_type) { + case Multiface: + case Digiface: + default: return (64 * out) + in; - case 0x96: - case 0x97: - case 0x98: + case H9632: return (32 * out) + in; - default: + case H9652: return (52 * out) + in; } } @@ -1623,14 +1623,7 @@ static int hdsp_set_spdif_output(struct hdsp *hdsp, int out) return 0; } -static int snd_hdsp_info_spdif_bits(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_hdsp_info_spdif_bits snd_ctl_boolean_mono_info static int snd_hdsp_get_spdif_out(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -2111,14 +2104,7 @@ static int snd_hdsp_put_clock_source(struct snd_kcontrol *kcontrol, struct snd_c return change; } -static int snd_hdsp_info_clock_source_lock(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_hdsp_info_clock_source_lock snd_ctl_boolean_mono_info static int snd_hdsp_get_clock_source_lock(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -2420,14 +2406,7 @@ static int hdsp_set_xlr_breakout_cable(struct hdsp *hdsp, int mode) return 0; } -static int snd_hdsp_info_xlr_breakout_cable(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_hdsp_info_xlr_breakout_cable snd_ctl_boolean_mono_info static int snd_hdsp_get_xlr_breakout_cable(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -2483,14 +2462,7 @@ static int hdsp_set_aeb(struct hdsp *hdsp, int mode) return 0; } -static int snd_hdsp_info_aeb(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_hdsp_info_aeb snd_ctl_boolean_mono_info static int snd_hdsp_get_aeb(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -2729,14 +2701,7 @@ static int hdsp_set_line_output(struct hdsp *hdsp, int out) return 0; } -static int snd_hdsp_info_line_out(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_hdsp_info_line_out snd_ctl_boolean_mono_info static int snd_hdsp_get_line_out(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -2782,14 +2747,7 @@ static int hdsp_set_precise_pointer(struct hdsp *hdsp, int precise) return 0; } -static int snd_hdsp_info_precise_pointer(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_hdsp_info_precise_pointer snd_ctl_boolean_mono_info static int snd_hdsp_get_precise_pointer(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -2835,14 +2793,7 @@ static int hdsp_set_use_midi_tasklet(struct hdsp *hdsp, int use_tasklet) return 0; } -static int snd_hdsp_info_use_midi_tasklet(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_hdsp_info_use_midi_tasklet snd_ctl_boolean_mono_info static int snd_hdsp_get_use_midi_tasklet(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -3108,6 +3059,9 @@ static int hdsp_dds_offset(struct hdsp *hdsp) unsigned int dds_value = hdsp->dds_value; int system_sample_rate = hdsp->system_sample_rate; + if (!dds_value) + return 0; + n = DDS_NUMERATOR; /* * dds_value = n / rate diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 143185e7e4d..f1bdda6cbcf 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -1,5 +1,4 @@ -/* -*- linux-c -*- - * +/* * ALSA driver for RME Hammerfall DSP MADI audio interface(s) * * Copyright (c) 2003 Winfried Ritsch (IEM) @@ -78,7 +77,8 @@ MODULE_PARM_DESC(enable_monitor, "Enable Analog Out on Channel 63/64 by default."); MODULE_AUTHOR - ("Winfried Ritsch <ritsch_AT_iem.at>, Paul Davis <paul@linuxaudiosystems.com>, " + ("Winfried Ritsch <ritsch_AT_iem.at>, " + "Paul Davis <paul@linuxaudiosystems.com>, " "Marcus Andersson, Thomas Charbonnel <thomas@undata.org>, " "Remy Bruno <remy.bruno@trinnov.com>"); MODULE_DESCRIPTION("RME HDSPM"); @@ -161,7 +161,9 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); 0=off, 1=on */ /* MADI ONLY */ #define HDSPM_Dolby (1<<11) /* Dolby = "NonAudio" ?? */ /* AES32 ONLY */ -#define HDSPM_InputSelect0 (1<<14) /* Input select 0= optical, 1=coax */ /* MADI ONLY*/ +#define HDSPM_InputSelect0 (1<<14) /* Input select 0= optical, 1=coax + * -- MADI ONLY + */ #define HDSPM_InputSelect1 (1<<15) /* should be 0 */ #define HDSPM_SyncRef0 (1<<16) /* 0=WOrd, 1=MADI */ @@ -189,11 +191,13 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); /* --- bit helper defines */ #define HDSPM_LatencyMask (HDSPM_Latency0|HDSPM_Latency1|HDSPM_Latency2) -#define HDSPM_FrequencyMask (HDSPM_Frequency0|HDSPM_Frequency1|HDSPM_DoubleSpeed|HDSPM_QuadSpeed) +#define HDSPM_FrequencyMask (HDSPM_Frequency0|HDSPM_Frequency1|\ + HDSPM_DoubleSpeed|HDSPM_QuadSpeed) #define HDSPM_InputMask (HDSPM_InputSelect0|HDSPM_InputSelect1) #define HDSPM_InputOptical 0 #define HDSPM_InputCoaxial (HDSPM_InputSelect0) -#define HDSPM_SyncRefMask (HDSPM_SyncRef0|HDSPM_SyncRef1|HDSPM_SyncRef2|HDSPM_SyncRef3) +#define HDSPM_SyncRefMask (HDSPM_SyncRef0|HDSPM_SyncRef1|\ + HDSPM_SyncRef2|HDSPM_SyncRef3) #define HDSPM_SyncRef_Word 0 #define HDSPM_SyncRef_MADI (HDSPM_SyncRef0) @@ -205,10 +209,12 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); #define HDSPM_Frequency48KHz (HDSPM_Frequency1|HDSPM_Frequency0) #define HDSPM_Frequency64KHz (HDSPM_DoubleSpeed|HDSPM_Frequency0) #define HDSPM_Frequency88_2KHz (HDSPM_DoubleSpeed|HDSPM_Frequency1) -#define HDSPM_Frequency96KHz (HDSPM_DoubleSpeed|HDSPM_Frequency1|HDSPM_Frequency0) +#define HDSPM_Frequency96KHz (HDSPM_DoubleSpeed|HDSPM_Frequency1|\ + HDSPM_Frequency0) #define HDSPM_Frequency128KHz (HDSPM_QuadSpeed|HDSPM_Frequency0) #define HDSPM_Frequency176_4KHz (HDSPM_QuadSpeed|HDSPM_Frequency1) -#define HDSPM_Frequency192KHz (HDSPM_QuadSpeed|HDSPM_Frequency1|HDSPM_Frequency0) +#define HDSPM_Frequency192KHz (HDSPM_QuadSpeed|HDSPM_Frequency1|\ + HDSPM_Frequency0) /* --- for internal discrimination */ #define HDSPM_CLOCK_SOURCE_AUTOSYNC 0 /* Sample Clock Sources */ @@ -256,10 +262,14 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); #define HDSPM_RD_MULTIPLE (1<<10) /* --- Status Register bits --- */ /* MADI ONLY */ /* Bits defined here and - that do not conflict with specific bits for AES32 seem to be valid also for the AES32 */ + that do not conflict with specific bits for AES32 seem to be valid also + for the AES32 + */ #define HDSPM_audioIRQPending (1<<0) /* IRQ is high and pending */ -#define HDSPM_RX_64ch (1<<1) /* Input 64chan. MODE=1, 56chn. MODE=0 */ -#define HDSPM_AB_int (1<<2) /* InputChannel Opt=0, Coax=1 (like inp0) */ +#define HDSPM_RX_64ch (1<<1) /* Input 64chan. MODE=1, 56chn MODE=0 */ +#define HDSPM_AB_int (1<<2) /* InputChannel Opt=0, Coax=1 + * (like inp0) + */ #define HDSPM_madiLock (1<<3) /* MADI Locked =1, no=0 */ #define HDSPM_BufferPositionMask 0x000FFC0 /* Bit 6..15 : h/w buffer pointer */ @@ -274,12 +284,15 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); #define HDSPM_madiFreq2 (1<<24) /* 4=64, 5=88.2 6=96 */ #define HDSPM_madiFreq3 (1<<25) /* 7=128, 8=176.4 9=192 */ -#define HDSPM_BufferID (1<<26) /* (Double)Buffer ID toggles with Interrupt */ +#define HDSPM_BufferID (1<<26) /* (Double)Buffer ID toggles with + * Interrupt + */ #define HDSPM_midi0IRQPending (1<<30) /* MIDI IRQ is pending */ #define HDSPM_midi1IRQPending (1<<31) /* and aktiv */ /* --- status bit helpers */ -#define HDSPM_madiFreqMask (HDSPM_madiFreq0|HDSPM_madiFreq1|HDSPM_madiFreq2|HDSPM_madiFreq3) +#define HDSPM_madiFreqMask (HDSPM_madiFreq0|HDSPM_madiFreq1|\ + HDSPM_madiFreq2|HDSPM_madiFreq3) #define HDSPM_madiFreq32 (HDSPM_madiFreq0) #define HDSPM_madiFreq44_1 (HDSPM_madiFreq1) #define HDSPM_madiFreq48 (HDSPM_madiFreq0|HDSPM_madiFreq1) @@ -319,10 +332,12 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); #define HDSPM_wcFreq96 (HDSPM_wc_freq1|HDSPM_wc_freq2) -#define HDSPM_SelSyncRefMask (HDSPM_SelSyncRef0|HDSPM_SelSyncRef1|HDSPM_SelSyncRef2) +#define HDSPM_SelSyncRefMask (HDSPM_SelSyncRef0|HDSPM_SelSyncRef1|\ + HDSPM_SelSyncRef2) #define HDSPM_SelSyncRef_WORD 0 #define HDSPM_SelSyncRef_MADI (HDSPM_SelSyncRef0) -#define HDSPM_SelSyncRef_NVALID (HDSPM_SelSyncRef0|HDSPM_SelSyncRef1|HDSPM_SelSyncRef2) +#define HDSPM_SelSyncRef_NVALID (HDSPM_SelSyncRef0|HDSPM_SelSyncRef1|\ + HDSPM_SelSyncRef2) /* For AES32, bits for status, status2 and timecode are different @@ -344,7 +359,7 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); #define HDSPM_AES32_AUTOSYNC_FROM_AES6 6 #define HDSPM_AES32_AUTOSYNC_FROM_AES7 7 #define HDSPM_AES32_AUTOSYNC_FROM_AES8 8 -#define HDSPM_AES32_AUTOSYNC_FROM_NONE -1 +#define HDSPM_AES32_AUTOSYNC_FROM_NONE 9 /* status2 */ /* HDSPM_LockAES_bit is given by HDSPM_LockAES >> (AES# - 1) */ @@ -398,6 +413,13 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); /* revisions >= 230 indicate AES32 card */ #define HDSPM_AESREVISION 230 +/* speed factor modes */ +#define HDSPM_SPEED_SINGLE 0 +#define HDSPM_SPEED_DOUBLE 1 +#define HDSPM_SPEED_QUAD 2 +/* names for speed modes */ +static char *hdspm_speed_names[] = { "single", "double", "quad" }; + struct hdspm_midi { struct hdspm *hdspm; int id; @@ -412,8 +434,9 @@ struct hdspm_midi { struct hdspm { spinlock_t lock; - struct snd_pcm_substream *capture_substream; /* only one playback */ - struct snd_pcm_substream *playback_substream; /* and/or capture stream */ + /* only one playback and/or capture stream */ + struct snd_pcm_substream *capture_substream; + struct snd_pcm_substream *playback_substream; char *card_name; /* for procinfo */ unsigned short firmware_rev; /* dont know if relevant (yes if AES32)*/ @@ -460,9 +483,12 @@ struct hdspm { struct pci_dev *pci; /* and an pci info */ /* Mixer vars */ - struct snd_kcontrol *playback_mixer_ctls[HDSPM_MAX_CHANNELS]; /* fast alsa mixer */ - struct snd_kcontrol *input_mixer_ctls[HDSPM_MAX_CHANNELS]; /* but input to much, so not used */ - struct hdspm_mixer *mixer; /* full mixer accessable over mixer ioctl or hwdep-device */ + /* fast alsa mixer */ + struct snd_kcontrol *playback_mixer_ctls[HDSPM_MAX_CHANNELS]; + /* but input to much, so not used */ + struct snd_kcontrol *input_mixer_ctls[HDSPM_MAX_CHANNELS]; + /* full mixer accessable over mixer ioctl or hwdep-device */ + struct hdspm_mixer *mixer; }; @@ -616,13 +642,15 @@ static inline int hdspm_external_sample_rate(struct hdspm * hdspm) if (hdspm->is_aes32) { unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2); unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister); - unsigned int timecode = hdspm_read(hdspm, HDSPM_timecodeRegister); + unsigned int timecode = + hdspm_read(hdspm, HDSPM_timecodeRegister); int syncref = hdspm_autosync_ref(hdspm); if (syncref == HDSPM_AES32_AUTOSYNC_FROM_WORD && status & HDSPM_AES32_wcLock) - return HDSPM_bit2freq((status >> HDSPM_AES32_wcFreq_bit) & 0xF); + return HDSPM_bit2freq((status >> HDSPM_AES32_wcFreq_bit) + & 0xF); if (syncref >= HDSPM_AES32_AUTOSYNC_FROM_AES1 && syncref <= HDSPM_AES32_AUTOSYNC_FROM_AES8 && status2 & (HDSPM_LockAES >> @@ -668,7 +696,9 @@ static inline int hdspm_external_sample_rate(struct hdspm * hdspm) } } - /* if rate detected and Syncref is Word than have it, word has priority to MADI */ + /* if rate detected and Syncref is Word than have it, + * word has priority to MADI + */ if (rate != 0 && (status2 & HDSPM_SelSyncRefMask) == HDSPM_SelSyncRef_WORD) return rate; @@ -727,12 +757,12 @@ static snd_pcm_uframes_t hdspm_hw_pointer(struct hdspm * hdspm) position = hdspm_read(hdspm, HDSPM_statusRegister); - if (!hdspm->precise_ptr) { - return (position & HDSPM_BufferID) ? (hdspm->period_bytes / - 4) : 0; - } + if (!hdspm->precise_ptr) + return (position & HDSPM_BufferID) ? + (hdspm->period_bytes / 4) : 0; - /* hwpointer comes in bytes and is 64Bytes accurate (by docu since PCI Burst) + /* hwpointer comes in bytes and is 64Bytes accurate (by docu since + PCI Burst) i have experimented that it is at most 64 Byte to much for playing so substraction of 64 byte should be ok for ALSA, but use it only for application where you know what you do since if you come to @@ -811,7 +841,7 @@ static void hdspm_set_dds_value(struct hdspm *hdspm, int rate) // return 104857600000000 / rate; // 100 MHz return 110100480000000 / rate; // 105 MHz */ - //n = 104857600000000ULL; /* = 2^20 * 10^8 */ + /* n = 104857600000000ULL; */ /* = 2^20 * 10^8 */ n = 110100480000000ULL; /* Value checked for AES32 and MADI */ div64_32(&n, rate, &r); /* n should be less than 2^32 for being written to FREQ register */ @@ -822,11 +852,10 @@ static void hdspm_set_dds_value(struct hdspm *hdspm, int rate) /* dummy set rate lets see what happens */ static int hdspm_set_rate(struct hdspm * hdspm, int rate, int called_internally) { - int reject_if_open = 0; int current_rate; int rate_bits; int not_set = 0; - int is_single, is_double, is_quad; + int current_speed, target_speed; /* ASSUMPTION: hdspm->lock is either set, or there is no need for it (e.g. during module initialization). @@ -841,8 +870,9 @@ static int hdspm_set_rate(struct hdspm * hdspm, int rate, int called_internally) just make a warning an remember setting for future master mode switching */ - snd_printk - (KERN_WARNING "HDSPM: Warning: device is not running as a clock master.\n"); + snd_printk(KERN_WARNING "HDSPM: " + "Warning: device is not running " + "as a clock master.\n"); not_set = 1; } else { @@ -850,16 +880,18 @@ static int hdspm_set_rate(struct hdspm * hdspm, int rate, int called_internally) int external_freq = hdspm_external_sample_rate(hdspm); - if ((hdspm_autosync_ref(hdspm) == - HDSPM_AUTOSYNC_FROM_NONE)) { + if (hdspm_autosync_ref(hdspm) == + HDSPM_AUTOSYNC_FROM_NONE) { - snd_printk(KERN_WARNING "HDSPM: Detected no Externel Sync \n"); + snd_printk(KERN_WARNING "HDSPM: " + "Detected no Externel Sync \n"); not_set = 1; } else if (rate != external_freq) { - snd_printk - (KERN_WARNING "HDSPM: Warning: No AutoSync source for requested rate\n"); + snd_printk(KERN_WARNING "HDSPM: " + "Warning: No AutoSync source for " + "requested rate\n"); not_set = 1; } } @@ -877,64 +909,60 @@ static int hdspm_set_rate(struct hdspm * hdspm, int rate, int called_internally) changes in the read/write routines. */ - is_single = (current_rate <= 48000); - is_double = (current_rate > 48000 && current_rate <= 96000); - is_quad = (current_rate > 96000); + if (current_rate <= 48000) + current_speed = HDSPM_SPEED_SINGLE; + else if (current_rate <= 96000) + current_speed = HDSPM_SPEED_DOUBLE; + else + current_speed = HDSPM_SPEED_QUAD; + + if (rate <= 48000) + target_speed = HDSPM_SPEED_SINGLE; + else if (rate <= 96000) + target_speed = HDSPM_SPEED_DOUBLE; + else + target_speed = HDSPM_SPEED_QUAD; switch (rate) { case 32000: - if (!is_single) - reject_if_open = 1; rate_bits = HDSPM_Frequency32KHz; break; case 44100: - if (!is_single) - reject_if_open = 1; rate_bits = HDSPM_Frequency44_1KHz; break; case 48000: - if (!is_single) - reject_if_open = 1; rate_bits = HDSPM_Frequency48KHz; break; case 64000: - if (!is_double) - reject_if_open = 1; rate_bits = HDSPM_Frequency64KHz; break; case 88200: - if (!is_double) - reject_if_open = 1; rate_bits = HDSPM_Frequency88_2KHz; break; case 96000: - if (!is_double) - reject_if_open = 1; rate_bits = HDSPM_Frequency96KHz; break; case 128000: - if (!is_quad) - reject_if_open = 1; rate_bits = HDSPM_Frequency128KHz; break; case 176400: - if (!is_quad) - reject_if_open = 1; rate_bits = HDSPM_Frequency176_4KHz; break; case 192000: - if (!is_quad) - reject_if_open = 1; rate_bits = HDSPM_Frequency192KHz; break; default: return -EINVAL; } - if (reject_if_open + if (current_speed != target_speed && (hdspm->capture_pid >= 0 || hdspm->playback_pid >= 0)) { snd_printk - (KERN_ERR "HDSPM: cannot change between single- and double-speed mode (capture PID = %d, playback PID = %d)\n", + (KERN_ERR "HDSPM: " + "cannot change from %s speed to %s speed mode " + "(capture PID = %d, playback PID = %d)\n", + hdspm_speed_names[current_speed], + hdspm_speed_names[target_speed], hdspm->capture_pid, hdspm->playback_pid); return -EBUSY; } @@ -966,8 +994,14 @@ static int hdspm_set_rate(struct hdspm * hdspm, int rate, int called_internally) static void all_in_all_mixer(struct hdspm * hdspm, int sgain) { int i, j; - unsigned int gain = - (sgain > UNITY_GAIN) ? UNITY_GAIN : (sgain < 0) ? 0 : sgain; + unsigned int gain; + + if (sgain > UNITY_GAIN) + gain = UNITY_GAIN; + else if (sgain < 0) + gain = 0; + else + gain = sgain; for (i = 0; i < HDSPM_MIXER_CHANNELS; i++) for (j = 0; j < HDSPM_MIXER_CHANNELS; j++) { @@ -980,7 +1014,8 @@ static void all_in_all_mixer(struct hdspm * hdspm, int sgain) MIDI ----------------------------------------------------------------------------*/ -static inline unsigned char snd_hdspm_midi_read_byte (struct hdspm *hdspm, int id) +static inline unsigned char snd_hdspm_midi_read_byte (struct hdspm *hdspm, + int id) { /* the hardware already does the relevant bit-mask with 0xff */ if (id) @@ -989,7 +1024,8 @@ static inline unsigned char snd_hdspm_midi_read_byte (struct hdspm *hdspm, int i return hdspm_read(hdspm, HDSPM_midiDataIn0); } -static inline void snd_hdspm_midi_write_byte (struct hdspm *hdspm, int id, int val) +static inline void snd_hdspm_midi_write_byte (struct hdspm *hdspm, int id, + int val) { /* the hardware already does the relevant bit-mask with 0xff */ if (id) @@ -1011,9 +1047,10 @@ static inline int snd_hdspm_midi_output_possible (struct hdspm *hdspm, int id) int fifo_bytes_used; if (id) - fifo_bytes_used = hdspm_read(hdspm, HDSPM_midiStatusOut1) & 0xff; + fifo_bytes_used = hdspm_read(hdspm, HDSPM_midiStatusOut1); else - fifo_bytes_used = hdspm_read(hdspm, HDSPM_midiStatusOut0) & 0xff; + fifo_bytes_used = hdspm_read(hdspm, HDSPM_midiStatusOut0); + fifo_bytes_used &= 0xff; if (fifo_bytes_used < 128) return 128 - fifo_bytes_used; @@ -1038,16 +1075,21 @@ static int snd_hdspm_midi_output_write (struct hdspm_midi *hmidi) /* Output is not interrupt driven */ spin_lock_irqsave (&hmidi->lock, flags); - if (hmidi->output) { - if (!snd_rawmidi_transmit_empty (hmidi->output)) { - if ((n_pending = snd_hdspm_midi_output_possible (hmidi->hdspm, hmidi->id)) > 0) { - if (n_pending > (int)sizeof (buf)) - n_pending = sizeof (buf); - - if ((to_write = snd_rawmidi_transmit (hmidi->output, buf, n_pending)) > 0) { - for (i = 0; i < to_write; ++i) - snd_hdspm_midi_write_byte (hmidi->hdspm, hmidi->id, buf[i]); - } + if (hmidi->output && + !snd_rawmidi_transmit_empty (hmidi->output)) { + n_pending = snd_hdspm_midi_output_possible (hmidi->hdspm, + hmidi->id); + if (n_pending > 0) { + if (n_pending > (int)sizeof (buf)) + n_pending = sizeof (buf); + + to_write = snd_rawmidi_transmit (hmidi->output, buf, + n_pending); + if (to_write > 0) { + for (i = 0; i < to_write; ++i) + snd_hdspm_midi_write_byte (hmidi->hdspm, + hmidi->id, + buf[i]); } } } @@ -1057,51 +1099,55 @@ static int snd_hdspm_midi_output_write (struct hdspm_midi *hmidi) static int snd_hdspm_midi_input_read (struct hdspm_midi *hmidi) { - unsigned char buf[128]; /* this buffer is designed to match the MIDI input FIFO size */ + unsigned char buf[128]; /* this buffer is designed to match the MIDI + * input FIFO size + */ unsigned long flags; int n_pending; int i; spin_lock_irqsave (&hmidi->lock, flags); - if ((n_pending = snd_hdspm_midi_input_available (hmidi->hdspm, hmidi->id)) > 0) { + n_pending = snd_hdspm_midi_input_available (hmidi->hdspm, hmidi->id); + if (n_pending > 0) { if (hmidi->input) { - if (n_pending > (int)sizeof (buf)) { + if (n_pending > (int)sizeof (buf)) n_pending = sizeof (buf); - } - for (i = 0; i < n_pending; ++i) { - buf[i] = snd_hdspm_midi_read_byte (hmidi->hdspm, hmidi->id); - } - if (n_pending) { - snd_rawmidi_receive (hmidi->input, buf, n_pending); - } + for (i = 0; i < n_pending; ++i) + buf[i] = snd_hdspm_midi_read_byte (hmidi->hdspm, + hmidi->id); + if (n_pending) + snd_rawmidi_receive (hmidi->input, buf, + n_pending); } else { /* flush the MIDI input FIFO */ - while (n_pending--) { - snd_hdspm_midi_read_byte (hmidi->hdspm, hmidi->id); - } + while (n_pending--) + snd_hdspm_midi_read_byte (hmidi->hdspm, + hmidi->id); } } hmidi->pending = 0; - if (hmidi->id) { + if (hmidi->id) hmidi->hdspm->control_register |= HDSPM_Midi1InterruptEnable; - } else { + else hmidi->hdspm->control_register |= HDSPM_Midi0InterruptEnable; - } - hdspm_write(hmidi->hdspm, HDSPM_controlRegister, hmidi->hdspm->control_register); + hdspm_write(hmidi->hdspm, HDSPM_controlRegister, + hmidi->hdspm->control_register); spin_unlock_irqrestore (&hmidi->lock, flags); return snd_hdspm_midi_output_write (hmidi); } -static void snd_hdspm_midi_input_trigger(struct snd_rawmidi_substream *substream, int up) +static void +snd_hdspm_midi_input_trigger(struct snd_rawmidi_substream *substream, int up) { struct hdspm *hdspm; struct hdspm_midi *hmidi; unsigned long flags; u32 ie; - hmidi = (struct hdspm_midi *) substream->rmidi->private_data; + hmidi = substream->rmidi->private_data; hdspm = hmidi->hdspm; - ie = hmidi->id ? HDSPM_Midi1InterruptEnable : HDSPM_Midi0InterruptEnable; + ie = hmidi->id ? + HDSPM_Midi1InterruptEnable : HDSPM_Midi0InterruptEnable; spin_lock_irqsave (&hdspm->lock, flags); if (up) { if (!(hdspm->control_register & ie)) { @@ -1138,12 +1184,13 @@ static void snd_hdspm_midi_output_timer(unsigned long data) spin_unlock_irqrestore (&hmidi->lock, flags); } -static void snd_hdspm_midi_output_trigger(struct snd_rawmidi_substream *substream, int up) +static void +snd_hdspm_midi_output_trigger(struct snd_rawmidi_substream *substream, int up) { struct hdspm_midi *hmidi; unsigned long flags; - hmidi = (struct hdspm_midi *) substream->rmidi->private_data; + hmidi = substream->rmidi->private_data; spin_lock_irqsave (&hmidi->lock, flags); if (up) { if (!hmidi->istimer) { @@ -1155,9 +1202,8 @@ static void snd_hdspm_midi_output_trigger(struct snd_rawmidi_substream *substrea hmidi->istimer++; } } else { - if (hmidi->istimer && --hmidi->istimer <= 0) { + if (hmidi->istimer && --hmidi->istimer <= 0) del_timer (&hmidi->timer); - } } spin_unlock_irqrestore (&hmidi->lock, flags); if (up) @@ -1168,7 +1214,7 @@ static int snd_hdspm_midi_input_open(struct snd_rawmidi_substream *substream) { struct hdspm_midi *hmidi; - hmidi = (struct hdspm_midi *) substream->rmidi->private_data; + hmidi = substream->rmidi->private_data; spin_lock_irq (&hmidi->lock); snd_hdspm_flush_midi_input (hmidi->hdspm, hmidi->id); hmidi->input = substream; @@ -1181,7 +1227,7 @@ static int snd_hdspm_midi_output_open(struct snd_rawmidi_substream *substream) { struct hdspm_midi *hmidi; - hmidi = (struct hdspm_midi *) substream->rmidi->private_data; + hmidi = substream->rmidi->private_data; spin_lock_irq (&hmidi->lock); hmidi->output = substream; spin_unlock_irq (&hmidi->lock); @@ -1195,7 +1241,7 @@ static int snd_hdspm_midi_input_close(struct snd_rawmidi_substream *substream) snd_hdspm_midi_input_trigger (substream, 0); - hmidi = (struct hdspm_midi *) substream->rmidi->private_data; + hmidi = substream->rmidi->private_data; spin_lock_irq (&hmidi->lock); hmidi->input = NULL; spin_unlock_irq (&hmidi->lock); @@ -1209,7 +1255,7 @@ static int snd_hdspm_midi_output_close(struct snd_rawmidi_substream *substream) snd_hdspm_midi_output_trigger (substream, 0); - hmidi = (struct hdspm_midi *) substream->rmidi->private_data; + hmidi = substream->rmidi->private_data; spin_lock_irq (&hmidi->lock); hmidi->output = NULL; spin_unlock_irq (&hmidi->lock); @@ -1231,29 +1277,28 @@ static struct snd_rawmidi_ops snd_hdspm_midi_input = .trigger = snd_hdspm_midi_input_trigger, }; -static int __devinit snd_hdspm_create_midi (struct snd_card *card, struct hdspm *hdspm, int id) +static int __devinit snd_hdspm_create_midi (struct snd_card *card, + struct hdspm *hdspm, int id) { int err; char buf[32]; hdspm->midi[id].id = id; - hdspm->midi[id].rmidi = NULL; - hdspm->midi[id].input = NULL; - hdspm->midi[id].output = NULL; hdspm->midi[id].hdspm = hdspm; - hdspm->midi[id].istimer = 0; - hdspm->midi[id].pending = 0; spin_lock_init (&hdspm->midi[id].lock); sprintf (buf, "%s MIDI %d", card->shortname, id+1); - if ((err = snd_rawmidi_new (card, buf, id, 1, 1, &hdspm->midi[id].rmidi)) < 0) + err = snd_rawmidi_new (card, buf, id, 1, 1, &hdspm->midi[id].rmidi); + if (err < 0) return err; sprintf (hdspm->midi[id].rmidi->name, "%s MIDI %d", card->id, id+1); hdspm->midi[id].rmidi->private_data = &hdspm->midi[id]; - snd_rawmidi_set_ops (hdspm->midi[id].rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_hdspm_midi_output); - snd_rawmidi_set_ops (hdspm->midi[id].rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_hdspm_midi_input); + snd_rawmidi_set_ops(hdspm->midi[id].rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, + &snd_hdspm_midi_output); + snd_rawmidi_set_ops(hdspm->midi[id].rmidi, SNDRV_RAWMIDI_STREAM_INPUT, + &snd_hdspm_midi_input); hdspm->midi[id].rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | @@ -1558,8 +1603,8 @@ static int snd_hdspm_put_clock_source(struct snd_kcontrol *kcontrol, val = ucontrol->value.enumerated.item[0]; if (val < 0) val = 0; - if (val > 6) - val = 6; + if (val > 9) + val = 9; spin_lock_irq(&hdspm->lock); if (val != hdspm_clock_source(hdspm)) change = (hdspm_set_clock_source(hdspm, val) == 0) ? 1 : 0; @@ -1637,7 +1682,8 @@ static int hdspm_set_pref_sync_ref(struct hdspm * hdspm, int pref) hdspm->control_register |= HDSPM_SyncRef2+HDSPM_SyncRef1; break; case 7: - hdspm->control_register |= HDSPM_SyncRef2+HDSPM_SyncRef1+HDSPM_SyncRef0; + hdspm->control_register |= + HDSPM_SyncRef2+HDSPM_SyncRef1+HDSPM_SyncRef0; break; case 8: hdspm->control_register |= HDSPM_SyncRef3; @@ -1675,7 +1721,8 @@ static int snd_hdspm_info_pref_sync_ref(struct snd_kcontrol *kcontrol, uinfo->value.enumerated.items = 9; - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + if (uinfo->value.enumerated.item >= + uinfo->value.enumerated.items) uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; strcpy(uinfo->value.enumerated.name, @@ -1688,7 +1735,8 @@ static int snd_hdspm_info_pref_sync_ref(struct snd_kcontrol *kcontrol, uinfo->value.enumerated.items = 2; - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + if (uinfo->value.enumerated.item >= + uinfo->value.enumerated.items) uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; strcpy(uinfo->value.enumerated.name, @@ -1740,7 +1788,8 @@ static int hdspm_autosync_ref(struct hdspm * hdspm) { if (hdspm->is_aes32) { unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister); - unsigned int syncref = (status >> HDSPM_AES32_syncref_bit) & 0xF; + unsigned int syncref = (status >> HDSPM_AES32_syncref_bit) & + 0xF; if (syncref == 0) return HDSPM_AES32_AUTOSYNC_FROM_WORD; if (syncref <= 8) @@ -1777,20 +1826,20 @@ static int snd_hdspm_info_autosync_ref(struct snd_kcontrol *kcontrol, uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; uinfo->value.enumerated.items = 10; - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + if (uinfo->value.enumerated.item >= + uinfo->value.enumerated.items) uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - } - else - { + } else { static char *texts[] = { "WordClock", "MADI", "None" }; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; uinfo->value.enumerated.items = 3; - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + if (uinfo->value.enumerated.item >= + uinfo->value.enumerated.items) uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; strcpy(uinfo->value.enumerated.name, @@ -1804,7 +1853,7 @@ static int snd_hdspm_get_autosync_ref(struct snd_kcontrol *kcontrol, { struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); - ucontrol->value.enumerated.item[0] = hdspm_pref_sync_ref(hdspm); + ucontrol->value.enumerated.item[0] = hdspm_autosync_ref(hdspm); return 0; } @@ -1834,15 +1883,7 @@ static int hdspm_set_line_output(struct hdspm * hdspm, int out) return 0; } -static int snd_hdspm_info_line_out(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_hdspm_info_line_out snd_ctl_boolean_mono_info static int snd_hdspm_get_line_out(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1897,15 +1938,7 @@ static int hdspm_set_tx_64(struct hdspm * hdspm, int out) return 0; } -static int snd_hdspm_info_tx_64(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_hdspm_info_tx_64 snd_ctl_boolean_mono_info static int snd_hdspm_get_tx_64(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1960,15 +1993,7 @@ static int hdspm_set_c_tms(struct hdspm * hdspm, int out) return 0; } -static int snd_hdspm_info_c_tms(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_hdspm_info_c_tms snd_ctl_boolean_mono_info static int snd_hdspm_get_c_tms(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -2023,15 +2048,7 @@ static int hdspm_set_safe_mode(struct hdspm * hdspm, int out) return 0; } -static int snd_hdspm_info_safe_mode(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_hdspm_info_safe_mode snd_ctl_boolean_mono_info static int snd_hdspm_get_safe_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -2086,15 +2103,7 @@ static int hdspm_set_emphasis(struct hdspm * hdspm, int emp) return 0; } -static int snd_hdspm_info_emphasis(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_hdspm_info_emphasis snd_ctl_boolean_mono_info static int snd_hdspm_get_emphasis(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -2149,15 +2158,7 @@ static int hdspm_set_dolby(struct hdspm * hdspm, int dol) return 0; } -static int snd_hdspm_info_dolby(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_hdspm_info_dolby snd_ctl_boolean_mono_info static int snd_hdspm_get_dolby(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -2212,15 +2213,7 @@ static int hdspm_set_professional(struct hdspm * hdspm, int dol) return 0; } -static int snd_hdspm_info_professional(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_hdspm_info_professional snd_ctl_boolean_mono_info static int snd_hdspm_get_professional(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -2472,7 +2465,7 @@ static int snd_hdspm_put_qs_wire(struct snd_kcontrol *kcontrol, if (val > 2) val = 2; spin_lock_irq(&hdspm->lock); - change = (int) val != hdspm_qs_wire(hdspm); + change = val != hdspm_qs_wire(hdspm); hdspm_set_qs_wire(hdspm, val); spin_unlock_irq(&hdspm->lock); return change; @@ -2573,8 +2566,8 @@ static int snd_hdspm_put_mixer(struct snd_kcontrol *kcontrol, source - HDSPM_MAX_CHANNELS); else - change = - gain != hdspm_read_in_gain(hdspm, destination, source); + change = gain != hdspm_read_in_gain(hdspm, destination, + source); if (change) { if (source >= HDSPM_MAX_CHANNELS) @@ -2627,7 +2620,8 @@ static int snd_hdspm_get_playback_mixer(struct snd_kcontrol *kcontrol, snd_assert(channel >= 0 || channel < HDSPM_MAX_CHANNELS, return -EINVAL); - if ((mapped_channel = hdspm->channel_map[channel]) < 0) + mapped_channel = hdspm->channel_map[channel]; + if (mapped_channel < 0) return -EINVAL; spin_lock_irq(&hdspm->lock); @@ -2635,10 +2629,12 @@ static int snd_hdspm_get_playback_mixer(struct snd_kcontrol *kcontrol, hdspm_read_pb_gain(hdspm, mapped_channel, mapped_channel); spin_unlock_irq(&hdspm->lock); - /* snd_printdd("get pb mixer index %d, channel %d, mapped_channel %d, value %d\n", - ucontrol->id.index, channel, mapped_channel, ucontrol->value.integer.value[0]); - */ - + /* + snd_printdd("get pb mixer index %d, channel %d, mapped_channel %d, " + "value %d\n", + ucontrol->id.index, channel, mapped_channel, + ucontrol->value.integer.value[0]); + */ return 0; } @@ -2659,7 +2655,8 @@ static int snd_hdspm_put_playback_mixer(struct snd_kcontrol *kcontrol, snd_assert(channel >= 0 || channel < HDSPM_MAX_CHANNELS, return -EINVAL); - if ((mapped_channel = hdspm->channel_map[channel]) < 0) + mapped_channel = hdspm->channel_map[channel]; + if (mapped_channel < 0) return -EINVAL; gain = ucontrol->value.integer.value[0]; @@ -2909,28 +2906,26 @@ static int snd_hdspm_create_controls(struct snd_card *card, struct hdspm * hdspm } /* Channel playback mixer as default control -Note: the whole matrix would be 128*HDSPM_MIXER_CHANNELS Faders, thats too big for any alsamixer -they are accesible via special IOCTL on hwdep -and the mixer 2dimensional mixer control */ + Note: the whole matrix would be 128*HDSPM_MIXER_CHANNELS Faders, + thats too * big for any alsamixer they are accesible via special + IOCTL on hwdep and the mixer 2dimensional mixer control + */ snd_hdspm_playback_mixer.name = "Chn"; limit = HDSPM_MAX_CHANNELS; - /* The index values are one greater than the channel ID so that alsamixer - will display them correctly. We want to use the index for fast lookup - of the relevant channel, but if we use it at all, most ALSA software - does the wrong thing with it ... + /* The index values are one greater than the channel ID so that + * alsamixer will display them correctly. We want to use the index + * for fast lookup of the relevant channel, but if we use it at all, + * most ALSA software does the wrong thing with it ... */ for (idx = 0; idx < limit; ++idx) { snd_hdspm_playback_mixer.index = idx + 1; - if ((err = snd_ctl_add(card, - kctl = - snd_ctl_new1 - (&snd_hdspm_playback_mixer, - hdspm)))) { + kctl = snd_ctl_new1(&snd_hdspm_playback_mixer, hdspm); + err = snd_ctl_add(card, kctl); + if (err < 0) return err; - } hdspm->playback_mixer_ctls[idx] = kctl; } @@ -2945,7 +2940,7 @@ static void snd_hdspm_proc_read_madi(struct snd_info_entry * entry, struct snd_info_buffer *buffer) { - struct hdspm *hdspm = (struct hdspm *) entry->private_data; + struct hdspm *hdspm = entry->private_data; unsigned int status; unsigned int status2; char *pref_sync_ref; @@ -2978,14 +2973,14 @@ snd_hdspm_proc_read_madi(struct snd_info_entry * entry, (status & HDSPM_midi1IRQPending) ? 1 : 0, hdspm->irq_count); snd_iprintf(buffer, - "HW pointer: id = %d, rawptr = %d (%d->%d) estimated= %ld (bytes)\n", + "HW pointer: id = %d, rawptr = %d (%d->%d) " + "estimated= %ld (bytes)\n", ((status & HDSPM_BufferID) ? 1 : 0), (status & HDSPM_BufferPositionMask), - (status & HDSPM_BufferPositionMask) % (2 * - (int)hdspm-> - period_bytes), - ((status & HDSPM_BufferPositionMask) - - 64) % (2 * (int)hdspm->period_bytes), + (status & HDSPM_BufferPositionMask) % + (2 * (int)hdspm->period_bytes), + ((status & HDSPM_BufferPositionMask) - 64) % + (2 * (int)hdspm->period_bytes), (long) hdspm_hw_pointer(hdspm) * 4); snd_iprintf(buffer, @@ -2995,24 +2990,22 @@ snd_hdspm_proc_read_madi(struct snd_info_entry * entry, hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xFF, hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xFF); snd_iprintf(buffer, - "Register: ctrl1=0x%x, ctrl2=0x%x, status1=0x%x, status2=0x%x\n", + "Register: ctrl1=0x%x, ctrl2=0x%x, status1=0x%x, " + "status2=0x%x\n", hdspm->control_register, hdspm->control2_register, status, status2); snd_iprintf(buffer, "--- Settings ---\n"); - x = 1 << (6 + - hdspm_decode_latency(hdspm-> - control_register & - HDSPM_LatencyMask)); + x = 1 << (6 + hdspm_decode_latency(hdspm->control_register & + HDSPM_LatencyMask)); snd_iprintf(buffer, "Size (Latency): %d samples (2 periods of %lu bytes)\n", x, (unsigned long) hdspm->period_bytes); snd_iprintf(buffer, "Line out: %s, Precise Pointer: %s\n", - (hdspm-> - control_register & HDSPM_LineOut) ? "on " : "off", + (hdspm->control_register & HDSPM_LineOut) ? "on " : "off", (hdspm->precise_ptr) ? "on" : "off"); switch (hdspm->control_register & HDSPM_InputMask) { @@ -3040,7 +3033,8 @@ snd_hdspm_proc_read_madi(struct snd_info_entry * entry, syncref); snd_iprintf(buffer, - "ClearTrackMarker = %s, Transmit in %s Channel Mode, Auto Input %s\n", + "ClearTrackMarker = %s, Transmit in %s Channel Mode, " + "Auto Input %s\n", (hdspm-> control_register & HDSPM_clr_tms) ? "on" : "off", (hdspm-> @@ -3141,7 +3135,7 @@ static void snd_hdspm_proc_read_aes32(struct snd_info_entry * entry, struct snd_info_buffer *buffer) { - struct hdspm *hdspm = (struct hdspm *) entry->private_data; + struct hdspm *hdspm = entry->private_data; unsigned int status; unsigned int status2; unsigned int timecode; @@ -3171,14 +3165,14 @@ snd_hdspm_proc_read_aes32(struct snd_info_entry * entry, (status & HDSPM_midi1IRQPending) ? 1 : 0, hdspm->irq_count); snd_iprintf(buffer, - "HW pointer: id = %d, rawptr = %d (%d->%d) estimated= %ld (bytes)\n", + "HW pointer: id = %d, rawptr = %d (%d->%d) " + "estimated= %ld (bytes)\n", ((status & HDSPM_BufferID) ? 1 : 0), (status & HDSPM_BufferPositionMask), - (status & HDSPM_BufferPositionMask) % (2 * - (int)hdspm-> - period_bytes), - ((status & HDSPM_BufferPositionMask) - - 64) % (2 * (int)hdspm->period_bytes), + (status & HDSPM_BufferPositionMask) % + (2 * (int)hdspm->period_bytes), + ((status & HDSPM_BufferPositionMask) - 64) % + (2 * (int)hdspm->period_bytes), (long) hdspm_hw_pointer(hdspm) * 4); snd_iprintf(buffer, @@ -3188,16 +3182,15 @@ snd_hdspm_proc_read_aes32(struct snd_info_entry * entry, hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xFF, hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xFF); snd_iprintf(buffer, - "Register: ctrl1=0x%x, status1=0x%x, status2=0x%x, timecode=0x%x\n", + "Register: ctrl1=0x%x, status1=0x%x, status2=0x%x, " + "timecode=0x%x\n", hdspm->control_register, status, status2, timecode); snd_iprintf(buffer, "--- Settings ---\n"); - x = 1 << (6 + - hdspm_decode_latency(hdspm-> - control_register & - HDSPM_LatencyMask)); + x = 1 << (6 + hdspm_decode_latency(hdspm->control_register & + HDSPM_LatencyMask)); snd_iprintf(buffer, "Size (Latency): %d samples (2 periods of %lu bytes)\n", @@ -3280,14 +3273,15 @@ snd_hdspm_proc_read_aes32(struct snd_info_entry * entry, snd_iprintf(buffer, "--- Status:\n"); snd_iprintf(buffer, "Word: %s Frequency: %d\n", - (status & HDSPM_AES32_wcLock)? "Sync " : "No Lock", - HDSPM_bit2freq((status >> HDSPM_AES32_wcFreq_bit) & 0xF)); + (status & HDSPM_AES32_wcLock)? "Sync " : "No Lock", + HDSPM_bit2freq((status >> HDSPM_AES32_wcFreq_bit) & 0xF)); for (x = 0; x < 8; x++) { snd_iprintf(buffer, "AES%d: %s Frequency: %d\n", - x+1, - (status2 & (HDSPM_LockAES >> x))? "Sync ": "No Lock", - HDSPM_bit2freq((timecode >> (4*x)) & 0xF)); + x+1, + (status2 & (HDSPM_LockAES >> x)) ? + "Sync ": "No Lock", + HDSPM_bit2freq((timecode >> (4*x)) & 0xF)); } switch (hdspm_autosync_ref(hdspm)) { @@ -3313,12 +3307,11 @@ static void snd_hdspm_proc_read_debug(struct snd_info_entry * entry, struct snd_info_buffer *buffer) { - struct hdspm *hdspm = (struct hdspm *)entry->private_data; + struct hdspm *hdspm = entry->private_data; int j,i; - for (i = 0; i < 256 /* 1024*64 */; i += j) - { + for (i = 0; i < 256 /* 1024*64 */; i += j) { snd_iprintf(buffer, "0x%08X: ", i); for (j = 0; j < 16; j += 4) snd_iprintf(buffer, "%08X ", hdspm_read(hdspm, i + j)); @@ -3361,14 +3354,20 @@ static int snd_hdspm_set_defaults(struct hdspm * hdspm) /* set defaults: */ if (hdspm->is_aes32) - hdspm->control_register = HDSPM_ClockModeMaster | /* Master Cloack Mode on */ - hdspm_encode_latency(7) | /* latency maximum = 8192 samples */ + hdspm->control_register = + HDSPM_ClockModeMaster | /* Master Cloack Mode on */ + hdspm_encode_latency(7) | /* latency maximum = + * 8192 samples + */ HDSPM_SyncRef0 | /* AES1 is syncclock */ HDSPM_LineOut | /* Analog output in */ HDSPM_Professional; /* Professional mode */ else - hdspm->control_register = HDSPM_ClockModeMaster | /* Master Cloack Mode on */ - hdspm_encode_latency(7) | /* latency maximum = 8192 samples */ + hdspm->control_register = + HDSPM_ClockModeMaster | /* Master Cloack Mode on */ + hdspm_encode_latency(7) | /* latency maximum = + * 8192 samples + */ HDSPM_InputCoaxial | /* Input Coax not Optical */ HDSPM_SyncRef_MADI | /* Madi is syncclock */ HDSPM_LineOut | /* Analog output in */ @@ -3399,7 +3398,8 @@ static int snd_hdspm_set_defaults(struct hdspm * hdspm) if (line_outs_monitor[hdspm->dev]) { - snd_printk(KERN_INFO "HDSPM: sending all playback streams to line outs.\n"); + snd_printk(KERN_INFO "HDSPM: " + "sending all playback streams to line outs.\n"); for (i = 0; i < HDSPM_MIXER_CHANNELS; i++) { if (hdspm_write_pb_gain(hdspm, i, i, UNITY_GAIN)) @@ -3448,20 +3448,16 @@ static irqreturn_t snd_hdspm_interrupt(int irq, void *dev_id) if (audio) { if (hdspm->capture_substream) - snd_pcm_period_elapsed(hdspm->pcm-> - streams - [SNDRV_PCM_STREAM_CAPTURE]. - substream); + snd_pcm_period_elapsed(hdspm->capture_substream); if (hdspm->playback_substream) - snd_pcm_period_elapsed(hdspm->pcm-> - streams - [SNDRV_PCM_STREAM_PLAYBACK]. - substream); + snd_pcm_period_elapsed(hdspm->playback_substream); } if (midi0 && midi0status) { - /* we disable interrupts for this input until processing is done */ + /* we disable interrupts for this input until processing + * is done + */ hdspm->control_register &= ~HDSPM_Midi0InterruptEnable; hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); @@ -3469,7 +3465,9 @@ static irqreturn_t snd_hdspm_interrupt(int irq, void *dev_id) schedule = 1; } if (midi1 && midi1status) { - /* we disable interrupts for this input until processing is done */ + /* we disable interrupts for this input until processing + * is done + */ hdspm->control_register &= ~HDSPM_Midi1InterruptEnable; hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); @@ -3501,16 +3499,16 @@ static char *hdspm_channel_buffer_location(struct hdspm * hdspm, snd_assert(channel >= 0 || channel < HDSPM_MAX_CHANNELS, return NULL); - if ((mapped_channel = hdspm->channel_map[channel]) < 0) + mapped_channel = hdspm->channel_map[channel]; + if (mapped_channel < 0) return NULL; - if (stream == SNDRV_PCM_STREAM_CAPTURE) { + if (stream == SNDRV_PCM_STREAM_CAPTURE) return hdspm->capture_buffer + mapped_channel * HDSPM_CHANNEL_BUFFER_BYTES; - } else { + else return hdspm->playback_buffer + mapped_channel * HDSPM_CHANNEL_BUFFER_BYTES; - } } @@ -3525,9 +3523,9 @@ static int snd_hdspm_playback_copy(struct snd_pcm_substream *substream, snd_assert(pos + count <= HDSPM_CHANNEL_BUFFER_BYTES / 4, return -EINVAL); - channel_buf = hdspm_channel_buffer_location(hdspm, - substream->pstr-> - stream, channel); + channel_buf = + hdspm_channel_buffer_location(hdspm, substream->pstr->stream, + channel); snd_assert(channel_buf != NULL, return -EIO); @@ -3544,9 +3542,9 @@ static int snd_hdspm_capture_copy(struct snd_pcm_substream *substream, snd_assert(pos + count <= HDSPM_CHANNEL_BUFFER_BYTES / 4, return -EINVAL); - channel_buf = hdspm_channel_buffer_location(hdspm, - substream->pstr-> - stream, channel); + channel_buf = + hdspm_channel_buffer_location(hdspm, substream->pstr->stream, + channel); snd_assert(channel_buf != NULL, return -EIO); return copy_to_user(dst, channel_buf + pos * 4, count * 4); } @@ -3559,8 +3557,8 @@ static int snd_hdspm_hw_silence(struct snd_pcm_substream *substream, char *channel_buf; channel_buf = - hdspm_channel_buffer_location(hdspm, substream->pstr->stream, - channel); + hdspm_channel_buffer_location(hdspm, substream->pstr->stream, + channel); snd_assert(channel_buf != NULL, return -EIO); memset(channel_buf + pos * 4, 0, count * 4); return 0; @@ -3616,7 +3614,7 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream, other_pid = hdspm->playback_pid; } - if ((other_pid > 0) && (this_pid != other_pid)) { + if (other_pid > 0 && this_pid != other_pid) { /* The other stream is open, and not by the same task as this one. Make sure that the parameters @@ -3633,7 +3631,7 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream, if (params_period_size(params) != hdspm->period_bytes / 4) { spin_unlock_irq(&hdspm->lock); _snd_pcm_hw_param_setempty(params, - SNDRV_PCM_HW_PARAM_PERIOD_SIZE); + SNDRV_PCM_HW_PARAM_PERIOD_SIZE); return -EBUSY; } @@ -3644,7 +3642,8 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream, /* how to make sure that the rate matches an externally-set one ? */ spin_lock_irq(&hdspm->lock); - if ((err = hdspm_set_rate(hdspm, params_rate(params), 0)) < 0) { + err = hdspm_set_rate(hdspm, params_rate(params), 0); + if (err < 0) { spin_unlock_irq(&hdspm->lock); _snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_RATE); @@ -3652,16 +3651,17 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream, } spin_unlock_irq(&hdspm->lock); - if ((err = - hdspm_set_interrupt_interval(hdspm, - params_period_size(params))) < - 0) { + err = hdspm_set_interrupt_interval(hdspm, + params_period_size(params)); + if (err < 0) { _snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE); return err; } - /* Memory allocation, takashi's method, dont know if we should spinlock */ + /* Memory allocation, takashi's method, dont know if we should + * spinlock + */ /* malloc all buffer even if not enabled to get sure */ /* Update for MADI rev 204: we need to allocate for all channels, * otherwise it doesn't work at 96kHz */ @@ -3746,7 +3746,8 @@ static int snd_hdspm_channel_info(struct snd_pcm_substream *substream, snd_assert(info->channel < HDSPM_MAX_CHANNELS, return -EINVAL); - if ((mapped_channel = hdspm->channel_map[info->channel]) < 0) + mapped_channel = hdspm->channel_map[info->channel]; + if (mapped_channel < 0) return -EINVAL; info->offset = mapped_channel * HDSPM_CHANNEL_BUFFER_BYTES; @@ -3760,15 +3761,13 @@ static int snd_hdspm_ioctl(struct snd_pcm_substream *substream, { switch (cmd) { case SNDRV_PCM_IOCTL1_RESET: - { - return snd_hdspm_reset(substream); - } + return snd_hdspm_reset(substream); case SNDRV_PCM_IOCTL1_CHANNEL_INFO: - { - struct snd_pcm_channel_info *info = arg; - return snd_hdspm_channel_info(substream, info); - } + { + struct snd_pcm_channel_info *info = arg; + return snd_hdspm_channel_info(substream, info); + } default: break; } @@ -3979,9 +3978,12 @@ static int snd_hdspm_hw_rule_channels(struct snd_pcm_hw_params *params, } -static unsigned int hdspm_aes32_sample_rates[] = { 32000, 44100, 48000, 64000, 88200, 96000, 128000, 176400, 192000 }; +static unsigned int hdspm_aes32_sample_rates[] = { + 32000, 44100, 48000, 64000, 88200, 96000, 128000, 176400, 192000 +}; -static struct snd_pcm_hw_constraint_list hdspm_hw_constraints_aes32_sample_rates = { +static struct snd_pcm_hw_constraint_list +hdspm_hw_constraints_aes32_sample_rates = { .count = ARRAY_SIZE(hdspm_aes32_sample_rates), .list = hdspm_aes32_sample_rates, .mask = 0 @@ -4107,7 +4109,7 @@ static int snd_hdspm_hwdep_dummy_op(struct snd_hwdep * hw, struct file *file) static int snd_hdspm_hwdep_ioctl(struct snd_hwdep * hw, struct file *file, unsigned int cmd, unsigned long arg) { - struct hdspm *hdspm = (struct hdspm *) hw->private_data; + struct hdspm *hdspm = hw->private_data; struct hdspm_mixer_ioctl mixer; struct hdspm_config_info info; struct hdspm_version hdspm_version; @@ -4115,11 +4117,12 @@ static int snd_hdspm_hwdep_ioctl(struct snd_hwdep * hw, struct file *file, switch (cmd) { - case SNDRV_HDSPM_IOCTL_GET_PEAK_RMS: if (copy_from_user(&rms, (void __user *)arg, sizeof(rms))) return -EFAULT; - /* maybe there is a chance to memorymap in future so dont touch just copy */ + /* maybe there is a chance to memorymap in future + * so dont touch just copy + */ if(copy_to_user_fromio((void __user *)rms.peak, hdspm->iobase+HDSPM_MADI_peakrmsbase, sizeof(struct hdspm_peak_rms)) != 0 ) @@ -4131,21 +4134,16 @@ static int snd_hdspm_hwdep_ioctl(struct snd_hwdep * hw, struct file *file, case SNDRV_HDSPM_IOCTL_GET_CONFIG_INFO: spin_lock_irq(&hdspm->lock); - info.pref_sync_ref = - (unsigned char) hdspm_pref_sync_ref(hdspm); - info.wordclock_sync_check = - (unsigned char) hdspm_wc_sync_check(hdspm); + info.pref_sync_ref = hdspm_pref_sync_ref(hdspm); + info.wordclock_sync_check = hdspm_wc_sync_check(hdspm); info.system_sample_rate = hdspm->system_sample_rate; info.autosync_sample_rate = hdspm_external_sample_rate(hdspm); - info.system_clock_mode = - (unsigned char) hdspm_system_clock_mode(hdspm); - info.clock_source = - (unsigned char) hdspm_clock_source(hdspm); - info.autosync_ref = - (unsigned char) hdspm_autosync_ref(hdspm); - info.line_out = (unsigned char) hdspm_line_out(hdspm); + info.system_clock_mode = hdspm_system_clock_mode(hdspm); + info.clock_source = hdspm_clock_source(hdspm); + info.autosync_ref = hdspm_autosync_ref(hdspm); + info.line_out = hdspm_line_out(hdspm); info.passthru = 0; spin_unlock_irq(&hdspm->lock); if (copy_to_user((void __user *) arg, &info, sizeof(info))) @@ -4162,8 +4160,8 @@ static int snd_hdspm_hwdep_ioctl(struct snd_hwdep * hw, struct file *file, case SNDRV_HDSPM_IOCTL_GET_MIXER: if (copy_from_user(&mixer, (void __user *)arg, sizeof(mixer))) return -EFAULT; - if (copy_to_user - ((void __user *)mixer.mixer, hdspm->mixer, sizeof(struct hdspm_mixer))) + if (copy_to_user((void __user *)mixer.mixer, hdspm->mixer, + sizeof(struct hdspm_mixer))) return -EFAULT; break; @@ -4206,7 +4204,8 @@ static int __devinit snd_hdspm_create_hwdep(struct snd_card *card, struct snd_hwdep *hw; int err; - if ((err = snd_hwdep_new(card, "HDSPM hwdep", 0, &hw)) < 0) + err = snd_hwdep_new(card, "HDSPM hwdep", 0, &hw); + if (err < 0) return err; hdspm->hwdep = hw; @@ -4232,15 +4231,15 @@ static int __devinit snd_hdspm_preallocate_memory(struct hdspm * hdspm) pcm = hdspm->pcm; -/* wanted = HDSPM_DMA_AREA_BYTES + 4096;*/ /* dont know why, but it works */ wanted = HDSPM_DMA_AREA_BYTES; - if ((err = + err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, snd_dma_pci_data(hdspm->pci), wanted, - wanted)) < 0) { + wanted); + if (err < 0) { snd_printdd("Could not preallocate %zd Bytes\n", wanted); return err; @@ -4256,8 +4255,7 @@ static void hdspm_set_sgbuf(struct hdspm * hdspm, struct snd_sg_buf *sgbuf, int i; for (i = 0; i < (channels * 16); i++) hdspm_write(hdspm, reg + 4 * i, - snd_pcm_sgbuf_get_addr(sgbuf, - (size_t) 4096 * i)); + snd_pcm_sgbuf_get_addr(sgbuf, (size_t) 4096 * i)); } /* ------------- ALSA Devices ---------------------------- */ @@ -4267,7 +4265,8 @@ static int __devinit snd_hdspm_create_pcm(struct snd_card *card, struct snd_pcm *pcm; int err; - if ((err = snd_pcm_new(card, hdspm->card_name, 0, 1, 1, &pcm)) < 0) + err = snd_pcm_new(card, hdspm->card_name, 0, 1, 1, &pcm); + if (err < 0) return err; hdspm->pcm = pcm; @@ -4281,7 +4280,8 @@ static int __devinit snd_hdspm_create_pcm(struct snd_card *card, pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX; - if ((err = snd_hdspm_preallocate_memory(hdspm)) < 0) + err = snd_hdspm_preallocate_memory(hdspm); + if (err < 0) return err; return 0; @@ -4299,19 +4299,24 @@ static int __devinit snd_hdspm_create_alsa_devices(struct snd_card *card, int err; snd_printdd("Create card...\n"); - if ((err = snd_hdspm_create_pcm(card, hdspm)) < 0) + err = snd_hdspm_create_pcm(card, hdspm); + if (err < 0) return err; - if ((err = snd_hdspm_create_midi(card, hdspm, 0)) < 0) + err = snd_hdspm_create_midi(card, hdspm, 0); + if (err < 0) return err; - if ((err = snd_hdspm_create_midi(card, hdspm, 1)) < 0) + err = snd_hdspm_create_midi(card, hdspm, 1); + if (err < 0) return err; - if ((err = snd_hdspm_create_controls(card, hdspm)) < 0) + err = snd_hdspm_create_controls(card, hdspm); + if (err < 0) return err; - if ((err = snd_hdspm_create_hwdep(card, hdspm)) < 0) + err = snd_hdspm_create_hwdep(card, hdspm); + if (err < 0) return err; snd_printdd("proc init...\n"); @@ -4326,7 +4331,8 @@ static int __devinit snd_hdspm_create_alsa_devices(struct snd_card *card, hdspm->playback_substream = NULL; snd_printdd("Set defaults...\n"); - if ((err = snd_hdspm_set_defaults(hdspm)) < 0) + err = snd_hdspm_set_defaults(hdspm); + if (err < 0) return err; snd_printdd("Update mixer controls...\n"); @@ -4334,7 +4340,8 @@ static int __devinit snd_hdspm_create_alsa_devices(struct snd_card *card, snd_printdd("Initializeing complete ???\n"); - if ((err = snd_card_register(card)) < 0) { + err = snd_card_register(card); + if (err < 0) { snd_printk(KERN_ERR "HDSPM: error registering card\n"); return err; } @@ -4344,36 +4351,18 @@ static int __devinit snd_hdspm_create_alsa_devices(struct snd_card *card, return 0; } -static int __devinit snd_hdspm_create(struct snd_card *card, struct hdspm * hdspm, +static int __devinit snd_hdspm_create(struct snd_card *card, + struct hdspm *hdspm, int precise_ptr, int enable_monitor) { struct pci_dev *pci = hdspm->pci; int err; - int i; - unsigned long io_extent; hdspm->irq = -1; - hdspm->irq_count = 0; - - hdspm->midi[0].rmidi = NULL; - hdspm->midi[1].rmidi = NULL; - hdspm->midi[0].input = NULL; - hdspm->midi[1].input = NULL; - hdspm->midi[0].output = NULL; - hdspm->midi[1].output = NULL; + spin_lock_init(&hdspm->midi[0].lock); spin_lock_init(&hdspm->midi[1].lock); - hdspm->iobase = NULL; - hdspm->control_register = 0; - hdspm->control2_register = 0; - - hdspm->playback_buffer = NULL; - hdspm->capture_buffer = NULL; - - for (i = 0; i < HDSPM_MAX_CHANNELS; ++i) - hdspm->playback_mixer_ctls[i] = NULL; - hdspm->mixer = NULL; hdspm->card = card; @@ -4396,12 +4385,14 @@ static int __devinit snd_hdspm_create(struct snd_card *card, struct hdspm * hdsp hdspm->card_name = "RME HDSPM MADI"; } - if ((err = pci_enable_device(pci)) < 0) + err = pci_enable_device(pci); + if (err < 0) return err; pci_set_master(hdspm->pci); - if ((err = pci_request_regions(pci, "hdspm")) < 0) + err = pci_request_regions(pci, "hdspm"); + if (err < 0) return err; hdspm->port = pci_resource_start(pci, 0); @@ -4411,8 +4402,10 @@ static int __devinit snd_hdspm_create(struct snd_card *card, struct hdspm * hdsp hdspm->port, hdspm->port + io_extent - 1); - if ((hdspm->iobase = ioremap_nocache(hdspm->port, io_extent)) == NULL) { - snd_printk(KERN_ERR "HDSPM: unable to remap region 0x%lx-0x%lx\n", + hdspm->iobase = ioremap_nocache(hdspm->port, io_extent); + if (!hdspm->iobase) { + snd_printk(KERN_ERR "HDSPM: " + "unable to remap region 0x%lx-0x%lx\n", hdspm->port, hdspm->port + io_extent - 1); return -EBUSY; } @@ -4435,9 +4428,10 @@ static int __devinit snd_hdspm_create(struct snd_card *card, struct hdspm * hdsp snd_printdd("kmalloc Mixer memory of %zd Bytes\n", sizeof(struct hdspm_mixer)); - if ((hdspm->mixer = kmalloc(sizeof(struct hdspm_mixer), GFP_KERNEL)) - == NULL) { - snd_printk(KERN_ERR "HDSPM: unable to kmalloc Mixer memory of %d Bytes\n", + hdspm->mixer = kzalloc(sizeof(struct hdspm_mixer), GFP_KERNEL); + if (!hdspm->mixer) { + snd_printk(KERN_ERR "HDSPM: " + "unable to kmalloc Mixer memory of %d Bytes\n", (int)sizeof(struct hdspm_mixer)); return err; } @@ -4447,7 +4441,8 @@ static int __devinit snd_hdspm_create(struct snd_card *card, struct hdspm * hdsp hdspm->qs_channels = MADI_QS_CHANNELS; snd_printdd("create alsa devices.\n"); - if ((err = snd_hdspm_create_alsa_devices(card, hdspm)) < 0) + err = snd_hdspm_create_alsa_devices(card, hdspm); + if (err < 0) return err; snd_hdspm_initialize_midi_flush(hdspm); @@ -4462,9 +4457,8 @@ static int snd_hdspm_free(struct hdspm * hdspm) /* stop th audio, and cancel all interrupts */ hdspm->control_register &= - ~(HDSPM_Start | HDSPM_AudioInterruptEnable - | HDSPM_Midi0InterruptEnable | - HDSPM_Midi1InterruptEnable); + ~(HDSPM_Start | HDSPM_AudioInterruptEnable | + HDSPM_Midi0InterruptEnable | HDSPM_Midi1InterruptEnable); hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); } @@ -4472,7 +4466,6 @@ static int snd_hdspm_free(struct hdspm * hdspm) if (hdspm->irq >= 0) free_irq(hdspm->irq, (void *) hdspm); - kfree(hdspm->mixer); if (hdspm->iobase) @@ -4487,7 +4480,7 @@ static int snd_hdspm_free(struct hdspm * hdspm) static void snd_hdspm_card_free(struct snd_card *card) { - struct hdspm *hdspm = (struct hdspm *) card->private_data; + struct hdspm *hdspm = card->private_data; if (hdspm) snd_hdspm_free(hdspm); @@ -4508,20 +4501,21 @@ static int __devinit snd_hdspm_probe(struct pci_dev *pci, return -ENOENT; } - if (!(card = snd_card_new(index[dev], id[dev], - THIS_MODULE, sizeof(struct hdspm)))) + card = snd_card_new(index[dev], id[dev], + THIS_MODULE, sizeof(struct hdspm)); + if (!card) return -ENOMEM; - hdspm = (struct hdspm *) card->private_data; + hdspm = card->private_data; card->private_free = snd_hdspm_card_free; hdspm->dev = dev; hdspm->pci = pci; snd_card_set_dev(card, &pci->dev); - if ((err = - snd_hdspm_create(card, hdspm, precise_ptr[dev], - enable_monitor[dev])) < 0) { + err = snd_hdspm_create(card, hdspm, precise_ptr[dev], + enable_monitor[dev]); + if (err < 0) { snd_card_free(card); return err; } @@ -4530,7 +4524,8 @@ static int __devinit snd_hdspm_probe(struct pci_dev *pci, sprintf(card->longname, "%s at 0x%lx, irq %d", hdspm->card_name, hdspm->port, hdspm->irq); - if ((err = snd_card_register(card)) < 0) { + err = snd_card_register(card); + if (err < 0) { snd_card_free(card); return err; } diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c index 2de27405a0b..34f96f12e5b 100644 --- a/sound/pci/rme9652/rme9652.c +++ b/sound/pci/rme9652/rme9652.c @@ -1067,14 +1067,7 @@ static int rme9652_set_spdif_output(struct snd_rme9652 *rme9652, int out) return 0; } -static int snd_rme9652_info_spdif_out(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_rme9652_info_spdif_out snd_ctl_boolean_mono_info static int snd_rme9652_get_spdif_out(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1338,14 +1331,7 @@ static int snd_rme9652_put_thru(struct snd_kcontrol *kcontrol, struct snd_ctl_el .put = snd_rme9652_put_passthru, \ .get = snd_rme9652_get_passthru } -static int snd_rme9652_info_passthru(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_rme9652_info_passthru snd_ctl_boolean_mono_info static int snd_rme9652_get_passthru(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1445,14 +1431,7 @@ static int snd_rme9652_get_adat_sync(struct snd_kcontrol *kcontrol, struct snd_c .info = snd_rme9652_info_tc_valid, \ .get = snd_rme9652_get_tc_valid } -static int snd_rme9652_info_tc_valid(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_rme9652_info_tc_valid snd_ctl_boolean_mono_info static int snd_rme9652_get_tc_valid(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c index 9f25d93cbec..44a7f5fad57 100644 --- a/sound/pci/sonicvibes.c +++ b/sound/pci/sonicvibes.c @@ -1,6 +1,6 @@ /* * Driver for S3 SonicVibes soundcard - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * * BUGS: * It looks like 86c617 rev 3 doesn't supports DDMA buffers above 16MB? @@ -42,7 +42,7 @@ #include <asm/io.h> -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("S3 SonicVibes PCI"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{S3,SonicVibes PCI}}"); diff --git a/sound/pci/trident/Makefile b/sound/pci/trident/Makefile index 65bc5b70323..65f2c218324 100644 --- a/sound/pci/trident/Makefile +++ b/sound/pci/trident/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-trident-objs := trident.o trident_main.o trident_memory.o diff --git a/sound/pci/trident/trident.c b/sound/pci/trident/trident.c index 9145f7c57fb..84884567df6 100644 --- a/sound/pci/trident/trident.c +++ b/sound/pci/trident/trident.c @@ -30,7 +30,7 @@ #include <sound/trident.h> #include <sound/initval.h> -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, <audio@tridentmicro.com>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, <audio@tridentmicro.com>"); MODULE_DESCRIPTION("Trident 4D-WaveDX/NX & SiS SI7018"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Trident,4DWave DX}," diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c index 7ca60627246..a235e034a69 100644 --- a/sound/pci/trident/trident_main.c +++ b/sound/pci/trident/trident_main.c @@ -1,5 +1,5 @@ /* - * Maintained by Jaroslav Kysela <perex@suse.cz> + * Maintained by Jaroslav Kysela <perex@perex.cz> * Originated by audio@tridentmicro.com * Fri Feb 19 15:55:28 MST 1999 * Routines for control of Trident 4DWave (DX and NX) chip @@ -2317,15 +2317,7 @@ int __devinit snd_trident_spdif_pcm(struct snd_trident * trident, Description: enable/disable S/PDIF out from ac97 mixer ---------------------------------------------------------------------------*/ -static int snd_trident_spdif_control_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_trident_spdif_control_info snd_ctl_boolean_mono_info static int snd_trident_spdif_control_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -2545,15 +2537,7 @@ static struct snd_kcontrol_new snd_trident_spdif_stream __devinitdata = Description: enable/disable rear path for ac97 ---------------------------------------------------------------------------*/ -static int snd_trident_ac97_control_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_trident_ac97_control_info snd_ctl_boolean_mono_info static int snd_trident_ac97_control_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/pci/trident/trident_memory.c b/sound/pci/trident/trident_memory.c index aff3f874131..847b8c6d5c0 100644 --- a/sound/pci/trident/trident_memory.c +++ b/sound/pci/trident/trident_memory.c @@ -1,5 +1,5 @@ /* - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * Copyright (c) by Takashi Iwai <tiwai@suse.de> * Copyright (c) by Scott McNab <sdm@fractalgraphics.com.au> * diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 6ea09df0c73..cf62d2ab8d7 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -3,7 +3,7 @@ * * VT82C686A/B/C, VT8233A/C, VT8235 * - * Copyright (c) 2000 Jaroslav Kysela <perex@suse.cz> + * Copyright (c) 2000 Jaroslav Kysela <perex@perex.cz> * Tjeerd.Mulder <Tjeerd.Mulder@fujitsu-siemens.com> * 2002 Takashi Iwai <tiwai@suse.de> * @@ -68,7 +68,7 @@ #define POINTER_DEBUG #endif -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("VIA VT82xx audio"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{VIA,VT82C686A/B/C,pci},{VIA,VT8233A/C,8235}}"); @@ -1572,15 +1572,7 @@ static struct snd_kcontrol_new snd_via8233_capture_source __devinitdata = { .put = snd_via8233_capture_source_put, }; -static int snd_via8233_dxs3_spdif_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_via8233_dxs3_spdif_info snd_ctl_boolean_mono_info static int snd_via8233_dxs3_spdif_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -2098,7 +2090,7 @@ static int snd_via82xx_chip_init(struct via82xx *chip) pci_read_config_byte(chip->pci, VIA_ACLINK_STAT, &pval); if (pval & VIA_ACLINK_C00_READY) /* primary codec ready */ break; - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } while (time_before(jiffies, end_time)); if ((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_BUSY) @@ -2117,7 +2109,7 @@ static int snd_via82xx_chip_init(struct via82xx *chip) chip->ac97_secondary = 1; goto __ac97_ok2; } - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } while (time_before(jiffies, end_time)); /* This is ok, the most of motherboards have only one codec */ @@ -2371,6 +2363,7 @@ static struct snd_pci_quirk dxs_whitelist[] __devinitdata = { SND_PCI_QUIRK(0x1071, 0, "Diverse Notebook", VIA_DXS_NO_VRA), SND_PCI_QUIRK(0x10cf, 0x118e, "FSC Laptop", VIA_DXS_ENABLE), SND_PCI_QUIRK(0x1106, 0, "ASRock", VIA_DXS_SRC), + SND_PCI_QUIRK(0x1297, 0xa231, "Shuttle AK31v2", VIA_DXS_SRC), SND_PCI_QUIRK(0x1297, 0xa232, "Shuttle", VIA_DXS_ENABLE), SND_PCI_QUIRK(0x1297, 0xc160, "Shuttle Sk41G", VIA_DXS_ENABLE), SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte GA-7VAXP", VIA_DXS_ENABLE), diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c index 72425e73aba..57fb9ae22f9 100644 --- a/sound/pci/via82xx_modem.c +++ b/sound/pci/via82xx_modem.c @@ -3,7 +3,7 @@ * * VT82C686A/B/C, VT8233A/C, VT8235 * - * Copyright (c) 2000 Jaroslav Kysela <perex@suse.cz> + * Copyright (c) 2000 Jaroslav Kysela <perex@perex.cz> * Tjeerd.Mulder <Tjeerd.Mulder@fujitsu-siemens.com> * 2002 Takashi Iwai <tiwai@suse.de> * @@ -50,7 +50,7 @@ #define POINTER_DEBUG #endif -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("VIA VT82xx modem"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{VIA,VT82C686A/B/C modem,pci}}"); @@ -983,7 +983,7 @@ static int snd_via82xx_chip_init(struct via82xx_modem *chip) pci_read_config_byte(chip->pci, VIA_ACLINK_STAT, &pval); if (pval & VIA_ACLINK_C00_READY) /* primary codec ready */ break; - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } while (time_before(jiffies, end_time)); if ((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_BUSY) @@ -1001,7 +1001,7 @@ static int snd_via82xx_chip_init(struct via82xx_modem *chip) chip->ac97_secondary = 1; goto __ac97_ok2; } - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } while (time_before(jiffies, end_time)); /* This is ok, the most of motherboards have only one codec */ diff --git a/sound/pci/vx222/Makefile b/sound/pci/vx222/Makefile index 058c8bff7c1..a4d08d4de35 100644 --- a/sound/pci/vx222/Makefile +++ b/sound/pci/vx222/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-vx222-objs := vx222.o vx222_ops.o diff --git a/sound/pci/ymfpci/Makefile b/sound/pci/ymfpci/Makefile index 8790c5f3ed0..bd3d514ed76 100644 --- a/sound/pci/ymfpci/Makefile +++ b/sound/pci/ymfpci/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-ymfpci-objs := ymfpci.o ymfpci_main.o diff --git a/sound/pci/ymfpci/ymfpci.c b/sound/pci/ymfpci/ymfpci.c index fd9b7b83a88..5c4256a4d4b 100644 --- a/sound/pci/ymfpci/ymfpci.c +++ b/sound/pci/ymfpci/ymfpci.c @@ -1,6 +1,6 @@ /* * The driver for the Yamaha's DS1/DS1E cards - * 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 @@ -30,7 +30,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("Yamaha DS-1 PCI"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Yamaha,YMF724}," diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index ab7a81c3570..1fe39ed2876 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_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 YMF724/740/744/754 chips * * This program is free software; you can redistribute it and/or modify @@ -84,7 +84,6 @@ static int snd_ymfpci_codec_ready(struct snd_ymfpci *chip, int secondary) do { if ((snd_ymfpci_readw(chip, reg) & 0x8000) == 0) return 0; - set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout_uninterruptible(1); } while (time_before(jiffies, end_time)); snd_printk(KERN_ERR "codec_ready: codec %i is not ready [0x%x]\n", secondary, snd_ymfpci_readw(chip, reg)); @@ -171,17 +170,6 @@ static u32 snd_ymfpci_calc_lpfQ(u32 rate) return val[0]; } -static void snd_ymfpci_pcm_441_volume_set(struct snd_ymfpci_pcm *ypcm) -{ - unsigned int value; - struct snd_ymfpci_pcm_mixer *mixer; - - mixer = &ypcm->chip->pcm_mixer[ypcm->substream->number]; - value = min_t(unsigned int, mixer->left, 0x7fff) >> 1; - value |= (min_t(unsigned int, mixer->right, 0x7fff) >> 1) << 16; - snd_ymfpci_writel(ypcm->chip, YDSXGR_BUF441OUTVOL, value); -} - /* * Hardware start management */ @@ -389,6 +377,7 @@ static int snd_ymfpci_playback_trigger(struct snd_pcm_substream *substream, { struct snd_ymfpci *chip = snd_pcm_substream_chip(substream); struct snd_ymfpci_pcm *ypcm = substream->runtime->private_data; + struct snd_kcontrol *kctl = NULL; int result = 0; spin_lock(&chip->reg_lock); @@ -406,6 +395,11 @@ static int snd_ymfpci_playback_trigger(struct snd_pcm_substream *substream, ypcm->running = 1; break; case SNDRV_PCM_TRIGGER_STOP: + if (substream->pcm == chip->pcm && !ypcm->use_441_slot) { + kctl = chip->pcm_mixer[substream->number].ctl; + kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; + } + /* fall through */ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_SUSPEND: chip->ctrl_playback[ypcm->voices[0]->number + 1] = 0; @@ -419,6 +413,8 @@ static int snd_ymfpci_playback_trigger(struct snd_pcm_substream *substream, } __unlock: spin_unlock(&chip->reg_lock); + if (kctl) + snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_INFO, &kctl->id); return result; } static int snd_ymfpci_capture_trigger(struct snd_pcm_substream *substream, @@ -526,7 +522,6 @@ static void snd_ymfpci_pcm_init_voice(struct snd_ymfpci_pcm *ypcm, unsigned int ypcm->chip->src441_used = voice->number; ypcm->use_441_slot = 1; format |= 0x10000000; - snd_ymfpci_pcm_441_volume_set(ypcm); } if (ypcm->chip->src441_used == voice->number && (format & 0x10000000) == 0) { @@ -667,6 +662,7 @@ static int snd_ymfpci_playback_prepare(struct snd_pcm_substream *substream) struct snd_ymfpci *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct snd_ymfpci_pcm *ypcm = runtime->private_data; + struct snd_kcontrol *kctl; unsigned int nvoice; ypcm->period_size = runtime->period_size; @@ -676,6 +672,12 @@ static int snd_ymfpci_playback_prepare(struct snd_pcm_substream *substream) for (nvoice = 0; nvoice < runtime->channels; nvoice++) snd_ymfpci_pcm_init_voice(ypcm, nvoice, runtime, substream->pcm == chip->pcm); + + if (substream->pcm == chip->pcm && !ypcm->use_441_slot) { + kctl = chip->pcm_mixer[substream->number].ctl; + kctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; + snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_INFO, &kctl->id); + } return 0; } @@ -926,7 +928,6 @@ static int snd_ymfpci_playback_open(struct snd_pcm_substream *substream) struct snd_ymfpci *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct snd_ymfpci_pcm *ypcm; - struct snd_kcontrol *kctl; int err; if ((err = snd_ymfpci_playback_open_1(substream)) < 0) @@ -941,10 +942,6 @@ static int snd_ymfpci_playback_open(struct snd_pcm_substream *substream) chip->rear_opened++; } spin_unlock_irq(&chip->reg_lock); - - kctl = chip->pcm_mixer[substream->number].ctl; - kctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; - snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_INFO, &kctl->id); return 0; } @@ -1039,7 +1036,6 @@ static int snd_ymfpci_playback_close(struct snd_pcm_substream *substream) { struct snd_ymfpci *chip = snd_pcm_substream_chip(substream); struct snd_ymfpci_pcm *ypcm = substream->runtime->private_data; - struct snd_kcontrol *kctl; spin_lock_irq(&chip->reg_lock); if (ypcm->output_rear && chip->rear_opened > 0) { @@ -1047,9 +1043,6 @@ static int snd_ymfpci_playback_close(struct snd_pcm_substream *substream) ymfpci_close_extension(chip); } spin_unlock_irq(&chip->reg_lock); - kctl = chip->pcm_mixer[substream->number].ctl; - kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; - snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_INFO, &kctl->id); return snd_ymfpci_playback_close_1(substream); } @@ -1443,22 +1436,7 @@ static struct snd_kcontrol_new snd_ymfpci_drec_source __devinitdata = { .get = snd_ymfpci_get_single, .put = snd_ymfpci_put_single, \ .private_value = ((reg) | ((shift) << 16)) } -static int snd_ymfpci_info_single(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - int reg = kcontrol->private_value & 0xffff; - - switch (reg) { - case YDSXGR_SPDIFOUTCTRL: break; - case YDSXGR_SPDIFINCTRL: break; - default: return -EINVAL; - } - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} +#define snd_ymfpci_info_single snd_ctl_boolean_mono_info static int snd_ymfpci_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1567,17 +1545,30 @@ static int snd_ymfpci_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e return change; } +static int snd_ymfpci_put_nativedacvol(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol); + unsigned int reg = YDSXGR_NATIVEDACOUTVOL; + unsigned int reg2 = YDSXGR_BUF441OUTVOL; + int change; + unsigned int value, oval; + + value = ucontrol->value.integer.value[0] & 0x3fff; + value |= (ucontrol->value.integer.value[1] & 0x3fff) << 16; + spin_lock_irq(&chip->reg_lock); + oval = snd_ymfpci_readl(chip, reg); + change = value != oval; + snd_ymfpci_writel(chip, reg, value); + snd_ymfpci_writel(chip, reg2, value); + spin_unlock_irq(&chip->reg_lock); + return change; +} + /* * 4ch duplication */ -static int snd_ymfpci_info_dup4ch(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_ymfpci_info_dup4ch snd_ctl_boolean_mono_info static int snd_ymfpci_get_dup4ch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1598,7 +1589,17 @@ static int snd_ymfpci_put_dup4ch(struct snd_kcontrol *kcontrol, struct snd_ctl_e static struct snd_kcontrol_new snd_ymfpci_controls[] __devinitdata = { -YMFPCI_DOUBLE("Wave Playback Volume", 0, YDSXGR_NATIVEDACOUTVOL), +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Wave Playback Volume", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ, + .info = snd_ymfpci_info_double, + .get = snd_ymfpci_get_double, + .put = snd_ymfpci_put_nativedacvol, + .private_value = YDSXGR_NATIVEDACOUTVOL, + .tlv = { .p = db_scale_native }, +}, YMFPCI_DOUBLE("Wave Capture Volume", 0, YDSXGR_NATIVEDACLOOPVOL), YMFPCI_DOUBLE("Digital Capture Volume", 0, YDSXGR_NATIVEDACINVOL), YMFPCI_DOUBLE("Digital Capture Volume", 1, YDSXGR_NATIVEADCINVOL), @@ -1665,14 +1666,7 @@ static int snd_ymfpci_set_gpio_out(struct snd_ymfpci *chip, int pin, int enable) return 0; } -static int snd_ymfpci_gpio_sw_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_ymfpci_gpio_sw_info snd_ctl_boolean_mono_info static int snd_ymfpci_gpio_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1748,8 +1742,6 @@ static int snd_ymfpci_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ymfpci_pcm *ypcm = substream->runtime->private_data; if (!ypcm->use_441_slot) ypcm->update_pcm_vol = 2; - else - snd_ymfpci_pcm_441_volume_set(ypcm); } spin_unlock_irqrestore(&chip->voice_lock, flags); return 1; diff --git a/sound/pcmcia/Makefile b/sound/pcmcia/Makefile index b6656d48bec..beef2e33b71 100644 --- a/sound/pcmcia/Makefile +++ b/sound/pcmcia/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> # obj-$(CONFIG_SND) += vx/ pdaudiocf/ diff --git a/sound/pcmcia/pdaudiocf/Makefile b/sound/pcmcia/pdaudiocf/Makefile index 6e194f9b50e..e892d7299ab 100644 --- a/sound/pcmcia/pdaudiocf/Makefile +++ b/sound/pcmcia/pdaudiocf/Makefile @@ -1,6 +1,6 @@ # # Makefile for ALSA -# Copyright (c) 2004 by Jaroslav Kysela <perex@suse.cz> +# Copyright (c) 2004 by Jaroslav Kysela <perex@perex.cz> # snd-pdaudiocf-objs := pdaudiocf.o pdaudiocf_core.o pdaudiocf_irq.o pdaudiocf_pcm.o diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.c b/sound/pcmcia/pdaudiocf/pdaudiocf.c index 2d40cc72f23..de683b08fe0 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf.c @@ -1,7 +1,7 @@ /* * Driver for Sound Core PDAudioCF soundcard * - * Copyright (c) 2003 by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) 2003 by Jaroslav Kysela <perex@perex.cz> * * 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 @@ -33,7 +33,7 @@ #define CARD_NAME "PDAudio-CF" -MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); +MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("Sound Core " CARD_NAME); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Sound Core," CARD_NAME "}}"); diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.h b/sound/pcmcia/pdaudiocf/pdaudiocf.h index 206e2f5a113..b0601838112 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf.h +++ b/sound/pcmcia/pdaudiocf/pdaudiocf.h @@ -1,7 +1,7 @@ /* * Driver for Sound Cors PDAudioCF soundcard * - * Copyright (c) 2003 by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) 2003 by Jaroslav Kysela <perex@perex.cz> * * 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 diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_core.c b/sound/pcmcia/pdaudiocf/pdaudiocf_core.c index 1dfe29b863d..484c8f9a6f1 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf_core.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf_core.c @@ -1,7 +1,7 @@ /* * Driver for Sound Core PDAudioCF soundcard * - * Copyright (c) 2003 by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) 2003 by Jaroslav Kysela <perex@perex.cz> * * 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 diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c b/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c index 5bd69206ba6..54543369949 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c @@ -1,7 +1,7 @@ /* * Driver for Sound Core PDAudioCF soundcard * - * Copyright (c) 2003 by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) 2003 by Jaroslav Kysela <perex@perex.cz> * * 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 diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c index 7f2a4de1d35..10afcb262d5 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c @@ -3,7 +3,7 @@ * * PCM part * - * Copyright (c) 2003 by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) 2003 by Jaroslav Kysela <perex@perex.cz> * * 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 diff --git a/sound/pcmcia/vx/Makefile b/sound/pcmcia/vx/Makefile index 54971f01e96..2bb42ea12f3 100644 --- a/sound/pcmcia/vx/Makefile +++ b/sound/pcmcia/vx/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-vxpocket-objs := vxpocket.o vxp_ops.o vxp_mixer.o diff --git a/sound/pcmcia/vx/vxp_mixer.c b/sound/pcmcia/vx/vxp_mixer.c index 2b1f996c898..1eff158b868 100644 --- a/sound/pcmcia/vx/vxp_mixer.c +++ b/sound/pcmcia/vx/vxp_mixer.c @@ -80,14 +80,7 @@ static struct snd_kcontrol_new vx_control_mic_level = { /* * mic boost level control (for VXP440) */ -static int vx_mic_boost_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 vx_mic_boost_info snd_ctl_boolean_mono_info static int vx_mic_boost_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { diff --git a/sound/ppc/Makefile b/sound/ppc/Makefile index eacee2d0675..679c45a8da2 100644 --- a/sound/ppc/Makefile +++ b/sound/ppc/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-powermac-objs := powermac.o pmac.o awacs.o burgundy.o daca.o tumbler.o keywest.o beep.o diff --git a/sound/ppc/beep.c b/sound/ppc/beep.c index a1aa89f2faf..566b5ab9d4e 100644 --- a/sound/ppc/beep.c +++ b/sound/ppc/beep.c @@ -236,8 +236,8 @@ int __init snd_pmac_attach_beep(struct snd_pmac *chip) input_dev->id.product = 0x0001; input_dev->id.version = 0x0100; - input_dev->evbit[0] = BIT(EV_SND); - input_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE); + input_dev->evbit[0] = BIT_MASK(EV_SND); + input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE); input_dev->event = snd_pmac_beep_event; input_dev->dev.parent = &chip->pdev->dev; input_set_drvdata(input_dev, chip); diff --git a/sound/ppc/daca.c b/sound/ppc/daca.c index 57202b0f033..c5a1f0be6a4 100644 --- a/sound/ppc/daca.c +++ b/sound/ppc/daca.c @@ -91,15 +91,7 @@ static int daca_set_volume(struct pmac_daca *mix) /* deemphasis switch */ -static int daca_info_deemphasis(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 daca_info_deemphasis snd_ctl_boolean_mono_info static int daca_get_deemphasis(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c index 7a22f0f3784..4f9b19c90a4 100644 --- a/sound/ppc/pmac.c +++ b/sound/ppc/pmac.c @@ -490,35 +490,14 @@ static int snd_pmac_pcm_open(struct snd_pmac *chip, struct pmac_stream *rec, struct snd_pcm_substream *subs) { struct snd_pcm_runtime *runtime = subs->runtime; - int i, j, fflags; - static int typical_freqs[] = { - 44100, - 22050, - 11025, - 0, - }; - static int typical_freq_flags[] = { - SNDRV_PCM_RATE_44100, - SNDRV_PCM_RATE_22050, - SNDRV_PCM_RATE_11025, - 0, - }; + int i; /* look up frequency table and fill bit mask */ runtime->hw.rates = 0; - fflags = chip->freqs_ok; - for (i = 0; typical_freqs[i]; i++) { - for (j = 0; j < chip->num_freqs; j++) { - if ((chip->freqs_ok & (1 << j)) && - chip->freq_table[j] == typical_freqs[i]) { - runtime->hw.rates |= typical_freq_flags[i]; - fflags &= ~(1 << j); - break; - } - } - } - if (fflags) /* rest */ - runtime->hw.rates |= SNDRV_PCM_RATE_KNOT; + for (i = 0; i < chip->num_freqs; i++) + if (chip->freqs_ok & (1 << i)) + runtime->hw.rates |= + snd_pcm_rate_to_rate_bit(chip->freq_table[i]); /* check for minimum and maximum rates */ for (i = 0; i < chip->num_freqs; i++) { @@ -551,9 +530,6 @@ static int snd_pmac_pcm_open(struct snd_pmac *chip, struct pmac_stream *rec, runtime->hw.periods_max = rec->cmd.size - 1; - if (chip->can_duplex) - snd_pcm_set_sync(subs); - /* constraints to fix choppy sound */ snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); return 0; @@ -1035,29 +1011,6 @@ static int __init snd_pmac_detect(struct snd_pmac *chip) return 0; } -/* - * exported - boolean info callbacks for ease of programming - */ -int snd_pmac_boolean_stereo_info(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; -} - -int snd_pmac_boolean_mono_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; -} - #ifdef PMAC_SUPPORT_AUTOMUTE /* * auto-mute diff --git a/sound/ppc/pmac.h b/sound/ppc/pmac.h index 8394e66ceb0..25c512c2d74 100644 --- a/sound/ppc/pmac.h +++ b/sound/ppc/pmac.h @@ -202,8 +202,8 @@ int snd_pmac_keywest_init(struct pmac_keywest *i2c); void snd_pmac_keywest_cleanup(struct pmac_keywest *i2c); /* misc */ -int snd_pmac_boolean_stereo_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); -int snd_pmac_boolean_mono_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); +#define snd_pmac_boolean_stereo_info snd_ctl_boolean_stereo_info +#define snd_pmac_boolean_mono_info snd_ctl_boolean_mono_info int snd_pmac_add_automute(struct snd_pmac *chip); diff --git a/sound/ppc/snd_ps3.c b/sound/ppc/snd_ps3.c index 1aa0b467599..27b61899fe8 100644 --- a/sound/ppc/snd_ps3.c +++ b/sound/ppc/snd_ps3.c @@ -33,7 +33,6 @@ #include <linux/dmapool.h> #include <linux/dma-mapping.h> #include <asm/firmware.h> -#include <linux/io.h> #include <asm/dma.h> #include <asm/lv1call.h> #include <asm/ps3.h> diff --git a/sound/sh/aica.c b/sound/sh/aica.c index 739786529ca..131ec481228 100644 --- a/sound/sh/aica.c +++ b/sound/sh/aica.c @@ -451,15 +451,7 @@ static int __init snd_aicapcmchip(struct snd_card_aica } /* Mixer controls */ -static int aica_pcmswitch_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 aica_pcmswitch_info snd_ctl_boolean_mono_info static int aica_pcmswitch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index e5fb437b86e..78248808a9d 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -17,3 +17,23 @@ config SND_SOC_WM8753 config SND_SOC_WM9712 tristate depends on SND_SOC + +# Cirrus Logic CS4270 Codec +config SND_SOC_CS4270 + tristate + depends on SND_SOC + +# Cirrus Logic CS4270 Codec Hardware Mute Support +# Select if you have external muting circuitry attached to your CS4270. +config SND_SOC_CS4270_HWMUTE + bool + depends on SND_SOC_CS4270 + +# Cirrus Logic CS4270 Codec VD = 3.3V Errata +# Select if you are affected by the errata where the part will not function +# if MCLK divide-by-1.5 is selected and VD is set to 3.3V. The driver will +# not select any sample rates that require MCLK to be divided by 1.5. +config SND_SOC_CS4270_VD33_ERRATA + bool + depends on SND_SOC_CS4270 + diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index e39a747a17c..7ad78e36d50 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -3,9 +3,11 @@ snd-soc-wm8731-objs := wm8731.o snd-soc-wm8750-objs := wm8750.o snd-soc-wm8753-objs := wm8753.o snd-soc-wm9712-objs := wm9712.o +snd-soc-cs4270-objs := cs4270.o obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o +obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c new file mode 100644 index 00000000000..5d601ad6da7 --- /dev/null +++ b/sound/soc/codecs/cs4270.c @@ -0,0 +1,805 @@ +/* + * CS4270 ALSA SoC (ASoC) codec driver + * + * Author: Timur Tabi <timur@freescale.com> + * + * Copyright 2007 Freescale Semiconductor, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + * + * This is an ASoC device driver for the Cirrus Logic CS4270 codec. + * + * Current features/limitations: + * + * 1) Software mode is supported. Stand-alone mode is automatically + * selected if I2C is disabled or if a CS4270 is not found on the I2C + * bus. However, stand-alone mode is only partially implemented because + * there is no mechanism yet for this driver and the machine driver to + * communicate the values of the M0, M1, MCLK1, and MCLK2 pins. + * 2) Only I2C is supported, not SPI + * 3) Only Master mode is supported, not Slave. + * 4) The machine driver's 'startup' function must call + * cs4270_set_dai_sysclk() with the value of MCLK. + * 5) Only I2S and left-justified modes are supported + * 6) Power management is not supported + * 7) The only supported control is volume and hardware mute (if enabled) + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <sound/driver.h> +#include <sound/core.h> +#include <sound/soc.h> +#include <sound/initval.h> +#include <linux/i2c.h> + +#include "cs4270.h" + +/* If I2C is defined, then we support software mode. However, if we're + not compiled as module but I2C is, then we can't use I2C calls. */ +#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) +#define USE_I2C +#endif + +/* Private data for the CS4270 */ +struct cs4270_private { + unsigned int mclk; /* Input frequency of the MCLK pin */ + unsigned int mode; /* The mode (I2S or left-justified) */ +}; + +/* The number of MCLK/LRCK ratios supported by the CS4270 */ +#define NUM_MCLK_RATIOS 9 + +/* The actual MCLK/LRCK ratios, in increasing numerical order */ +static unsigned int mclk_ratios[NUM_MCLK_RATIOS] = + {64, 96, 128, 192, 256, 384, 512, 768, 1024}; + +/* + * Determine the CS4270 samples rates. + * + * 'freq' is the input frequency to MCLK. The other parameters are ignored. + * + * The value of MCLK is used to determine which sample rates are supported + * by the CS4270. The ratio of MCLK / Fs must be equal to one of nine + * support values: 64, 96, 128, 192, 256, 384, 512, 768, and 1024. + * + * This function calculates the nine ratios and determines which ones match + * a standard sample rate. If there's a match, then it is added to the list + * of support sample rates. + * + * This function must be called by the machine driver's 'startup' function, + * otherwise the list of supported sample rates will not be available in + * time for ALSA. + * + * Note that in stand-alone mode, the sample rate is determined by input + * pins M0, M1, MDIV1, and MDIV2. Also in stand-alone mode, divide-by-3 + * is not a programmable option. However, divide-by-3 is not an available + * option in stand-alone mode. This cases two problems: a ratio of 768 is + * not available (it requires divide-by-3) and B) ratios 192 and 384 can + * only be selected with divide-by-1.5, but there is an errate that make + * this selection difficult. + * + * In addition, there is no mechanism for communicating with the machine + * driver what the input settings can be. This would need to be implemented + * for stand-alone mode to work. + */ +static int cs4270_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct cs4270_private *cs4270 = codec->private_data; + unsigned int rates = 0; + unsigned int rate_min = -1; + unsigned int rate_max = 0; + unsigned int i; + + cs4270->mclk = freq; + + for (i = 0; i < NUM_MCLK_RATIOS; i++) { + unsigned int rate = freq / mclk_ratios[i]; + rates |= snd_pcm_rate_to_rate_bit(rate); + if (rate < rate_min) + rate_min = rate; + if (rate > rate_max) + rate_max = rate; + } + /* FIXME: soc should support a rate list */ + rates &= ~SNDRV_PCM_RATE_KNOT; + + if (!rates) { + printk(KERN_ERR "cs4270: could not find a valid sample rate\n"); + return -EINVAL; + } + + codec_dai->playback.rates = rates; + codec_dai->playback.rate_min = rate_min; + codec_dai->playback.rate_max = rate_max; + + codec_dai->capture.rates = rates; + codec_dai->capture.rate_min = rate_min; + codec_dai->capture.rate_max = rate_max; + + return 0; +} + +/* + * Configure the codec for the selected audio format + * + * This function takes a bitmask of SND_SOC_DAIFMT_x bits and programs the + * codec accordingly. + * + * Currently, this function only supports SND_SOC_DAIFMT_I2S and + * SND_SOC_DAIFMT_LEFT_J. The CS4270 codec also supports right-justified + * data for playback only, but ASoC currently does not support different + * formats for playback vs. record. + */ +static int cs4270_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, + unsigned int format) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct cs4270_private *cs4270 = codec->private_data; + int ret = 0; + + switch (format & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + case SND_SOC_DAIFMT_LEFT_J: + cs4270->mode = format & SND_SOC_DAIFMT_FORMAT_MASK; + break; + default: + printk(KERN_ERR "cs4270: invalid DAI format\n"); + ret = -EINVAL; + } + + return ret; +} + +/* + * The codec isn't really big-endian or little-endian, since the I2S + * interface requires data to be sent serially with the MSbit first. + * However, to support BE and LE I2S devices, we specify both here. That + * way, ALSA will always match the bit patterns. + */ +#define CS4270_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ + SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \ + SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \ + SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \ + SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE) + +#ifdef USE_I2C + +/* CS4270 registers addresses */ +#define CS4270_CHIPID 0x01 /* Chip ID */ +#define CS4270_PWRCTL 0x02 /* Power Control */ +#define CS4270_MODE 0x03 /* Mode Control */ +#define CS4270_FORMAT 0x04 /* Serial Format, ADC/DAC Control */ +#define CS4270_TRANS 0x05 /* Transition Control */ +#define CS4270_MUTE 0x06 /* Mute Control */ +#define CS4270_VOLA 0x07 /* DAC Channel A Volume Control */ +#define CS4270_VOLB 0x08 /* DAC Channel B Volume Control */ + +#define CS4270_FIRSTREG 0x01 +#define CS4270_LASTREG 0x08 +#define CS4270_NUMREGS (CS4270_LASTREG - CS4270_FIRSTREG + 1) + +/* Bit masks for the CS4270 registers */ +#define CS4270_CHIPID_ID 0xF0 +#define CS4270_CHIPID_REV 0x0F +#define CS4270_PWRCTL_FREEZE 0x80 +#define CS4270_PWRCTL_PDN_ADC 0x20 +#define CS4270_PWRCTL_PDN_DAC 0x02 +#define CS4270_PWRCTL_PDN 0x01 +#define CS4270_MODE_SPEED_MASK 0x30 +#define CS4270_MODE_1X 0x00 +#define CS4270_MODE_2X 0x10 +#define CS4270_MODE_4X 0x20 +#define CS4270_MODE_SLAVE 0x30 +#define CS4270_MODE_DIV_MASK 0x0E +#define CS4270_MODE_DIV1 0x00 +#define CS4270_MODE_DIV15 0x02 +#define CS4270_MODE_DIV2 0x04 +#define CS4270_MODE_DIV3 0x06 +#define CS4270_MODE_DIV4 0x08 +#define CS4270_MODE_POPGUARD 0x01 +#define CS4270_FORMAT_FREEZE_A 0x80 +#define CS4270_FORMAT_FREEZE_B 0x40 +#define CS4270_FORMAT_LOOPBACK 0x20 +#define CS4270_FORMAT_DAC_MASK 0x18 +#define CS4270_FORMAT_DAC_LJ 0x00 +#define CS4270_FORMAT_DAC_I2S 0x08 +#define CS4270_FORMAT_DAC_RJ16 0x18 +#define CS4270_FORMAT_DAC_RJ24 0x10 +#define CS4270_FORMAT_ADC_MASK 0x01 +#define CS4270_FORMAT_ADC_LJ 0x00 +#define CS4270_FORMAT_ADC_I2S 0x01 +#define CS4270_TRANS_ONE_VOL 0x80 +#define CS4270_TRANS_SOFT 0x40 +#define CS4270_TRANS_ZERO 0x20 +#define CS4270_TRANS_INV_ADC_A 0x08 +#define CS4270_TRANS_INV_ADC_B 0x10 +#define CS4270_TRANS_INV_DAC_A 0x02 +#define CS4270_TRANS_INV_DAC_B 0x04 +#define CS4270_TRANS_DEEMPH 0x01 +#define CS4270_MUTE_AUTO 0x20 +#define CS4270_MUTE_ADC_A 0x08 +#define CS4270_MUTE_ADC_B 0x10 +#define CS4270_MUTE_POLARITY 0x04 +#define CS4270_MUTE_DAC_A 0x01 +#define CS4270_MUTE_DAC_B 0x02 + +/* + * A list of addresses on which this CS4270 could use. I2C addresses are + * 7 bits. For the CS4270, the upper four bits are always 1001, and the + * lower three bits are determined via the AD2, AD1, and AD0 pins + * (respectively). + */ +static unsigned short normal_i2c[] = { + 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, I2C_CLIENT_END +}; +I2C_CLIENT_INSMOD; + +/* + * Pre-fill the CS4270 register cache. + * + * We use the auto-increment feature of the CS4270 to read all registers in + * one shot. + */ +static int cs4270_fill_cache(struct snd_soc_codec *codec) +{ + u8 *cache = codec->reg_cache; + struct i2c_client *i2c_client = codec->control_data; + s32 length; + + length = i2c_smbus_read_i2c_block_data(i2c_client, + CS4270_FIRSTREG | 0x80, CS4270_NUMREGS, cache); + + if (length != CS4270_NUMREGS) { + printk(KERN_ERR "cs4270: I2C read failure, addr=0x%x\n", + i2c_client->addr); + return -EIO; + } + + return 0; +} + +/* + * Read from the CS4270 register cache. + * + * This CS4270 registers are cached to avoid excessive I2C I/O operations. + * After the initial read to pre-fill the cache, the CS4270 never updates + * the register values, so we won't have a cache coherncy problem. + */ +static unsigned int cs4270_read_reg_cache(struct snd_soc_codec *codec, + unsigned int reg) +{ + u8 *cache = codec->reg_cache; + + if ((reg < CS4270_FIRSTREG) || (reg > CS4270_LASTREG)) + return -EIO; + + return cache[reg - CS4270_FIRSTREG]; +} + +/* + * Write to a CS4270 register via the I2C bus. + * + * This function writes the given value to the given CS4270 register, and + * also updates the register cache. + * + * Note that we don't use the hw_write function pointer of snd_soc_codec. + * That's because it's too clunky: the hw_write_t prototype does not match + * i2c_smbus_write_byte_data(), and it's just another layer of overhead. + */ +static int cs4270_i2c_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u8 *cache = codec->reg_cache; + + if ((reg < CS4270_FIRSTREG) || (reg > CS4270_LASTREG)) + return -EIO; + + /* Only perform an I2C operation if the new value is different */ + if (cache[reg - CS4270_FIRSTREG] != value) { + struct i2c_client *client = codec->control_data; + if (i2c_smbus_write_byte_data(client, reg, value)) { + printk(KERN_ERR "cs4270: I2C write failed\n"); + return -EIO; + } + + /* We've written to the hardware, so update the cache */ + cache[reg - CS4270_FIRSTREG] = value; + } + + return 0; +} + +/* + * Clock Ratio Selection for Master Mode with I2C enabled + * + * The data for this chart is taken from Table 5 of the CS4270 reference + * manual. + * + * This table is used to determine how to program the Mode Control register. + * It is also used by cs4270_set_dai_sysclk() to tell ALSA which sampling + * rates the CS4270 currently supports. + * + * Each element in this array corresponds to the ratios in mclk_ratios[]. + * These two arrays need to be in sync. + * + * 'speed_mode' is the corresponding bit pattern to be written to the + * MODE bits of the Mode Control Register + * + * 'mclk' is the corresponding bit pattern to be wirten to the MCLK bits of + * the Mode Control Register. + * + * In situations where a single ratio is represented by multiple speed + * modes, we favor the slowest speed. E.g, for a ratio of 128, we pick + * double-speed instead of quad-speed. However, the CS4270 errata states + * that Divide-By-1.5 can cause failures, so we avoid that mode where + * possible. + * + * ERRATA: There is an errata for the CS4270 where divide-by-1.5 does not + * work if VD = 3.3V. If this effects you, select the + * CONFIG_SND_SOC_CS4270_VD33_ERRATA Kconfig option, and the driver will + * never select any sample rates that require divide-by-1.5. + */ +static struct { + u8 speed_mode; + u8 mclk; +} cs4270_mode_ratios[NUM_MCLK_RATIOS] = { + {CS4270_MODE_4X, CS4270_MODE_DIV1}, /* 64 */ +#ifndef CONFIG_SND_SOC_CS4270_VD33_ERRATA + {CS4270_MODE_4X, CS4270_MODE_DIV15}, /* 96 */ +#endif + {CS4270_MODE_2X, CS4270_MODE_DIV1}, /* 128 */ + {CS4270_MODE_4X, CS4270_MODE_DIV3}, /* 192 */ + {CS4270_MODE_1X, CS4270_MODE_DIV1}, /* 256 */ + {CS4270_MODE_2X, CS4270_MODE_DIV3}, /* 384 */ + {CS4270_MODE_1X, CS4270_MODE_DIV2}, /* 512 */ + {CS4270_MODE_1X, CS4270_MODE_DIV3}, /* 768 */ + {CS4270_MODE_1X, CS4270_MODE_DIV4} /* 1024 */ +}; + +/* + * Program the CS4270 with the given hardware parameters. + * + * The .dai_ops functions are used to provide board-specific data, like + * input frequencies, to this driver. This function takes that information, + * combines it with the hardware parameters provided, and programs the + * hardware accordingly. + */ +static int cs4270_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->codec; + struct cs4270_private *cs4270 = codec->private_data; + unsigned int ret = 0; + unsigned int i; + unsigned int rate; + unsigned int ratio; + int reg; + + /* Figure out which MCLK/LRCK ratio to use */ + + rate = params_rate(params); /* Sampling rate, in Hz */ + ratio = cs4270->mclk / rate; /* MCLK/LRCK ratio */ + + for (i = 0; i < NUM_MCLK_RATIOS; i++) { + if (mclk_ratios[i] == ratio) + break; + } + + if (i == NUM_MCLK_RATIOS) { + /* We did not find a matching ratio */ + printk(KERN_ERR "cs4270: could not find matching ratio\n"); + return -EINVAL; + } + + /* Freeze and power-down the codec */ + + ret = snd_soc_write(codec, CS4270_PWRCTL, CS4270_PWRCTL_FREEZE | + CS4270_PWRCTL_PDN_ADC | CS4270_PWRCTL_PDN_DAC | + CS4270_PWRCTL_PDN); + if (ret < 0) { + printk(KERN_ERR "cs4270: I2C write failed\n"); + return ret; + } + + /* Program the mode control register */ + + reg = snd_soc_read(codec, CS4270_MODE); + reg &= ~(CS4270_MODE_SPEED_MASK | CS4270_MODE_DIV_MASK); + reg |= cs4270_mode_ratios[i].speed_mode | cs4270_mode_ratios[i].mclk; + + ret = snd_soc_write(codec, CS4270_MODE, reg); + if (ret < 0) { + printk(KERN_ERR "cs4270: I2C write failed\n"); + return ret; + } + + /* Program the format register */ + + reg = snd_soc_read(codec, CS4270_FORMAT); + reg &= ~(CS4270_FORMAT_DAC_MASK | CS4270_FORMAT_ADC_MASK); + + switch (cs4270->mode) { + case SND_SOC_DAIFMT_I2S: + reg |= CS4270_FORMAT_DAC_I2S | CS4270_FORMAT_ADC_I2S; + break; + case SND_SOC_DAIFMT_LEFT_J: + reg |= CS4270_FORMAT_DAC_LJ | CS4270_FORMAT_ADC_LJ; + break; + default: + printk(KERN_ERR "cs4270: unknown format\n"); + return -EINVAL; + } + + ret = snd_soc_write(codec, CS4270_FORMAT, reg); + if (ret < 0) { + printk(KERN_ERR "cs4270: I2C write failed\n"); + return ret; + } + + /* Disable auto-mute. This feature appears to be buggy, because in + some situations, auto-mute will not deactivate when it should. */ + + reg = snd_soc_read(codec, CS4270_MUTE); + reg &= ~CS4270_MUTE_AUTO; + ret = snd_soc_write(codec, CS4270_MUTE, reg); + if (ret < 0) { + printk(KERN_ERR "cs4270: I2C write failed\n"); + return ret; + } + + /* Thaw and power-up the codec */ + + ret = snd_soc_write(codec, CS4270_PWRCTL, 0); + if (ret < 0) { + printk(KERN_ERR "cs4270: I2C write failed\n"); + return ret; + } + + return ret; +} + +#ifdef CONFIG_SND_SOC_CS4270_HWMUTE + +/* + * Set the CS4270 external mute + * + * This function toggles the mute bits in the MUTE register. The CS4270's + * mute capability is intended for external muting circuitry, so if the + * board does not have the MUTEA or MUTEB pins connected to such circuitry, + * then this function will do nothing. + */ +static int cs4270_mute(struct snd_soc_codec_dai *dai, int mute) +{ + struct snd_soc_codec *codec = dai->codec; + int reg6; + + reg6 = snd_soc_read(codec, CS4270_MUTE); + + if (mute) + reg6 |= CS4270_MUTE_ADC_A | CS4270_MUTE_ADC_B | + CS4270_MUTE_DAC_A | CS4270_MUTE_DAC_B; + else + reg6 &= ~(CS4270_MUTE_ADC_A | CS4270_MUTE_ADC_B | + CS4270_MUTE_DAC_A | CS4270_MUTE_DAC_B); + + return snd_soc_write(codec, CS4270_MUTE, reg6); +} + +#endif + +static int cs4270_i2c_probe(struct i2c_adapter *adap, int addr, int kind); + +/* + * Notify the driver that a new I2C bus has been found. + * + * This function is called for each I2C bus in the system. The function + * then asks the I2C subsystem to probe that bus at the addresses on which + * our device (the CS4270) could exist. If a device is found at one of + * those addresses, then our probe function (cs4270_i2c_probe) is called. + */ +static int cs4270_i2c_attach(struct i2c_adapter *adapter) +{ + return i2c_probe(adapter, &addr_data, cs4270_i2c_probe); +} + +static int cs4270_i2c_detach(struct i2c_client *client) +{ + struct snd_soc_codec *codec = i2c_get_clientdata(client); + + i2c_detach_client(client); + codec->control_data = NULL; + + kfree(codec->reg_cache); + codec->reg_cache = NULL; + + kfree(client); + return 0; +} + +/* A list of non-DAPM controls that the CS4270 supports */ +static const struct snd_kcontrol_new cs4270_snd_controls[] = { + SOC_DOUBLE_R("Master Playback Volume", + CS4270_VOLA, CS4270_VOLB, 0, 0xFF, 1) +}; + +static struct i2c_driver cs4270_i2c_driver = { + .driver = { + .name = "CS4270 I2C", + .owner = THIS_MODULE, + }, + .id = I2C_DRIVERID_CS4270, + .attach_adapter = cs4270_i2c_attach, + .detach_client = cs4270_i2c_detach, +}; + +/* + * Global variable to store socdev for i2c probe function. + * + * If struct i2c_driver had a private_data field, we wouldn't need to use + * cs4270_socdec. This is the only way to pass the socdev structure to + * cs4270_i2c_probe(). + * + * The real solution to cs4270_socdev is to create a mechanism + * that maps I2C addresses to snd_soc_device structures. Perhaps the + * creation of the snd_soc_device object should be moved out of + * cs4270_probe() and into cs4270_i2c_probe(), but that would make this + * driver dependent on I2C. The CS4270 supports "stand-alone" mode, whereby + * the chip is *not* connected to the I2C bus, but is instead configured via + * input pins. + */ +static struct snd_soc_device *cs4270_socdev; + +/* + * Initialize the I2C interface of the CS4270 + * + * This function is called for whenever the I2C subsystem finds a device + * at a particular address. + * + * Note: snd_soc_new_pcms() must be called before this function can be called, + * because of snd_ctl_add(). + */ +static int cs4270_i2c_probe(struct i2c_adapter *adapter, int addr, int kind) +{ + struct snd_soc_device *socdev = cs4270_socdev; + struct snd_soc_codec *codec = socdev->codec; + struct i2c_client *i2c_client = NULL; + int i; + int ret = 0; + + /* Probing all possible addresses has one drawback: if there are + multiple CS4270s on the bus, then you cannot specify which + socdev is matched with which CS4270. For now, we just reject + this I2C device if the socdev already has one attached. */ + if (codec->control_data) + return -ENODEV; + + /* Note: codec_dai->codec is NULL here */ + + i2c_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (!i2c_client) { + printk(KERN_ERR "cs4270: could not allocate I2C client\n"); + return -ENOMEM; + } + + codec->reg_cache = kzalloc(CS4270_NUMREGS, GFP_KERNEL); + if (!codec->reg_cache) { + printk(KERN_ERR "cs4270: could not allocate register cache\n"); + ret = -ENOMEM; + goto error; + } + + i2c_set_clientdata(i2c_client, codec); + strcpy(i2c_client->name, "CS4270"); + + i2c_client->driver = &cs4270_i2c_driver; + i2c_client->adapter = adapter; + i2c_client->addr = addr; + + /* Verify that we have a CS4270 */ + + ret = i2c_smbus_read_byte_data(i2c_client, CS4270_CHIPID); + if (ret < 0) { + printk(KERN_ERR "cs4270: failed to read I2C\n"); + goto error; + } + /* The top four bits of the chip ID should be 1100. */ + if ((ret & 0xF0) != 0xC0) { + /* The device at this address is not a CS4270 codec */ + ret = -ENODEV; + goto error; + } + + printk(KERN_INFO "cs4270: found device at I2C address %X\n", addr); + printk(KERN_INFO "cs4270: hardware revision %X\n", ret & 0xF); + + /* Tell the I2C layer a new client has arrived */ + + ret = i2c_attach_client(i2c_client); + if (ret) { + printk(KERN_ERR "cs4270: could not attach codec, " + "I2C address %x, error code %i\n", addr, ret); + goto error; + } + + codec->control_data = i2c_client; + codec->read = cs4270_read_reg_cache; + codec->write = cs4270_i2c_write; + codec->reg_cache_size = CS4270_NUMREGS; + + /* The I2C interface is set up, so pre-fill our register cache */ + + ret = cs4270_fill_cache(codec); + if (ret < 0) { + printk(KERN_ERR "cs4270: failed to fill register cache\n"); + goto error; + } + + /* Add the non-DAPM controls */ + + for (i = 0; i < ARRAY_SIZE(cs4270_snd_controls); i++) { + struct snd_kcontrol *kctrl = + snd_soc_cnew(&cs4270_snd_controls[i], codec, NULL); + + ret = snd_ctl_add(codec->card, kctrl); + if (ret < 0) + goto error; + } + + return 0; + +error: + if (codec->control_data) { + i2c_detach_client(i2c_client); + codec->control_data = NULL; + } + + kfree(codec->reg_cache); + codec->reg_cache = NULL; + codec->reg_cache_size = 0; + + kfree(i2c_client); + + return ret; +} + +#endif + +struct snd_soc_codec_dai cs4270_dai = { + .name = "CS4270", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = 0, + .formats = CS4270_FORMATS, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = 0, + .formats = CS4270_FORMATS, + }, + .dai_ops = { + .set_sysclk = cs4270_set_dai_sysclk, + .set_fmt = cs4270_set_dai_fmt, + } +}; +EXPORT_SYMBOL_GPL(cs4270_dai); + +/* + * ASoC probe function + * + * This function is called when the machine driver calls + * platform_device_add(). + */ +static int cs4270_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec; + int ret = 0; + + printk(KERN_INFO "CS4270 ALSA SoC Codec\n"); + + /* Allocate enough space for the snd_soc_codec structure + and our private data together. */ + codec = kzalloc(ALIGN(sizeof(struct snd_soc_codec), 4) + + sizeof(struct cs4270_private), GFP_KERNEL); + if (!codec) { + printk(KERN_ERR "cs4270: Could not allocate codec structure\n"); + return -ENOMEM; + } + + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + codec->name = "CS4270"; + codec->owner = THIS_MODULE; + codec->dai = &cs4270_dai; + codec->num_dai = 1; + codec->private_data = codec + ALIGN(sizeof(struct snd_soc_codec), 4); + + socdev->codec = codec; + + /* Register PCMs */ + + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + printk(KERN_ERR "cs4270: failed to create PCMs\n"); + return ret; + } + +#ifdef USE_I2C + cs4270_socdev = socdev; + + ret = i2c_add_driver(&cs4270_i2c_driver); + if (ret) { + printk(KERN_ERR "cs4270: failed to attach driver"); + snd_soc_free_pcms(socdev); + return ret; + } + + /* Did we find a CS4270 on the I2C bus? */ + if (codec->control_data) { + /* Initialize codec ops */ + cs4270_dai.ops.hw_params = cs4270_hw_params; +#ifdef CONFIG_SND_SOC_CS4270_HWMUTE + cs4270_dai.dai_ops.digital_mute = cs4270_mute; +#endif + } else + printk(KERN_INFO "cs4270: no I2C device found, " + "using stand-alone mode\n"); +#else + printk(KERN_INFO "cs4270: I2C disabled, using stand-alone mode\n"); +#endif + + ret = snd_soc_register_card(socdev); + if (ret < 0) { + printk(KERN_ERR "cs4270: failed to register card\n"); + snd_soc_free_pcms(socdev); + return ret; + } + + return ret; +} + +static int cs4270_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + + snd_soc_free_pcms(socdev); + +#ifdef USE_I2C + if (socdev->codec->control_data) + i2c_del_driver(&cs4270_i2c_driver); +#endif + + kfree(socdev->codec); + socdev->codec = NULL; + + return 0; +} + +/* + * ASoC codec device structure + * + * Assign this variable to the codec_dev field of the machine driver's + * snd_soc_device structure. + */ +struct snd_soc_codec_device soc_codec_device_cs4270 = { + .probe = cs4270_probe, + .remove = cs4270_remove +}; +EXPORT_SYMBOL_GPL(soc_codec_device_cs4270); + +MODULE_AUTHOR("Timur Tabi <timur@freescale.com>"); +MODULE_DESCRIPTION("Cirrus Logic CS4270 ALSA SoC Codec Driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs4270.h b/sound/soc/codecs/cs4270.h new file mode 100644 index 00000000000..0ced49b7804 --- /dev/null +++ b/sound/soc/codecs/cs4270.h @@ -0,0 +1,28 @@ +/* + * Cirrus Logic CS4270 ALSA SoC Codec Driver + * + * Author: Timur Tabi <timur@freescale.com> + * + * Copyright 2007 Freescale Semiconductor, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +#ifndef _CS4270_H +#define _CS4270_H + +/* + * The ASoC codec DAI structure for the CS4270. Assign this structure to + * the .codec_dai field of your machine driver's snd_soc_dai_link structure. + */ +extern struct snd_soc_codec_dai cs4270_dai; + +/* + * The ASoC codec device structure for the CS4270. Assign this structure + * to the .codec_dev field of your machine driver's snd_soc_device + * structure. + */ +extern struct snd_soc_codec_device soc_codec_device_cs4270; + +#endif diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c index 80e82109fef..4dd8f35312b 100644 --- a/sound/soc/pxa/spitz.c +++ b/sound/soc/pxa/spitz.c @@ -34,7 +34,6 @@ #include <asm/arch/hardware.h> #include <asm/arch/akita.h> #include <asm/arch/spitz.h> -#include <asm/mach-types.h> #include "../codecs/wm8750.h" #include "pxa2xx-pcm.h" #include "pxa2xx-i2s.h" diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig index e97c68306a9..5632a2e1518 100644 --- a/sound/soc/s3c24xx/Kconfig +++ b/sound/soc/s3c24xx/Kconfig @@ -18,7 +18,7 @@ config SND_S3C2443_SOC_AC97 config SND_S3C24XX_SOC_NEO1973_WM8753 tristate "SoC I2S Audio support for NEO1973 - WM8753" - depends on SND_S3C24XX_SOC && MACH_GTA01 + depends on SND_S3C24XX_SOC && MACH_NEO1973_GTA01 select SND_S3C24XX_SOC_I2S select SND_SOC_WM8753 help diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c index 39f02462e07..cd89c4105fc 100644 --- a/sound/soc/s3c24xx/s3c24xx-i2s.c +++ b/sound/soc/s3c24xx/s3c24xx-i2s.c @@ -385,6 +385,7 @@ static int s3c24xx_i2s_probe(struct platform_device *pdev) s3c24xx_i2s.iis_clk=clk_get(&pdev->dev, "iis"); if (s3c24xx_i2s.iis_clk == NULL) { DBG("failed to get iis_clock\n"); + iounmap(s3c24xx_i2s.regs); return -ENODEV; } clk_enable(s3c24xx_i2s.iis_clk); diff --git a/sound/soc/s3c24xx/s3c24xx-pcm.c b/sound/soc/s3c24xx/s3c24xx-pcm.c index bfbdc3cbd43..4107a87d4de 100644 --- a/sound/soc/s3c24xx/s3c24xx-pcm.c +++ b/sound/soc/s3c24xx/s3c24xx-pcm.c @@ -158,18 +158,22 @@ static int s3c24xx_pcm_hw_params(struct snd_pcm_substream *substream, if (!dma) return 0; - /* prepare DMA */ - prtd->params = dma; + /* this may get called several times by oss emulation + * with different params -HW */ + if (prtd->params == NULL) { + /* prepare DMA */ + prtd->params = dma; - DBG("params %p, client %p, channel %d\n", prtd->params, - prtd->params->client, prtd->params->channel); + DBG("params %p, client %p, channel %d\n", prtd->params, + prtd->params->client, prtd->params->channel); - ret = s3c2410_dma_request(prtd->params->channel, - prtd->params->client, NULL); + ret = s3c2410_dma_request(prtd->params->channel, + prtd->params->client, NULL); - if (ret) { - DBG(KERN_ERR "failed to get dma channel\n"); - return ret; + if (ret) { + DBG(KERN_ERR "failed to get dma channel\n"); + return ret; + } } /* channel needs configuring for mem=>device, increment memory addr, diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 92d5d917b73..91651bdfa76 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1362,26 +1362,6 @@ int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol, EXPORT_SYMBOL_GPL(snd_soc_info_volsw_ext); /** - * snd_soc_info_bool_ext - external single boolean mixer info callback - * @kcontrol: mixer control - * @uinfo: control element information - * - * Callback to provide information about a single boolean external mixer control. - * - * Returns 0 for success. - */ -int snd_soc_info_bool_ext(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; -} -EXPORT_SYMBOL_GPL(snd_soc_info_bool_ext); - -/** * snd_soc_info_volsw - single mixer info callback * @kcontrol: mixer control * @uinfo: control element information diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 96bce55572a..b3193e687db 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -63,7 +63,7 @@ #define POP_DEBUG 0 #if POP_DEBUG #define POP_TIME 500 /* 500 msecs - change if pop debug is too fast */ -#define pop_wait(time) schedule_timeout_interruptible(msecs_to_jiffies(time)) +#define pop_wait(time) schedule_timeout_uninterruptible(msecs_to_jiffies(time)) #define pop_dbg(format, arg...) printk(format, ## arg); pop_wait(POP_TIME) #else #define pop_dbg(format, arg...) diff --git a/sound/sparc/cs4231.c b/sound/sparc/cs4231.c index f2950cab74a..9785382a5f3 100644 --- a/sound/sparc/cs4231.c +++ b/sound/sparc/cs4231.c @@ -3,9 +3,9 @@ * Copyright (C) 2002 David S. Miller <davem@redhat.com> * * Based entirely upon drivers/sbus/audio/cs4231.c which is: - * Copyright (C) 1996, 1997, 1998, 1998 Derrick J Brashear (shadow@andrew.cmu.edu) + * Copyright (C) 1996, 1997, 1998 Derrick J Brashear (shadow@andrew.cmu.edu) * and also sound/isa/cs423x/cs4231_lib.c which is: - * Copyright (c) by Jaroslav Kysela <perex@suse.cz> + * Copyright (c) by Jaroslav Kysela <perex@perex.cz> */ #include <linux/module.h> @@ -15,6 +15,9 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/moduleparam.h> +#include <linux/irq.h> +#include <linux/io.h> + #include <sound/driver.h> #include <sound/core.h> @@ -25,29 +28,21 @@ #include <sound/initval.h> #include <sound/pcm_params.h> -#include <asm/io.h> -#include <asm/irq.h> - #ifdef CONFIG_SBUS #define SBUS_SUPPORT -#endif - -#ifdef SBUS_SUPPORT #include <asm/sbus.h> #endif #if defined(CONFIG_PCI) && defined(CONFIG_SPARC64) #define EBUS_SUPPORT -#endif - -#ifdef EBUS_SUPPORT #include <linux/pci.h> #include <asm/ebus.h> #endif 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_PNP; /* Enable this card */ +/* Enable this card */ +static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; module_param_array(index, int, NULL, 0444); MODULE_PARM_DESC(index, "Index value for Sun CS4231 soundcard."); @@ -62,19 +57,22 @@ MODULE_SUPPORTED_DEVICE("{{Sun,CS4231}}"); #ifdef SBUS_SUPPORT struct sbus_dma_info { - spinlock_t lock; - int dir; - void __iomem *regs; + spinlock_t lock; /* DMA access lock */ + int dir; + void __iomem *regs; }; #endif struct snd_cs4231; struct cs4231_dma_control { - void (*prepare)(struct cs4231_dma_control *dma_cont, int dir); - void (*enable)(struct cs4231_dma_control *dma_cont, int on); - int (*request)(struct cs4231_dma_control *dma_cont, dma_addr_t bus_addr, size_t len); - unsigned int (*address)(struct cs4231_dma_control *dma_cont); - void (*preallocate)(struct snd_cs4231 *chip, struct snd_pcm *pcm); + void (*prepare)(struct cs4231_dma_control *dma_cont, + int dir); + void (*enable)(struct cs4231_dma_control *dma_cont, int on); + int (*request)(struct cs4231_dma_control *dma_cont, + dma_addr_t bus_addr, size_t len); + unsigned int (*address)(struct cs4231_dma_control *dma_cont); + void (*preallocate)(struct snd_cs4231 *chip, + struct snd_pcm *pcm); #ifdef EBUS_SUPPORT struct ebus_dma_info ebus_info; #endif @@ -84,7 +82,7 @@ struct cs4231_dma_control { }; struct snd_cs4231 { - spinlock_t lock; + spinlock_t lock; /* registers access lock */ void __iomem *port; struct cs4231_dma_control p_dma; @@ -108,13 +106,14 @@ struct snd_cs4231 { #define CS4231_MODE_PLAY 0x0001 #define CS4231_MODE_RECORD 0x0002 #define CS4231_MODE_TIMER 0x0004 -#define CS4231_MODE_OPEN (CS4231_MODE_PLAY|CS4231_MODE_RECORD|CS4231_MODE_TIMER) +#define CS4231_MODE_OPEN (CS4231_MODE_PLAY | CS4231_MODE_RECORD | \ + CS4231_MODE_TIMER) unsigned char image[32]; /* registers image */ int mce_bit; int calibrate_mute; - struct mutex mce_mutex; - struct mutex open_mutex; + struct mutex mce_mutex; /* mutex for mce register */ + struct mutex open_mutex; /* mutex for ALSA open/close */ union { #ifdef SBUS_SUPPORT @@ -136,129 +135,10 @@ static struct snd_cs4231 *cs4231_list; */ /* IO ports */ - -#define CS4231P(chip, x) ((chip)->port + c_d_c_CS4231##x) +#include <sound/cs4231-regs.h> /* XXX offsets are different than PC ISA chips... */ -#define c_d_c_CS4231REGSEL 0x0 -#define c_d_c_CS4231REG 0x4 -#define c_d_c_CS4231STATUS 0x8 -#define c_d_c_CS4231PIO 0xc - -/* codec registers */ - -#define CS4231_LEFT_INPUT 0x00 /* left input control */ -#define CS4231_RIGHT_INPUT 0x01 /* right input control */ -#define CS4231_AUX1_LEFT_INPUT 0x02 /* left AUX1 input control */ -#define CS4231_AUX1_RIGHT_INPUT 0x03 /* right AUX1 input control */ -#define CS4231_AUX2_LEFT_INPUT 0x04 /* left AUX2 input control */ -#define CS4231_AUX2_RIGHT_INPUT 0x05 /* right AUX2 input control */ -#define CS4231_LEFT_OUTPUT 0x06 /* left output control register */ -#define CS4231_RIGHT_OUTPUT 0x07 /* right output control register */ -#define CS4231_PLAYBK_FORMAT 0x08 /* clock and data format - playback - bits 7-0 MCE */ -#define CS4231_IFACE_CTRL 0x09 /* interface control - bits 7-2 MCE */ -#define CS4231_PIN_CTRL 0x0a /* pin control */ -#define CS4231_TEST_INIT 0x0b /* test and initialization */ -#define CS4231_MISC_INFO 0x0c /* miscellaneaous information */ -#define CS4231_LOOPBACK 0x0d /* loopback control */ -#define CS4231_PLY_UPR_CNT 0x0e /* playback upper base count */ -#define CS4231_PLY_LWR_CNT 0x0f /* playback lower base count */ -#define CS4231_ALT_FEATURE_1 0x10 /* alternate #1 feature enable */ -#define CS4231_ALT_FEATURE_2 0x11 /* alternate #2 feature enable */ -#define CS4231_LEFT_LINE_IN 0x12 /* left line input control */ -#define CS4231_RIGHT_LINE_IN 0x13 /* right line input control */ -#define CS4231_TIMER_LOW 0x14 /* timer low byte */ -#define CS4231_TIMER_HIGH 0x15 /* timer high byte */ -#define CS4231_LEFT_MIC_INPUT 0x16 /* left MIC input control register (InterWave only) */ -#define CS4231_RIGHT_MIC_INPUT 0x17 /* right MIC input control register (InterWave only) */ -#define CS4236_EXT_REG 0x17 /* extended register access */ -#define CS4231_IRQ_STATUS 0x18 /* irq status register */ -#define CS4231_LINE_LEFT_OUTPUT 0x19 /* left line output control register (InterWave only) */ -#define CS4231_VERSION 0x19 /* CS4231(A) - version values */ -#define CS4231_MONO_CTRL 0x1a /* mono input/output control */ -#define CS4231_LINE_RIGHT_OUTPUT 0x1b /* right line output control register (InterWave only) */ -#define CS4235_LEFT_MASTER 0x1b /* left master output control */ -#define CS4231_REC_FORMAT 0x1c /* clock and data format - record - bits 7-0 MCE */ -#define CS4231_PLY_VAR_FREQ 0x1d /* playback variable frequency */ -#define CS4235_RIGHT_MASTER 0x1d /* right master output control */ -#define CS4231_REC_UPR_CNT 0x1e /* record upper count */ -#define CS4231_REC_LWR_CNT 0x1f /* record lower count */ - -/* definitions for codec register select port - CODECP( REGSEL ) */ - -#define CS4231_INIT 0x80 /* CODEC is initializing */ -#define CS4231_MCE 0x40 /* mode change enable */ -#define CS4231_TRD 0x20 /* transfer request disable */ - -/* definitions for codec status register - CODECP( STATUS ) */ - -#define CS4231_GLOBALIRQ 0x01 /* IRQ is active */ - -/* definitions for codec irq status - CS4231_IRQ_STATUS */ - -#define CS4231_PLAYBACK_IRQ 0x10 -#define CS4231_RECORD_IRQ 0x20 -#define CS4231_TIMER_IRQ 0x40 -#define CS4231_ALL_IRQS 0x70 -#define CS4231_REC_UNDERRUN 0x08 -#define CS4231_REC_OVERRUN 0x04 -#define CS4231_PLY_OVERRUN 0x02 -#define CS4231_PLY_UNDERRUN 0x01 - -/* definitions for CS4231_LEFT_INPUT and CS4231_RIGHT_INPUT registers */ - -#define CS4231_ENABLE_MIC_GAIN 0x20 - -#define CS4231_MIXS_LINE 0x00 -#define CS4231_MIXS_AUX1 0x40 -#define CS4231_MIXS_MIC 0x80 -#define CS4231_MIXS_ALL 0xc0 - -/* definitions for clock and data format register - CS4231_PLAYBK_FORMAT */ - -#define CS4231_LINEAR_8 0x00 /* 8-bit unsigned data */ -#define CS4231_ALAW_8 0x60 /* 8-bit A-law companded */ -#define CS4231_ULAW_8 0x20 /* 8-bit U-law companded */ -#define CS4231_LINEAR_16 0x40 /* 16-bit twos complement data - little endian */ -#define CS4231_LINEAR_16_BIG 0xc0 /* 16-bit twos complement data - big endian */ -#define CS4231_ADPCM_16 0xa0 /* 16-bit ADPCM */ -#define CS4231_STEREO 0x10 /* stereo mode */ -/* bits 3-1 define frequency divisor */ -#define CS4231_XTAL1 0x00 /* 24.576 crystal */ -#define CS4231_XTAL2 0x01 /* 16.9344 crystal */ - -/* definitions for interface control register - CS4231_IFACE_CTRL */ - -#define CS4231_RECORD_PIO 0x80 /* record PIO enable */ -#define CS4231_PLAYBACK_PIO 0x40 /* playback PIO enable */ -#define CS4231_CALIB_MODE 0x18 /* calibration mode bits */ -#define CS4231_AUTOCALIB 0x08 /* auto calibrate */ -#define CS4231_SINGLE_DMA 0x04 /* use single DMA channel */ -#define CS4231_RECORD_ENABLE 0x02 /* record enable */ -#define CS4231_PLAYBACK_ENABLE 0x01 /* playback enable */ - -/* definitions for pin control register - CS4231_PIN_CTRL */ - -#define CS4231_IRQ_ENABLE 0x02 /* enable IRQ */ -#define CS4231_XCTL1 0x40 /* external control #1 */ -#define CS4231_XCTL0 0x80 /* external control #0 */ - -/* definitions for test and init register - CS4231_TEST_INIT */ - -#define CS4231_CALIB_IN_PROGRESS 0x20 /* auto calibrate in progress */ -#define CS4231_DMA_REQUEST 0x10 /* DMA request in progress */ - -/* definitions for misc control register - CS4231_MISC_INFO */ - -#define CS4231_MODE2 0x40 /* MODE 2 */ -#define CS4231_IW_MODE3 0x6c /* MODE 3 - InterWave enhanced mode */ -#define CS4231_4236_MODE3 0xe0 /* MODE 3 - CS4236+ enhanced mode */ - -/* definitions for alternate feature 1 register - CS4231_ALT_FEATURE_1 */ - -#define CS4231_DACZ 0x01 /* zero DAC when underrun */ -#define CS4231_TIMER_ENABLE 0x40 /* codec timer enable */ -#define CS4231_OLB 0x80 /* output level bit */ +#define CS4231U(chip, x) ((chip)->port + ((c_d_c_CS4231##x) << 2)) /* SBUS DMA register defines. */ @@ -339,7 +219,7 @@ static unsigned int rates[14] = { }; static struct snd_pcm_hw_constraint_list hw_constraints_rates = { - .count = 14, + .count = ARRAY_SIZE(rates), .list = rates, }; @@ -389,116 +269,89 @@ static unsigned char snd_cs4231_original_image[32] = static u8 __cs4231_readb(struct snd_cs4231 *cp, void __iomem *reg_addr) { #ifdef EBUS_SUPPORT - if (cp->flags & CS4231_FLAG_EBUS) { + if (cp->flags & CS4231_FLAG_EBUS) return readb(reg_addr); - } else { + else #endif #ifdef SBUS_SUPPORT return sbus_readb(reg_addr); #endif -#ifdef EBUS_SUPPORT - } -#endif } -static void __cs4231_writeb(struct snd_cs4231 *cp, u8 val, void __iomem *reg_addr) +static void __cs4231_writeb(struct snd_cs4231 *cp, u8 val, + void __iomem *reg_addr) { #ifdef EBUS_SUPPORT - if (cp->flags & CS4231_FLAG_EBUS) { + if (cp->flags & CS4231_FLAG_EBUS) return writeb(val, reg_addr); - } else { + else #endif #ifdef SBUS_SUPPORT return sbus_writeb(val, reg_addr); #endif -#ifdef EBUS_SUPPORT - } -#endif } /* * Basic I/O functions */ -static void snd_cs4231_outm(struct snd_cs4231 *chip, unsigned char reg, - unsigned char mask, unsigned char value) +static void snd_cs4231_ready(struct snd_cs4231 *chip) { int timeout; - unsigned char tmp; - for (timeout = 250; - timeout > 0 && (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT); - timeout--) - udelay(100); -#ifdef CONFIG_SND_DEBUG - if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT) - snd_printdd("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 { - __cs4231_writeb(chip, chip->mce_bit | reg, CS4231P(chip, REGSEL)); - mb(); - tmp = (chip->image[reg] & mask) | value; - __cs4231_writeb(chip, tmp, CS4231P(chip, REG)); - chip->image[reg] = tmp; - mb(); + for (timeout = 250; timeout > 0; timeout--) { + int val = __cs4231_readb(chip, CS4231U(chip, REGSEL)); + if ((val & CS4231_INIT) == 0) + break; + udelay(100); } } -static void snd_cs4231_dout(struct snd_cs4231 *chip, unsigned char reg, unsigned char value) +static void snd_cs4231_dout(struct snd_cs4231 *chip, unsigned char reg, + unsigned char value) { - int timeout; - - for (timeout = 250; - timeout > 0 && (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT); - timeout--) - udelay(100); + snd_cs4231_ready(chip); #ifdef CONFIG_SND_DEBUG - if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT) - snd_printdd("out: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value); + if (__cs4231_readb(chip, CS4231U(chip, REGSEL)) & CS4231_INIT) + snd_printdd("out: auto calibration time out - reg = 0x%x, " + "value = 0x%x\n", + reg, value); #endif - __cs4231_writeb(chip, chip->mce_bit | reg, CS4231P(chip, REGSEL)); - __cs4231_writeb(chip, value, CS4231P(chip, REG)); + __cs4231_writeb(chip, chip->mce_bit | reg, CS4231U(chip, REGSEL)); + wmb(); + __cs4231_writeb(chip, value, CS4231U(chip, REG)); mb(); } -static void snd_cs4231_out(struct snd_cs4231 *chip, unsigned char reg, unsigned char value) +static inline void snd_cs4231_outm(struct snd_cs4231 *chip, unsigned char reg, + unsigned char mask, unsigned char value) { - int timeout; + unsigned char tmp = (chip->image[reg] & mask) | value; - for (timeout = 250; - timeout > 0 && (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT); - timeout--) - udelay(100); -#ifdef CONFIG_SND_DEBUG - if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT) - snd_printdd("out: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value); -#endif - __cs4231_writeb(chip, chip->mce_bit | reg, CS4231P(chip, REGSEL)); - __cs4231_writeb(chip, value, CS4231P(chip, REG)); + chip->image[reg] = tmp; + if (!chip->calibrate_mute) + snd_cs4231_dout(chip, reg, tmp); +} + +static void snd_cs4231_out(struct snd_cs4231 *chip, unsigned char reg, + unsigned char value) +{ + snd_cs4231_dout(chip, reg, value); chip->image[reg] = value; mb(); } static unsigned char snd_cs4231_in(struct snd_cs4231 *chip, unsigned char reg) { - int timeout; - unsigned char ret; - - for (timeout = 250; - timeout > 0 && (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT); - timeout--) - udelay(100); + snd_cs4231_ready(chip); #ifdef CONFIG_SND_DEBUG - if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT) - snd_printdd("in: auto calibration time out - reg = 0x%x\n", reg); + if (__cs4231_readb(chip, CS4231U(chip, REGSEL)) & CS4231_INIT) + snd_printdd("in: auto calibration time out - reg = 0x%x\n", + reg); #endif - __cs4231_writeb(chip, chip->mce_bit | reg, CS4231P(chip, REGSEL)); + __cs4231_writeb(chip, chip->mce_bit | reg, CS4231U(chip, REGSEL)); mb(); - ret = __cs4231_readb(chip, CS4231P(chip, REG)); - return ret; + return __cs4231_readb(chip, CS4231U(chip, REG)); } /* @@ -509,15 +362,17 @@ static void snd_cs4231_busy_wait(struct snd_cs4231 *chip) { int timeout; - /* huh.. looks like this sequence is proper for CS4231A chip (GUS MAX) */ + /* looks like this sequence is proper for CS4231A chip (GUS MAX) */ for (timeout = 5; timeout > 0; timeout--) - __cs4231_readb(chip, CS4231P(chip, REGSEL)); + __cs4231_readb(chip, CS4231U(chip, REGSEL)); /* end of cleanup sequence */ - for (timeout = 500; - timeout > 0 && (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT); - timeout--) - udelay(1000); + for (timeout = 500; timeout > 0; timeout--) { + int val = __cs4231_readb(chip, CS4231U(chip, REGSEL)); + if ((val & CS4231_INIT) == 0) + break; + msleep(1); + } } static void snd_cs4231_mce_up(struct snd_cs4231 *chip) @@ -526,74 +381,81 @@ static void snd_cs4231_mce_up(struct snd_cs4231 *chip) int timeout; spin_lock_irqsave(&chip->lock, flags); - for (timeout = 250; timeout > 0 && (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT); timeout--) - udelay(100); + snd_cs4231_ready(chip); #ifdef CONFIG_SND_DEBUG - if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT) + if (__cs4231_readb(chip, CS4231U(chip, REGSEL)) & CS4231_INIT) snd_printdd("mce_up - auto calibration time out (0)\n"); #endif chip->mce_bit |= CS4231_MCE; - timeout = __cs4231_readb(chip, CS4231P(chip, REGSEL)); + timeout = __cs4231_readb(chip, CS4231U(chip, REGSEL)); if (timeout == 0x80) - snd_printdd("mce_up [%p]: serious init problem - codec still busy\n", chip->port); + snd_printdd("mce_up [%p]: serious init problem - " + "codec still busy\n", + chip->port); if (!(timeout & CS4231_MCE)) - __cs4231_writeb(chip, chip->mce_bit | (timeout & 0x1f), CS4231P(chip, REGSEL)); + __cs4231_writeb(chip, chip->mce_bit | (timeout & 0x1f), + CS4231U(chip, REGSEL)); spin_unlock_irqrestore(&chip->lock, flags); } static void snd_cs4231_mce_down(struct snd_cs4231 *chip) { unsigned long flags; + unsigned long end_time; int timeout; spin_lock_irqsave(&chip->lock, flags); snd_cs4231_busy_wait(chip); #ifdef CONFIG_SND_DEBUG - if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT) - snd_printdd("mce_down [%p] - auto calibration time out (0)\n", CS4231P(chip, REGSEL)); + if (__cs4231_readb(chip, CS4231U(chip, REGSEL)) & CS4231_INIT) + snd_printdd("mce_down [%p] - auto calibration time out (0)\n", + CS4231U(chip, REGSEL)); #endif chip->mce_bit &= ~CS4231_MCE; - timeout = __cs4231_readb(chip, CS4231P(chip, REGSEL)); - __cs4231_writeb(chip, chip->mce_bit | (timeout & 0x1f), CS4231P(chip, REGSEL)); + timeout = __cs4231_readb(chip, CS4231U(chip, REGSEL)); + __cs4231_writeb(chip, chip->mce_bit | (timeout & 0x1f), + CS4231U(chip, REGSEL)); if (timeout == 0x80) - snd_printdd("mce_down [%p]: serious init problem - codec still busy\n", chip->port); + snd_printdd("mce_down [%p]: serious init problem - " + "codec still busy\n", + chip->port); if ((timeout & CS4231_MCE) == 0) { spin_unlock_irqrestore(&chip->lock, flags); return; } - 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(100); - if ((snd_cs4231_in(chip, CS4231_TEST_INIT) & CS4231_CALIB_IN_PROGRESS) == 0) { - snd_printd("cs4231_mce_down - auto calibration time out (1)\n"); - spin_unlock_irqrestore(&chip->lock, flags); - return; - } + /* check condition up to 250ms */ + end_time = jiffies + msecs_to_jiffies(250); + while (snd_cs4231_in(chip, CS4231_TEST_INIT) & + CS4231_CALIB_IN_PROGRESS) { - /* in 10ms increments, check condition, up to 250ms */ - timeout = 25; - while (snd_cs4231_in(chip, CS4231_TEST_INIT) & CS4231_CALIB_IN_PROGRESS) { spin_unlock_irqrestore(&chip->lock, flags); - if (--timeout < 0) { - snd_printk("mce_down - auto calibration time out (2)\n"); + if (time_after(jiffies, end_time)) { + snd_printk("mce_down - " + "auto calibration time out (2)\n"); return; } - msleep(10); + msleep(1); spin_lock_irqsave(&chip->lock, flags); } - /* in 10ms increments, check condition, up to 100ms */ - timeout = 10; - while (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT) { + /* check condition up to 100ms */ + end_time = jiffies + msecs_to_jiffies(100); + while (__cs4231_readb(chip, CS4231U(chip, REGSEL)) & CS4231_INIT) { spin_unlock_irqrestore(&chip->lock, flags); - if (--timeout < 0) { - snd_printk("mce_down - auto calibration time out (3)\n"); + if (time_after(jiffies, end_time)) { + snd_printk("mce_down - " + "auto calibration time out (3)\n"); return; } - msleep(10); + msleep(1); spin_lock_irqsave(&chip->lock, flags); } spin_unlock_irqrestore(&chip->lock, flags); @@ -611,7 +473,8 @@ static void snd_cs4231_advance_dma(struct cs4231_dma_control *dma_cont, BUG_ON(period_size >= (1 << 24)); - if (dma_cont->request(dma_cont, runtime->dma_addr + offset, period_size)) + if (dma_cont->request(dma_cont, + runtime->dma_addr + offset, period_size)) return; (*periods_sent) = ((*periods_sent) + 1) % runtime->periods; } @@ -704,21 +567,32 @@ static unsigned char snd_cs4231_get_rate(unsigned int rate) for (i = 0; i < 14; i++) if (rate == rates[i]) return freq_bits[i]; - // snd_BUG(); + return freq_bits[13]; } -static unsigned char snd_cs4231_get_format(struct snd_cs4231 *chip, int format, int channels) +static unsigned char snd_cs4231_get_format(struct snd_cs4231 *chip, int format, + int channels) { unsigned char rformat; rformat = CS4231_LINEAR_8; switch (format) { - case SNDRV_PCM_FORMAT_MU_LAW: rformat = CS4231_ULAW_8; break; - case SNDRV_PCM_FORMAT_A_LAW: rformat = CS4231_ALAW_8; break; - case SNDRV_PCM_FORMAT_S16_LE: rformat = CS4231_LINEAR_16; break; - case SNDRV_PCM_FORMAT_S16_BE: rformat = CS4231_LINEAR_16_BIG; break; - case SNDRV_PCM_FORMAT_IMA_ADPCM: rformat = CS4231_ADPCM_16; break; + case SNDRV_PCM_FORMAT_MU_LAW: + rformat = CS4231_ULAW_8; + break; + case SNDRV_PCM_FORMAT_A_LAW: + rformat = CS4231_ALAW_8; + break; + case SNDRV_PCM_FORMAT_S16_LE: + rformat = CS4231_LINEAR_16; + break; + case SNDRV_PCM_FORMAT_S16_BE: + rformat = CS4231_LINEAR_16_BIG; + break; + case SNDRV_PCM_FORMAT_IMA_ADPCM: + rformat = CS4231_ADPCM_16; + break; } if (channels > 1) rformat |= CS4231_STEREO; @@ -765,7 +639,8 @@ static void snd_cs4231_calibrate_mute(struct snd_cs4231 *chip, int mute) spin_unlock_irqrestore(&chip->lock, flags); } -static void snd_cs4231_playback_format(struct snd_cs4231 *chip, struct snd_pcm_hw_params *params, +static void snd_cs4231_playback_format(struct snd_cs4231 *chip, + struct snd_pcm_hw_params *params, unsigned char pdfr) { unsigned long flags; @@ -788,8 +663,9 @@ static void snd_cs4231_playback_format(struct snd_cs4231 *chip, struct snd_pcm_h mutex_unlock(&chip->mce_mutex); } -static void snd_cs4231_capture_format(struct snd_cs4231 *chip, struct snd_pcm_hw_params *params, - unsigned char cdfr) +static void snd_cs4231_capture_format(struct snd_cs4231 *chip, + struct snd_pcm_hw_params *params, + unsigned char cdfr) { unsigned long flags; @@ -846,7 +722,8 @@ static int snd_cs4231_timer_start(struct snd_timer *timer) chip->image[CS4231_TIMER_LOW] = (unsigned char) ticks); snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, - chip->image[CS4231_ALT_FEATURE_1] | CS4231_TIMER_ENABLE); + chip->image[CS4231_ALT_FEATURE_1] | + CS4231_TIMER_ENABLE); } spin_unlock_irqrestore(&chip->lock, flags); @@ -859,8 +736,9 @@ static int snd_cs4231_timer_stop(struct snd_timer *timer) struct snd_cs4231 *chip = snd_timer_chip(timer); spin_lock_irqsave(&chip->lock, flags); + chip->image[CS4231_ALT_FEATURE_1] &= ~CS4231_TIMER_ENABLE; snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, - chip->image[CS4231_ALT_FEATURE_1] &= ~CS4231_TIMER_ENABLE); + chip->image[CS4231_ALT_FEATURE_1]); spin_unlock_irqrestore(&chip->lock, flags); return 0; @@ -877,8 +755,10 @@ static void __init snd_cs4231_init(struct snd_cs4231 *chip) #endif snd_cs4231_mce_up(chip); spin_lock_irqsave(&chip->lock, flags); - chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO | - CS4231_RECORD_ENABLE | CS4231_RECORD_PIO | + chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE | + CS4231_PLAYBACK_PIO | + CS4231_RECORD_ENABLE | + CS4231_RECORD_PIO | CS4231_CALIB_MODE); chip->image[CS4231_IFACE_CTRL] |= CS4231_AUTOCALIB; snd_cs4231_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]); @@ -891,21 +771,25 @@ static void __init snd_cs4231_init(struct snd_cs4231 *chip) snd_cs4231_mce_up(chip); spin_lock_irqsave(&chip->lock, flags); - snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1]); + snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, + chip->image[CS4231_ALT_FEATURE_1]); spin_unlock_irqrestore(&chip->lock, flags); snd_cs4231_mce_down(chip); #ifdef SNDRV_DEBUG_MCE - snd_printdd("init: (3) - afei = 0x%x\n", chip->image[CS4231_ALT_FEATURE_1]); + snd_printdd("init: (3) - afei = 0x%x\n", + chip->image[CS4231_ALT_FEATURE_1]); #endif spin_lock_irqsave(&chip->lock, flags); - snd_cs4231_out(chip, CS4231_ALT_FEATURE_2, chip->image[CS4231_ALT_FEATURE_2]); + snd_cs4231_out(chip, CS4231_ALT_FEATURE_2, + chip->image[CS4231_ALT_FEATURE_2]); spin_unlock_irqrestore(&chip->lock, flags); snd_cs4231_mce_up(chip); spin_lock_irqsave(&chip->lock, flags); - snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT, chip->image[CS4231_PLAYBK_FORMAT]); + snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT, + chip->image[CS4231_PLAYBK_FORMAT]); spin_unlock_irqrestore(&chip->lock, flags); snd_cs4231_mce_down(chip); @@ -944,8 +828,8 @@ static int snd_cs4231_open(struct snd_cs4231 *chip, unsigned int mode) CS4231_RECORD_IRQ | CS4231_TIMER_IRQ); snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0); - __cs4231_writeb(chip, 0, CS4231P(chip, STATUS)); /* clear IRQ */ - __cs4231_writeb(chip, 0, CS4231P(chip, STATUS)); /* clear IRQ */ + __cs4231_writeb(chip, 0, CS4231U(chip, STATUS)); /* clear IRQ */ + __cs4231_writeb(chip, 0, CS4231U(chip, STATUS)); /* clear IRQ */ snd_cs4231_out(chip, CS4231_IRQ_STATUS, CS4231_PLAYBACK_IRQ | CS4231_RECORD_IRQ | @@ -974,8 +858,8 @@ static void snd_cs4231_close(struct snd_cs4231 *chip, unsigned int mode) /* disable IRQ */ spin_lock_irqsave(&chip->lock, flags); snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0); - __cs4231_writeb(chip, 0, CS4231P(chip, STATUS)); /* clear IRQ */ - __cs4231_writeb(chip, 0, CS4231P(chip, STATUS)); /* clear IRQ */ + __cs4231_writeb(chip, 0, CS4231U(chip, STATUS)); /* clear IRQ */ + __cs4231_writeb(chip, 0, CS4231U(chip, STATUS)); /* clear IRQ */ /* now disable record & playback */ @@ -988,7 +872,8 @@ static void snd_cs4231_close(struct snd_cs4231 *chip, unsigned int mode) chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO | CS4231_RECORD_ENABLE | CS4231_RECORD_PIO); - snd_cs4231_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]); + snd_cs4231_out(chip, CS4231_IFACE_CTRL, + chip->image[CS4231_IFACE_CTRL]); spin_unlock_irqrestore(&chip->lock, flags); snd_cs4231_mce_down(chip); spin_lock_irqsave(&chip->lock, flags); @@ -996,8 +881,8 @@ static void snd_cs4231_close(struct snd_cs4231 *chip, unsigned int mode) /* clear IRQ again */ snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0); - __cs4231_writeb(chip, 0, CS4231P(chip, STATUS)); /* clear IRQ */ - __cs4231_writeb(chip, 0, CS4231P(chip, STATUS)); /* clear IRQ */ + __cs4231_writeb(chip, 0, CS4231U(chip, STATUS)); /* clear IRQ */ + __cs4231_writeb(chip, 0, CS4231U(chip, STATUS)); /* clear IRQ */ spin_unlock_irqrestore(&chip->lock, flags); snd_cs4231_calibrate_mute(chip, 0); @@ -1017,15 +902,14 @@ static int snd_cs4231_timer_open(struct snd_timer *timer) return 0; } -static int snd_cs4231_timer_close(struct snd_timer * timer) +static int snd_cs4231_timer_close(struct snd_timer *timer) { struct snd_cs4231 *chip = snd_timer_chip(timer); snd_cs4231_close(chip, CS4231_MODE_TIMER); return 0; } -static struct snd_timer_hardware snd_cs4231_timer_table = -{ +static struct snd_timer_hardware snd_cs4231_timer_table = { .flags = SNDRV_TIMER_HW_AUTO, .resolution = 9945, .ticks = 65535, @@ -1047,8 +931,9 @@ static int snd_cs4231_playback_hw_params(struct snd_pcm_substream *substream, unsigned char new_pdfr; int err; - if ((err = snd_pcm_lib_malloc_pages(substream, - params_buffer_bytes(hw_params))) < 0) + err = snd_pcm_lib_malloc_pages(substream, + params_buffer_bytes(hw_params)); + if (err < 0) return err; new_pdfr = snd_cs4231_get_format(chip, params_format(hw_params), params_channels(hw_params)) | @@ -1058,11 +943,6 @@ static int snd_cs4231_playback_hw_params(struct snd_pcm_substream *substream, return 0; } -static int snd_cs4231_playback_hw_free(struct snd_pcm_substream *substream) -{ - return snd_pcm_lib_free_pages(substream); -} - static int snd_cs4231_playback_prepare(struct snd_pcm_substream *substream) { struct snd_cs4231 *chip = snd_pcm_substream_chip(substream); @@ -1089,8 +969,9 @@ static int snd_cs4231_capture_hw_params(struct snd_pcm_substream *substream, unsigned char new_cdfr; int err; - if ((err = snd_pcm_lib_malloc_pages(substream, - params_buffer_bytes(hw_params))) < 0) + err = snd_pcm_lib_malloc_pages(substream, + params_buffer_bytes(hw_params)); + if (err < 0) return err; new_cdfr = snd_cs4231_get_format(chip, params_format(hw_params), params_channels(hw_params)) | @@ -1100,11 +981,6 @@ static int snd_cs4231_capture_hw_params(struct snd_pcm_substream *substream, return 0; } -static int snd_cs4231_capture_hw_free(struct snd_pcm_substream *substream) -{ - return snd_pcm_lib_free_pages(substream); -} - static int snd_cs4231_capture_prepare(struct snd_pcm_substream *substream) { struct snd_cs4231 *chip = snd_pcm_substream_chip(substream); @@ -1130,7 +1006,8 @@ static void snd_cs4231_overrange(struct snd_cs4231 *chip) res = snd_cs4231_in(chip, CS4231_TEST_INIT); spin_unlock_irqrestore(&chip->lock, flags); - if (res & (0x08 | 0x02)) /* detect overrange only above 0dB; may be user selectable? */ + /* detect overrange only above 0dB; may be user selectable? */ + if (res & (0x08 | 0x02)) chip->capture_substream->runtime->overrange++; } @@ -1152,51 +1029,50 @@ static void snd_cs4231_capture_callback(struct snd_cs4231 *chip) } } -static snd_pcm_uframes_t snd_cs4231_playback_pointer(struct snd_pcm_substream *substream) +static snd_pcm_uframes_t snd_cs4231_playback_pointer( + struct snd_pcm_substream *substream) { struct snd_cs4231 *chip = snd_pcm_substream_chip(substream); struct cs4231_dma_control *dma_cont = &chip->p_dma; size_t ptr; - + if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE)) return 0; ptr = dma_cont->address(dma_cont); if (ptr != 0) ptr -= substream->runtime->dma_addr; - + return bytes_to_frames(substream->runtime, ptr); } -static snd_pcm_uframes_t snd_cs4231_capture_pointer(struct snd_pcm_substream *substream) +static snd_pcm_uframes_t snd_cs4231_capture_pointer( + struct snd_pcm_substream *substream) { struct snd_cs4231 *chip = snd_pcm_substream_chip(substream); struct cs4231_dma_control *dma_cont = &chip->c_dma; size_t ptr; - + if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE)) return 0; ptr = dma_cont->address(dma_cont); if (ptr != 0) ptr -= substream->runtime->dma_addr; - + return bytes_to_frames(substream->runtime, ptr); } -/* - - */ - static int __init snd_cs4231_probe(struct snd_cs4231 *chip) { unsigned long flags; - int i, id, vers; + int i; + int id = 0; + int vers = 0; unsigned char *ptr; - id = vers = 0; for (i = 0; i < 50; i++) { mb(); - if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT) - udelay(2000); + if (__cs4231_readb(chip, CS4231U(chip, REGSEL)) & CS4231_INIT) + msleep(2); else { spin_lock_irqsave(&chip->lock, flags); snd_cs4231_out(chip, CS4231_MISC_INFO, CS4231_MODE2); @@ -1213,8 +1089,9 @@ static int __init snd_cs4231_probe(struct snd_cs4231 *chip) spin_lock_irqsave(&chip->lock, flags); - __cs4231_readb(chip, CS4231P(chip, STATUS)); /* clear any pendings IRQ */ - __cs4231_writeb(chip, 0, CS4231P(chip, STATUS)); + /* clear any pendings IRQ */ + __cs4231_readb(chip, CS4231U(chip, STATUS)); + __cs4231_writeb(chip, 0, CS4231U(chip, STATUS)); mb(); spin_unlock_irqrestore(&chip->lock, flags); @@ -1247,42 +1124,50 @@ static int __init snd_cs4231_probe(struct snd_cs4231 *chip) return 0; /* all things are ok.. */ } -static struct snd_pcm_hardware snd_cs4231_playback = -{ - .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START), - .formats = (SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | - SNDRV_PCM_FMTBIT_IMA_ADPCM | - SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S16_BE), - .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000, +static struct snd_pcm_hardware snd_cs4231_playback = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_SYNC_START, + .formats = SNDRV_PCM_FMTBIT_MU_LAW | + SNDRV_PCM_FMTBIT_A_LAW | + SNDRV_PCM_FMTBIT_IMA_ADPCM | + SNDRV_PCM_FMTBIT_U8 | + SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S16_BE, + .rates = SNDRV_PCM_RATE_KNOT | + SNDRV_PCM_RATE_8000_48000, .rate_min = 5510, .rate_max = 48000, .channels_min = 1, .channels_max = 2, - .buffer_bytes_max = (32*1024), + .buffer_bytes_max = 32 * 1024, .period_bytes_min = 64, - .period_bytes_max = (32*1024), + .period_bytes_max = 32 * 1024, .periods_min = 1, .periods_max = 1024, }; -static struct snd_pcm_hardware snd_cs4231_capture = -{ - .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START), - .formats = (SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | - SNDRV_PCM_FMTBIT_IMA_ADPCM | - SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S16_BE), - .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000, +static struct snd_pcm_hardware snd_cs4231_capture = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_SYNC_START, + .formats = SNDRV_PCM_FMTBIT_MU_LAW | + SNDRV_PCM_FMTBIT_A_LAW | + SNDRV_PCM_FMTBIT_IMA_ADPCM | + SNDRV_PCM_FMTBIT_U8 | + SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S16_BE, + .rates = SNDRV_PCM_RATE_KNOT | + SNDRV_PCM_RATE_8000_48000, .rate_min = 5510, .rate_max = 48000, .channels_min = 1, .channels_max = 2, - .buffer_bytes_max = (32*1024), + .buffer_bytes_max = 32 * 1024, .period_bytes_min = 64, - .period_bytes_max = (32*1024), + .period_bytes_max = 32 * 1024, .periods_min = 1, .periods_max = 1024, }; @@ -1295,7 +1180,8 @@ static int snd_cs4231_playback_open(struct snd_pcm_substream *substream) runtime->hw = snd_cs4231_playback; - if ((err = snd_cs4231_open(chip, CS4231_MODE_PLAY)) < 0) { + err = snd_cs4231_open(chip, CS4231_MODE_PLAY); + if (err < 0) { snd_free_pages(runtime->dma_area, runtime->dma_bytes); return err; } @@ -1315,7 +1201,8 @@ static int snd_cs4231_capture_open(struct snd_pcm_substream *substream) runtime->hw = snd_cs4231_capture; - if ((err = snd_cs4231_open(chip, CS4231_MODE_RECORD)) < 0) { + err = snd_cs4231_open(chip, CS4231_MODE_RECORD); + if (err < 0) { snd_free_pages(runtime->dma_area, runtime->dma_bytes); return err; } @@ -1356,7 +1243,7 @@ static struct snd_pcm_ops snd_cs4231_playback_ops = { .close = snd_cs4231_playback_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_cs4231_playback_hw_params, - .hw_free = snd_cs4231_playback_hw_free, + .hw_free = snd_pcm_lib_free_pages, .prepare = snd_cs4231_playback_prepare, .trigger = snd_cs4231_trigger, .pointer = snd_cs4231_playback_pointer, @@ -1367,23 +1254,27 @@ static struct snd_pcm_ops snd_cs4231_capture_ops = { .close = snd_cs4231_capture_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_cs4231_capture_hw_params, - .hw_free = snd_cs4231_capture_hw_free, + .hw_free = snd_pcm_lib_free_pages, .prepare = snd_cs4231_capture_prepare, .trigger = snd_cs4231_trigger, .pointer = snd_cs4231_capture_pointer, }; -static int __init snd_cs4231_pcm(struct snd_cs4231 *chip) +static int __init snd_cs4231_pcm(struct snd_card *card) { + struct snd_cs4231 *chip = card->private_data; struct snd_pcm *pcm; int err; - if ((err = snd_pcm_new(chip->card, "CS4231", 0, 1, 1, &pcm)) < 0) + err = snd_pcm_new(card, "CS4231", 0, 1, 1, &pcm); + if (err < 0) return err; - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_cs4231_playback_ops); - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_cs4231_capture_ops); - + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, + &snd_cs4231_playback_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, + &snd_cs4231_capture_ops); + /* global setup */ pcm->private_data = chip; pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX; @@ -1396,8 +1287,9 @@ static int __init snd_cs4231_pcm(struct snd_cs4231 *chip) return 0; } -static int __init snd_cs4231_timer(struct snd_cs4231 *chip) +static int __init snd_cs4231_timer(struct snd_card *card) { + struct snd_cs4231 *chip = card->private_data; struct snd_timer *timer; struct snd_timer_id tid; int err; @@ -1405,10 +1297,11 @@ static int __init snd_cs4231_timer(struct snd_cs4231 *chip) /* Timer initialization */ tid.dev_class = SNDRV_TIMER_CLASS_CARD; tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE; - tid.card = chip->card->number; + tid.card = card->number; tid.device = 0; tid.subdevice = 0; - if ((err = snd_timer_new(chip->card, "CS4231", &tid, &timer)) < 0) + err = snd_timer_new(card, "CS4231", &tid, &timer); + if (err < 0) return err; strcpy(timer->name, "CS4231"); timer->private_data = chip; @@ -1417,7 +1310,7 @@ static int __init snd_cs4231_timer(struct snd_cs4231 *chip) return 0; } - + /* * MIXER part */ @@ -1428,15 +1321,14 @@ static int snd_cs4231_info_mux(struct snd_kcontrol *kcontrol, static char *texts[4] = { "Line", "CD", "Mic", "Mix" }; - struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol); - snd_assert(chip->card != NULL, return -EINVAL); uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 2; uinfo->value.enumerated.items = 4; if (uinfo->value.enumerated.item > 3) uinfo->value.enumerated.item = 3; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); return 0; } @@ -1446,7 +1338,7 @@ static int snd_cs4231_get_mux(struct snd_kcontrol *kcontrol, { struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol); unsigned long flags; - + spin_lock_irqsave(&chip->lock, flags); ucontrol->value.enumerated.item[0] = (chip->image[CS4231_LEFT_INPUT] & CS4231_MIXS_ALL) >> 6; @@ -1464,7 +1356,7 @@ static int snd_cs4231_put_mux(struct snd_kcontrol *kcontrol, unsigned long flags; unsigned short left, right; int change; - + if (ucontrol->value.enumerated.item[0] > 3 || ucontrol->value.enumerated.item[1] > 3) return -EINVAL; @@ -1476,7 +1368,7 @@ static int snd_cs4231_put_mux(struct snd_kcontrol *kcontrol, left = (chip->image[CS4231_LEFT_INPUT] & ~CS4231_MIXS_ALL) | left; right = (chip->image[CS4231_RIGHT_INPUT] & ~CS4231_MIXS_ALL) | right; change = left != chip->image[CS4231_LEFT_INPUT] || - right != chip->image[CS4231_RIGHT_INPUT]; + right != chip->image[CS4231_RIGHT_INPUT]; snd_cs4231_out(chip, CS4231_LEFT_INPUT, left); snd_cs4231_out(chip, CS4231_RIGHT_INPUT, right); @@ -1508,7 +1400,7 @@ static int snd_cs4231_get_single(struct snd_kcontrol *kcontrol, int shift = (kcontrol->private_value >> 8) & 0xff; int mask = (kcontrol->private_value >> 16) & 0xff; int invert = (kcontrol->private_value >> 24) & 0xff; - + spin_lock_irqsave(&chip->lock, flags); ucontrol->value.integer.value[0] = (chip->image[reg] >> shift) & mask; @@ -1533,7 +1425,7 @@ static int snd_cs4231_put_single(struct snd_kcontrol *kcontrol, int invert = (kcontrol->private_value >> 24) & 0xff; int change; unsigned short val; - + val = (ucontrol->value.integer.value[0] & mask); if (invert) val = mask - val; @@ -1575,11 +1467,13 @@ static int snd_cs4231_get_double(struct snd_kcontrol *kcontrol, int shift_right = (kcontrol->private_value >> 19) & 0x07; int mask = (kcontrol->private_value >> 24) & 0xff; int invert = (kcontrol->private_value >> 22) & 1; - + spin_lock_irqsave(&chip->lock, flags); - ucontrol->value.integer.value[0] = (chip->image[left_reg] >> shift_left) & mask; - ucontrol->value.integer.value[1] = (chip->image[right_reg] >> shift_right) & mask; + ucontrol->value.integer.value[0] = + (chip->image[left_reg] >> shift_left) & mask; + ucontrol->value.integer.value[1] = + (chip->image[right_reg] >> shift_right) & mask; spin_unlock_irqrestore(&chip->lock, flags); @@ -1606,7 +1500,7 @@ static int snd_cs4231_put_double(struct snd_kcontrol *kcontrol, int invert = (kcontrol->private_value >> 22) & 1; int change; unsigned short val1, val2; - + val1 = ucontrol->value.integer.value[0] & mask; val2 = ucontrol->value.integer.value[1] & mask; if (invert) { @@ -1620,7 +1514,8 @@ static int snd_cs4231_put_double(struct snd_kcontrol *kcontrol, val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1; val2 = (chip->image[right_reg] & ~(mask << shift_right)) | val2; - change = val1 != chip->image[left_reg] || val2 != chip->image[right_reg]; + change = val1 != chip->image[left_reg]; + change |= val2 != chip->image[right_reg]; snd_cs4231_out(chip, left_reg, val1); snd_cs4231_out(chip, right_reg, val2); @@ -1630,31 +1525,42 @@ static int snd_cs4231_put_double(struct snd_kcontrol *kcontrol, } #define CS4231_SINGLE(xname, xindex, reg, shift, mask, invert) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ - .info = snd_cs4231_info_single, \ - .get = snd_cs4231_get_single, .put = snd_cs4231_put_single, \ - .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) } - -#define CS4231_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ - .info = snd_cs4231_info_double, \ - .get = snd_cs4231_get_double, .put = snd_cs4231_put_double, \ - .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) } +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), .index = (xindex), \ + .info = snd_cs4231_info_single, \ + .get = snd_cs4231_get_single, .put = snd_cs4231_put_single, \ + .private_value = (reg) | ((shift) << 8) | ((mask) << 16) | ((invert) << 24) } + +#define CS4231_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, \ + shift_right, mask, invert) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), .index = (xindex), \ + .info = snd_cs4231_info_double, \ + .get = snd_cs4231_get_double, .put = snd_cs4231_put_double, \ + .private_value = (left_reg) | ((right_reg) << 8) | ((shift_left) << 16) | \ + ((shift_right) << 19) | ((mask) << 24) | ((invert) << 22) } static struct snd_kcontrol_new snd_cs4231_controls[] __initdata = { -CS4231_DOUBLE("PCM Playback Switch", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1), -CS4231_DOUBLE("PCM Playback Volume", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1), -CS4231_DOUBLE("Line Playback Switch", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1), -CS4231_DOUBLE("Line Playback Volume", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1), -CS4231_DOUBLE("Aux Playback Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1), -CS4231_DOUBLE("Aux Playback Volume", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1), -CS4231_DOUBLE("Aux Playback Switch", 1, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1), -CS4231_DOUBLE("Aux Playback Volume", 1, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1), +CS4231_DOUBLE("PCM Playback Switch", 0, CS4231_LEFT_OUTPUT, + CS4231_RIGHT_OUTPUT, 7, 7, 1, 1), +CS4231_DOUBLE("PCM Playback Volume", 0, CS4231_LEFT_OUTPUT, + CS4231_RIGHT_OUTPUT, 0, 0, 63, 1), +CS4231_DOUBLE("Line Playback Switch", 0, CS4231_LEFT_LINE_IN, + CS4231_RIGHT_LINE_IN, 7, 7, 1, 1), +CS4231_DOUBLE("Line Playback Volume", 0, CS4231_LEFT_LINE_IN, + CS4231_RIGHT_LINE_IN, 0, 0, 31, 1), +CS4231_DOUBLE("Aux Playback Switch", 0, CS4231_AUX1_LEFT_INPUT, + CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1), +CS4231_DOUBLE("Aux Playback Volume", 0, CS4231_AUX1_LEFT_INPUT, + CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1), +CS4231_DOUBLE("Aux Playback Switch", 1, CS4231_AUX2_LEFT_INPUT, + CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1), +CS4231_DOUBLE("Aux Playback Volume", 1, CS4231_AUX2_LEFT_INPUT, + CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1), CS4231_SINGLE("Mono Playback Switch", 0, CS4231_MONO_CTRL, 7, 1, 1), CS4231_SINGLE("Mono Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1), CS4231_SINGLE("Mono Output Playback Switch", 0, CS4231_MONO_CTRL, 6, 1, 1), CS4231_SINGLE("Mono Output Playback Bypass", 0, CS4231_MONO_CTRL, 5, 1, 0), -CS4231_DOUBLE("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0), +CS4231_DOUBLE("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, + 15, 0), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Capture Source", @@ -1662,29 +1568,28 @@ CS4231_DOUBLE("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, .get = snd_cs4231_get_mux, .put = snd_cs4231_put_mux, }, -CS4231_DOUBLE("Mic Boost", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 5, 5, 1, 0), +CS4231_DOUBLE("Mic Boost", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 5, 5, + 1, 0), CS4231_SINGLE("Loopback Capture Switch", 0, CS4231_LOOPBACK, 0, 1, 0), CS4231_SINGLE("Loopback Capture Volume", 0, CS4231_LOOPBACK, 2, 63, 1), /* SPARC specific uses of XCTL{0,1} general purpose outputs. */ CS4231_SINGLE("Line Out Switch", 0, CS4231_PIN_CTRL, 6, 1, 1), CS4231_SINGLE("Headphone Out Switch", 0, CS4231_PIN_CTRL, 7, 1, 1) }; - -static int __init snd_cs4231_mixer(struct snd_cs4231 *chip) + +static int __init snd_cs4231_mixer(struct snd_card *card) { - struct snd_card *card; + struct snd_cs4231 *chip = card->private_data; int err, idx; snd_assert(chip != NULL && chip->pcm != NULL, return -EINVAL); - card = chip->card; - strcpy(card->mixername, chip->pcm->name); for (idx = 0; idx < ARRAY_SIZE(snd_cs4231_controls); idx++) { - if ((err = snd_ctl_add(card, - snd_ctl_new1(&snd_cs4231_controls[idx], - chip))) < 0) + err = snd_ctl_add(card, + snd_ctl_new1(&snd_cs4231_controls[idx], chip)); + if (err < 0) return err; } return 0; @@ -1695,6 +1600,7 @@ static int dev; static int __init cs4231_attach_begin(struct snd_card **rcard) { struct snd_card *card; + struct snd_cs4231 *chip; *rcard = NULL; @@ -1706,31 +1612,40 @@ static int __init cs4231_attach_begin(struct snd_card **rcard) return -ENOENT; } - card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); + card = snd_card_new(index[dev], id[dev], THIS_MODULE, + sizeof(struct snd_cs4231)); if (card == NULL) return -ENOMEM; strcpy(card->driver, "CS4231"); strcpy(card->shortname, "Sun CS4231"); + chip = card->private_data; + chip->card = card; + *rcard = card; return 0; } -static int __init cs4231_attach_finish(struct snd_card *card, struct snd_cs4231 *chip) +static int __init cs4231_attach_finish(struct snd_card *card) { + struct snd_cs4231 *chip = card->private_data; int err; - if ((err = snd_cs4231_pcm(chip)) < 0) + err = snd_cs4231_pcm(card); + if (err < 0) goto out_err; - if ((err = snd_cs4231_mixer(chip)) < 0) + err = snd_cs4231_mixer(card); + if (err < 0) goto out_err; - if ((err = snd_cs4231_timer(chip)) < 0) + err = snd_cs4231_timer(card); + if (err < 0) goto out_err; - if ((err = snd_card_register(card)) < 0) + err = snd_card_register(card); + if (err < 0) goto out_err; chip->next = cs4231_list; @@ -1754,7 +1669,7 @@ static irqreturn_t snd_cs4231_sbus_interrupt(int irq, void *dev_id) struct snd_cs4231 *chip = dev_id; /*This is IRQ is not raised by the cs4231*/ - if (!(__cs4231_readb(chip, CS4231P(chip, STATUS)) & CS4231_GLOBALIRQ)) + if (!(__cs4231_readb(chip, CS4231U(chip, STATUS)) & CS4231_GLOBALIRQ)) return IRQ_NONE; /* ACK the APC interrupt. */ @@ -1762,24 +1677,24 @@ static irqreturn_t snd_cs4231_sbus_interrupt(int irq, void *dev_id) sbus_writel(csr, chip->port + APCCSR); - if ((csr & APC_PDMA_READY) && - (csr & APC_PLAY_INT) && + if ((csr & APC_PDMA_READY) && + (csr & APC_PLAY_INT) && (csr & APC_XINT_PNVA) && !(csr & APC_XINT_EMPT)) snd_cs4231_play_callback(chip); - if ((csr & APC_CDMA_READY) && - (csr & APC_CAPT_INT) && + if ((csr & APC_CDMA_READY) && + (csr & APC_CAPT_INT) && (csr & APC_XINT_CNVA) && !(csr & APC_XINT_EMPT)) snd_cs4231_capture_callback(chip); - + status = snd_cs4231_in(chip, CS4231_IRQ_STATUS); if (status & CS4231_TIMER_IRQ) { if (chip->timer) snd_timer_interrupt(chip->timer, chip->timer->sticks); - } + } if ((status & CS4231_RECORD_IRQ) && (csr & APC_CDMA_READY)) snd_cs4231_overrange(chip); @@ -1796,26 +1711,27 @@ static irqreturn_t snd_cs4231_sbus_interrupt(int irq, void *dev_id) * SBUS DMA routines */ -static int sbus_dma_request(struct cs4231_dma_control *dma_cont, dma_addr_t bus_addr, size_t len) +static int sbus_dma_request(struct cs4231_dma_control *dma_cont, + dma_addr_t bus_addr, size_t len) { unsigned long flags; u32 test, csr; int err; struct sbus_dma_info *base = &dma_cont->sbus_info; - + if (len >= (1 << 24)) return -EINVAL; spin_lock_irqsave(&base->lock, flags); csr = sbus_readl(base->regs + APCCSR); err = -EINVAL; test = APC_CDMA_READY; - if ( base->dir == APC_PLAY ) + if (base->dir == APC_PLAY) test = APC_PDMA_READY; if (!(csr & test)) goto out; err = -EBUSY; test = APC_XINT_CNVA; - if ( base->dir == APC_PLAY ) + if (base->dir == APC_PLAY) test = APC_XINT_PNVA; if (!(csr & test)) goto out; @@ -1838,7 +1754,7 @@ static void sbus_dma_prepare(struct cs4231_dma_control *dma_cont, int d) test = APC_GENL_INT | APC_PLAY_INT | APC_XINT_ENA | APC_XINT_PLAY | APC_XINT_PEMP | APC_XINT_GENL | APC_XINT_PENA; - if ( base->dir == APC_RECORD ) + if (base->dir == APC_RECORD) test = APC_GENL_INT | APC_CAPT_INT | APC_XINT_ENA | APC_XINT_CAPT | APC_XINT_CEMP | APC_XINT_GENL; csr |= test; @@ -1856,28 +1772,28 @@ static void sbus_dma_enable(struct cs4231_dma_control *dma_cont, int on) if (!on) { sbus_writel(0, base->regs + base->dir + APCNC); sbus_writel(0, base->regs + base->dir + APCNVA); - if ( base->dir == APC_PLAY ) { + if (base->dir == APC_PLAY) { sbus_writel(0, base->regs + base->dir + APCC); sbus_writel(0, base->regs + base->dir + APCVA); } udelay(1200); - } + } csr = sbus_readl(base->regs + APCCSR); shift = 0; - if ( base->dir == APC_PLAY ) + if (base->dir == APC_PLAY) shift = 1; if (on) csr &= ~(APC_CPAUSE << shift); else - csr |= (APC_CPAUSE << shift); + csr |= (APC_CPAUSE << shift); sbus_writel(csr, base->regs + APCCSR); if (on) csr |= (APC_CDMA_READY << shift); else csr &= ~(APC_CDMA_READY << shift); sbus_writel(csr, base->regs + APCCSR); - + spin_unlock_irqrestore(&base->lock, flags); } @@ -1885,14 +1801,14 @@ static unsigned int sbus_dma_addr(struct cs4231_dma_control *dma_cont) { struct sbus_dma_info *base = &dma_cont->sbus_info; - return sbus_readl(base->regs + base->dir + APCVA); + return sbus_readl(base->regs + base->dir + APCVA); } static void sbus_dma_preallocate(struct snd_cs4231 *chip, struct snd_pcm *pcm) { snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_SBUS, - snd_dma_sbus_data(chip->dev_u.sdev), - 64*1024, 128*1024); + snd_dma_sbus_data(chip->dev_u.sdev), + 64 * 1024, 128 * 1024); } /* @@ -1907,8 +1823,6 @@ static int snd_cs4231_sbus_free(struct snd_cs4231 *chip) if (chip->port) sbus_iounmap(chip->port, chip->regs_size); - kfree(chip); - return 0; } @@ -1925,23 +1839,16 @@ static struct snd_device_ops snd_cs4231_sbus_dev_ops = { static int __init snd_cs4231_sbus_create(struct snd_card *card, struct sbus_dev *sdev, - int dev, - struct snd_cs4231 **rchip) + int dev) { - struct snd_cs4231 *chip; + struct snd_cs4231 *chip = card->private_data; int err; - *rchip = NULL; - chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (chip == NULL) - return -ENOMEM; - spin_lock_init(&chip->lock); spin_lock_init(&chip->c_dma.sbus_info.lock); spin_lock_init(&chip->p_dma.sbus_info.lock); mutex_init(&chip->mce_mutex); mutex_init(&chip->open_mutex); - chip->card = card; chip->dev_u.sdev = sdev; chip->regs_size = sdev->reg_addrs[0].reg_size; memcpy(&chip->image, &snd_cs4231_original_image, @@ -1992,14 +1899,12 @@ static int __init snd_cs4231_sbus_create(struct snd_card *card, return err; } - *rchip = chip; return 0; } static int __init cs4231_sbus_attach(struct sbus_dev *sdev) { struct resource *rp = &sdev->resource[0]; - struct snd_cs4231 *cp; struct snd_card *card; int err; @@ -2013,25 +1918,28 @@ static int __init cs4231_sbus_attach(struct sbus_dev *sdev) (unsigned long long)rp->start, sdev->irqs[0]); - if ((err = snd_cs4231_sbus_create(card, sdev, dev, &cp)) < 0) { + err = snd_cs4231_sbus_create(card, sdev, dev); + if (err < 0) { snd_card_free(card); return err; } - return cs4231_attach_finish(card, cp); + return cs4231_attach_finish(card); } #endif #ifdef EBUS_SUPPORT -static void snd_cs4231_ebus_play_callback(struct ebus_dma_info *p, int event, void *cookie) +static void snd_cs4231_ebus_play_callback(struct ebus_dma_info *p, int event, + void *cookie) { struct snd_cs4231 *chip = cookie; - + snd_cs4231_play_callback(chip); } -static void snd_cs4231_ebus_capture_callback(struct ebus_dma_info *p, int event, void *cookie) +static void snd_cs4231_ebus_capture_callback(struct ebus_dma_info *p, + int event, void *cookie) { struct snd_cs4231 *chip = cookie; @@ -2042,7 +1950,8 @@ static void snd_cs4231_ebus_capture_callback(struct ebus_dma_info *p, int event, * EBUS DMA wrappers */ -static int _ebus_dma_request(struct cs4231_dma_control *dma_cont, dma_addr_t bus_addr, size_t len) +static int _ebus_dma_request(struct cs4231_dma_control *dma_cont, + dma_addr_t bus_addr, size_t len) { return ebus_dma_request(&dma_cont->ebus_info, bus_addr, len); } @@ -2087,8 +1996,6 @@ static int snd_cs4231_ebus_free(struct snd_cs4231 *chip) if (chip->port) iounmap(chip->port); - kfree(chip); - return 0; } @@ -2105,24 +2012,17 @@ static struct snd_device_ops snd_cs4231_ebus_dev_ops = { static int __init snd_cs4231_ebus_create(struct snd_card *card, struct linux_ebus_device *edev, - int dev, - struct snd_cs4231 **rchip) + int dev) { - struct snd_cs4231 *chip; + struct snd_cs4231 *chip = card->private_data; int err; - *rchip = NULL; - chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (chip == NULL) - return -ENOMEM; - spin_lock_init(&chip->lock); spin_lock_init(&chip->c_dma.ebus_info.lock); spin_lock_init(&chip->p_dma.ebus_info.lock); mutex_init(&chip->mce_mutex); mutex_init(&chip->open_mutex); chip->flags |= CS4231_FLAG_EBUS; - chip->card = card; chip->dev_u.pdev = edev->bus->self; memcpy(&chip->image, &snd_cs4231_original_image, sizeof(snd_cs4231_original_image)); @@ -2152,7 +2052,8 @@ static int __init snd_cs4231_ebus_create(struct snd_card *card, chip->port = ioremap(edev->resource[0].start, 0x10); chip->p_dma.ebus_info.regs = ioremap(edev->resource[1].start, 0x10); chip->c_dma.ebus_info.regs = ioremap(edev->resource[2].start, 0x10); - if (!chip->port || !chip->p_dma.ebus_info.regs || !chip->c_dma.ebus_info.regs) { + if (!chip->port || !chip->p_dma.ebus_info.regs || + !chip->c_dma.ebus_info.regs) { snd_cs4231_ebus_free(chip); snd_printdd("cs4231-%d: Unable to map chip registers.\n", dev); return -EIO; @@ -2160,18 +2061,21 @@ static int __init snd_cs4231_ebus_create(struct snd_card *card, if (ebus_dma_register(&chip->c_dma.ebus_info)) { snd_cs4231_ebus_free(chip); - snd_printdd("cs4231-%d: Unable to register EBUS capture DMA\n", dev); + snd_printdd("cs4231-%d: Unable to register EBUS capture DMA\n", + dev); return -EBUSY; } if (ebus_dma_irq_enable(&chip->c_dma.ebus_info, 1)) { snd_cs4231_ebus_free(chip); - snd_printdd("cs4231-%d: Unable to enable EBUS capture IRQ\n", dev); + snd_printdd("cs4231-%d: Unable to enable EBUS capture IRQ\n", + dev); return -EBUSY; } if (ebus_dma_register(&chip->p_dma.ebus_info)) { snd_cs4231_ebus_free(chip); - snd_printdd("cs4231-%d: Unable to register EBUS play DMA\n", dev); + snd_printdd("cs4231-%d: Unable to register EBUS play DMA\n", + dev); return -EBUSY; } if (ebus_dma_irq_enable(&chip->p_dma.ebus_info, 1)) { @@ -2192,14 +2096,12 @@ static int __init snd_cs4231_ebus_create(struct snd_card *card, return err; } - *rchip = chip; return 0; } static int __init cs4231_ebus_attach(struct linux_ebus_device *edev) { struct snd_card *card; - struct snd_cs4231 *chip; int err; err = cs4231_attach_begin(&card); @@ -2211,12 +2113,13 @@ static int __init cs4231_ebus_attach(struct linux_ebus_device *edev) edev->resource[0].start, edev->irqs[0]); - if ((err = snd_cs4231_ebus_create(card, edev, dev, &chip)) < 0) { + err = snd_cs4231_ebus_create(card, edev, dev); + if (err < 0) { snd_card_free(card); return err; } - return cs4231_attach_finish(card, chip); + return cs4231_attach_finish(card); } #endif diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c index e07085a7cfc..376b98691c9 100644 --- a/sound/sparc/dbri.c +++ b/sound/sparc/dbri.c @@ -8,18 +8,18 @@ * Copyright (C) 1997 Rudolf Koenig (rfkoenig@immd4.informatik.uni-erlangen.de) * Copyright (C) 1998, 1999 Brent Baccala (baccala@freesoft.org) * - * This is the lowlevel driver for the DBRI & MMCODEC duo used for ISDN & AUDIO - * on Sun SPARCstation 10, 20, LX and Voyager models. + * This is the low level driver for the DBRI & MMCODEC duo used for ISDN & AUDIO + * on Sun SPARCStation 10, 20, LX and Voyager models. * * - DBRI: AT&T T5900FX Dual Basic Rates ISDN Interface. It is a 32 channel * data time multiplexer with ISDN support (aka T7259) * Interfaces: SBus,ISDN NT & TE, CHI, 4 bits parallel. * CHI: (spelled ki) Concentration Highway Interface (AT&T or Intel bus ?). * Documentation: - * - "STP 4000SBus Dual Basic Rate ISDN (DBRI) Tranceiver" from + * - "STP 4000SBus Dual Basic Rate ISDN (DBRI) Transceiver" from * Sparc Technology Business (courtesy of Sun Support) * - Data sheet of the T7903, a newer but very similar ISA bus equivalent - * available from the Lucent (formarly AT&T microelectronics) home + * available from the Lucent (formerly AT&T microelectronics) home * page. * - http://www.freesoft.org/Linux/DBRI/ * - MMCODEC: Crystal Semiconductor CS4215 16 bit Multimedia Audio Codec @@ -27,21 +27,21 @@ * Documentation: from the Crystal Semiconductor home page. * * The DBRI is a 32 pipe machine, each pipe can transfer some bits between - * memory and a serial device (long pipes, nr 0-15) or between two serial - * devices (short pipes, nr 16-31), or simply send a fixed data to a serial + * memory and a serial device (long pipes, no. 0-15) or between two serial + * devices (short pipes, no. 16-31), or simply send a fixed data to a serial * device (short pipes). - * A timeslot defines the bit-offset and nr of bits read from a serial device. + * A timeslot defines the bit-offset and no. of bits read from a serial device. * The timeslots are linked to 6 circular lists, one for each direction for * each serial device (NT,TE,CHI). A timeslot is associated to 1 or 2 pipes * (the second one is a monitor/tee pipe, valid only for serial input). * * The mmcodec is connected via the CHI bus and needs the data & some - * parameters (volume, output selection) timemultiplexed in 8 byte + * parameters (volume, output selection) time multiplexed in 8 byte * chunks. It also has a control mode, which serves for audio format setting. * * Looking at the CS4215 data sheet it is easy to set up 2 or 4 codecs on - * the same CHI bus, so I thought perhaps it is possible to use the onboard - * & the speakerbox codec simultanously, giving 2 (not very independent :-) + * the same CHI bus, so I thought perhaps it is possible to use the on-board + * & the speakerbox codec simultaneously, giving 2 (not very independent :-) * audio devices. But the SUN HW group decided against it, at least on my * LX the speakerbox connector has at least 1 pin missing and 1 wrongly * connected. @@ -56,6 +56,8 @@ #include <sound/driver.h> #include <linux/interrupt.h> #include <linux/delay.h> +#include <linux/irq.h> +#include <linux/io.h> #include <sound/core.h> #include <sound/pcm.h> @@ -64,8 +66,7 @@ #include <sound/control.h> #include <sound/initval.h> -#include <asm/irq.h> -#include <asm/io.h> +#include <linux/of.h> #include <asm/sbus.h> #include <asm/atomic.h> @@ -76,7 +77,8 @@ MODULE_SUPPORTED_DEVICE("{{Sun,DBRI}}"); 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_PNP; /* Enable this card */ +/* Enable this card */ +static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; module_param_array(index, int, NULL, 0444); MODULE_PARM_DESC(index, "Index value for Sun DBRI soundcard."); @@ -104,7 +106,7 @@ static char *cmds[] = { "SSP", "CHI", "NT", "TE", "CDEC", "TEST", "CDM", "RESRV" }; -#define dprintk(a, x...) if(dbri_debug & a) printk(KERN_DEBUG x) +#define dprintk(a, x...) if (dbri_debug & a) printk(KERN_DEBUG x) #else #define dprintk(a, x...) do { } while (0) @@ -131,7 +133,7 @@ struct cs4215 { }; /* - * Control mode first + * Control mode first */ /* Time Slot 1, Status register */ @@ -219,7 +221,7 @@ static struct { /* Time Slot 7, Input Setting */ #define CS4215_LG(v) v /* Left Gain Setting 0xf: 22.5 dB */ #define CS4215_IS (1<<4) /* Input Select: 1=Microphone, 0=Line */ -#define CS4215_OVR (1<<5) /* 1: Overrange condition occurred */ +#define CS4215_OVR (1<<5) /* 1: Over range condition occurred */ #define CS4215_PIO0 (1<<6) /* Parallel I/O 0 */ #define CS4215_PIO1 (1<<7) @@ -232,12 +234,12 @@ static struct { ****************************************************************************/ /* DBRI main registers */ -#define REG0 0x00UL /* Status and Control */ -#define REG1 0x04UL /* Mode and Interrupt */ -#define REG2 0x08UL /* Parallel IO */ -#define REG3 0x0cUL /* Test */ -#define REG8 0x20UL /* Command Queue Pointer */ -#define REG9 0x24UL /* Interrupt Queue Pointer */ +#define REG0 0x00 /* Status and Control */ +#define REG1 0x04 /* Mode and Interrupt */ +#define REG2 0x08 /* Parallel IO */ +#define REG3 0x0c /* Test */ +#define REG8 0x20 /* Command Queue Pointer */ +#define REG9 0x24 /* Interrupt Queue Pointer */ #define DBRI_NO_CMDS 64 #define DBRI_INT_BLK 64 @@ -285,7 +287,7 @@ struct dbri_pipe { /* Per stream (playback or record) information */ struct dbri_streaminfo { struct snd_pcm_substream *substream; - u32 dvma_buffer; /* Device view of Alsa DMA buffer */ + u32 dvma_buffer; /* Device view of ALSA DMA buffer */ int size; /* Size of DMA buffer */ size_t offset; /* offset in user buffer */ int pipe; /* Data pipe used */ @@ -295,8 +297,6 @@ struct dbri_streaminfo { /* This structure holds the information for both chips (DBRI & CS4215) */ struct snd_dbri { - struct snd_card *card; /* ALSA card */ - int regs_size, irq; /* Needed for unload */ struct sbus_dev *sdev; /* SBUS device info */ spinlock_t lock; @@ -317,8 +317,6 @@ struct snd_dbri { struct cs4215 mm; /* mmcodec special info */ /* per stream (playback/record) info */ struct dbri_streaminfo stream_info[DBRI_NO_STREAMS]; - - struct snd_dbri *next; }; #define DBRI_MAX_VOLUME 63 /* Output volume */ @@ -341,11 +339,11 @@ struct snd_dbri { /* DBRI Reg1 - Mode and Interrupt Register - defines. (Page 18) */ #define D_LITTLE_END (1<<8) /* Byte Order */ #define D_BIG_END (0<<8) /* Byte Order */ -#define D_MRR (1<<4) /* Multiple Error Ack on SBus (readonly) */ -#define D_MLE (1<<3) /* Multiple Late Error on SBus (readonly) */ -#define D_LBG (1<<2) /* Lost Bus Grant on SBus (readonly) */ -#define D_MBE (1<<1) /* Burst Error on SBus (readonly) */ -#define D_IR (1<<0) /* Interrupt Indicator (readonly) */ +#define D_MRR (1<<4) /* Multiple Error Ack on SBus (read only) */ +#define D_MLE (1<<3) /* Multiple Late Error on SBus (read only) */ +#define D_LBG (1<<2) /* Lost Bus Grant on SBus (read only) */ +#define D_MBE (1<<1) /* Burst Error on SBus (read only) */ +#define D_IR (1<<0) /* Interrupt Indicator (read only) */ /* DBRI Reg2 - Parallel IO Register - defines. (Page 18) */ #define D_ENPIO3 (1<<7) /* Enable Pin 3 */ @@ -376,11 +374,11 @@ struct snd_dbri { #define D_CDM 0xe /* CHI Data mode command */ /* Special bits for some commands */ -#define D_PIPE(v) ((v)<<0) /* Pipe Nr: 0-15 long, 16-21 short */ +#define D_PIPE(v) ((v)<<0) /* Pipe No.: 0-15 long, 16-21 short */ /* Setup Data Pipe */ /* IRM */ -#define D_SDP_2SAME (1<<18) /* Report 2nd time in a row value rcvd */ +#define D_SDP_2SAME (1<<18) /* Report 2nd time in a row value received */ #define D_SDP_CHANGE (2<<18) /* Report any changes */ #define D_SDP_EVERY (3<<18) /* Report any changes */ #define D_SDP_EOL (1<<17) /* EOL interrupt enable */ @@ -419,7 +417,7 @@ struct snd_dbri { #define D_TS_NONCONTIG (3<<10) /* Non contiguous mode */ #define D_TS_ANCHOR (7<<10) /* Starting short pipes */ #define D_TS_MON(v) ((v)<<5) /* Monitor Pipe */ -#define D_TS_NEXT(v) ((v)<<0) /* Pipe Nr: 0-15 long, 16-21 short */ +#define D_TS_NEXT(v) ((v)<<0) /* Pipe no.: 0-15 long, 16-21 short */ /* Concentration Highway Interface Modes */ #define D_CHI_CHICM(v) ((v)<<16) /* Clock mode */ @@ -435,7 +433,7 @@ struct snd_dbri { #define D_NT_NBF (1<<16) /* Number of bad frames to loose framing */ #define D_NT_IRM_IMM (1<<15) /* Interrupt Report & Mask: Immediate */ #define D_NT_IRM_EN (1<<14) /* Interrupt Report & Mask: Enable */ -#define D_NT_ISNT (1<<13) /* Configfure interface as NT */ +#define D_NT_ISNT (1<<13) /* Configure interface as NT */ #define D_NT_FT (1<<12) /* Fixed Timing */ #define D_NT_EZ (1<<11) /* Echo Channel is Zeros */ #define D_NT_IFA (1<<10) /* Inhibit Final Activation */ @@ -455,7 +453,7 @@ struct snd_dbri { #define D_TEST_RAM(v) ((v)<<16) /* RAM Pointer */ #define D_TEST_SIZE(v) ((v)<<11) /* */ #define D_TEST_ROMONOFF 0x5 /* Toggle ROM opcode monitor on/off */ -#define D_TEST_PROC 0x6 /* MicroProcessor test */ +#define D_TEST_PROC 0x6 /* Microprocessor test */ #define D_TEST_SER 0x7 /* Serial-Controller test */ #define D_TEST_RAMREAD 0x8 /* Copy from Ram to system memory */ #define D_TEST_RAMWRITE 0x9 /* Copy into Ram from system memory */ @@ -464,12 +462,12 @@ struct snd_dbri { #define D_TEST_DUMP 0xe /* ROM Dump */ /* CHI Data Mode */ -#define D_CDM_THI (1<<8) /* Transmit Data on CHIDR Pin */ -#define D_CDM_RHI (1<<7) /* Receive Data on CHIDX Pin */ -#define D_CDM_RCE (1<<6) /* Receive on Rising Edge of CHICK */ -#define D_CDM_XCE (1<<2) /* Transmit Data on Rising Edge of CHICK */ -#define D_CDM_XEN (1<<1) /* Transmit Highway Enable */ -#define D_CDM_REN (1<<0) /* Receive Highway Enable */ +#define D_CDM_THI (1 << 8) /* Transmit Data on CHIDR Pin */ +#define D_CDM_RHI (1 << 7) /* Receive Data on CHIDX Pin */ +#define D_CDM_RCE (1 << 6) /* Receive on Rising Edge of CHICK */ +#define D_CDM_XCE (1 << 2) /* Transmit Data on Rising Edge of CHICK */ +#define D_CDM_XEN (1 << 1) /* Transmit Highway Enable */ +#define D_CDM_REN (1 << 0) /* Receive Highway Enable */ /* The Interrupts */ #define D_INTR_BRDY 1 /* Buffer Ready for processing */ @@ -493,9 +491,9 @@ struct snd_dbri { #define D_INTR_CHI 36 #define D_INTR_CMD 38 -#define D_INTR_GETCHAN(v) (((v)>>24) & 0x3f) -#define D_INTR_GETCODE(v) (((v)>>20) & 0xf) -#define D_INTR_GETCMD(v) (((v)>>16) & 0xf) +#define D_INTR_GETCHAN(v) (((v) >> 24) & 0x3f) +#define D_INTR_GETCODE(v) (((v) >> 20) & 0xf) +#define D_INTR_GETCMD(v) (((v) >> 16) & 0xf) #define D_INTR_GETVAL(v) ((v) & 0xffff) #define D_INTR_GETRVAL(v) ((v) & 0xfffff) @@ -533,43 +531,42 @@ struct snd_dbri { #define D_P_31 31 /* */ /* Transmit descriptor defines */ -#define DBRI_TD_F (1<<31) /* End of Frame */ -#define DBRI_TD_D (1<<30) /* Do not append CRC */ -#define DBRI_TD_CNT(v) ((v)<<16) /* Number of valid bytes in the buffer */ -#define DBRI_TD_B (1<<15) /* Final interrupt */ -#define DBRI_TD_M (1<<14) /* Marker interrupt */ -#define DBRI_TD_I (1<<13) /* Transmit Idle Characters */ -#define DBRI_TD_FCNT(v) (v) /* Flag Count */ -#define DBRI_TD_UNR (1<<3) /* Underrun: transmitter is out of data */ -#define DBRI_TD_ABT (1<<2) /* Abort: frame aborted */ -#define DBRI_TD_TBC (1<<0) /* Transmit buffer Complete */ -#define DBRI_TD_STATUS(v) ((v)&0xff) /* Transmit status */ - /* Maximum buffer size per TD: almost 8Kb */ +#define DBRI_TD_F (1 << 31) /* End of Frame */ +#define DBRI_TD_D (1 << 30) /* Do not append CRC */ +#define DBRI_TD_CNT(v) ((v) << 16) /* Number of valid bytes in the buffer */ +#define DBRI_TD_B (1 << 15) /* Final interrupt */ +#define DBRI_TD_M (1 << 14) /* Marker interrupt */ +#define DBRI_TD_I (1 << 13) /* Transmit Idle Characters */ +#define DBRI_TD_FCNT(v) (v) /* Flag Count */ +#define DBRI_TD_UNR (1 << 3) /* Underrun: transmitter is out of data */ +#define DBRI_TD_ABT (1 << 2) /* Abort: frame aborted */ +#define DBRI_TD_TBC (1 << 0) /* Transmit buffer Complete */ +#define DBRI_TD_STATUS(v) ((v) & 0xff) /* Transmit status */ + /* Maximum buffer size per TD: almost 8KB */ #define DBRI_TD_MAXCNT ((1 << 13) - 4) /* Receive descriptor defines */ -#define DBRI_RD_F (1<<31) /* End of Frame */ -#define DBRI_RD_C (1<<30) /* Completed buffer */ -#define DBRI_RD_B (1<<15) /* Final interrupt */ -#define DBRI_RD_M (1<<14) /* Marker interrupt */ -#define DBRI_RD_BCNT(v) (v) /* Buffer size */ -#define DBRI_RD_CRC (1<<7) /* 0: CRC is correct */ -#define DBRI_RD_BBC (1<<6) /* 1: Bad Byte received */ -#define DBRI_RD_ABT (1<<5) /* Abort: frame aborted */ -#define DBRI_RD_OVRN (1<<3) /* Overrun: data lost */ -#define DBRI_RD_STATUS(v) ((v)&0xff) /* Receive status */ -#define DBRI_RD_CNT(v) (((v)>>16)&0x1fff) /* Valid bytes in the buffer */ +#define DBRI_RD_F (1 << 31) /* End of Frame */ +#define DBRI_RD_C (1 << 30) /* Completed buffer */ +#define DBRI_RD_B (1 << 15) /* Final interrupt */ +#define DBRI_RD_M (1 << 14) /* Marker interrupt */ +#define DBRI_RD_BCNT(v) (v) /* Buffer size */ +#define DBRI_RD_CRC (1 << 7) /* 0: CRC is correct */ +#define DBRI_RD_BBC (1 << 6) /* 1: Bad Byte received */ +#define DBRI_RD_ABT (1 << 5) /* Abort: frame aborted */ +#define DBRI_RD_OVRN (1 << 3) /* Overrun: data lost */ +#define DBRI_RD_STATUS(v) ((v) & 0xff) /* Receive status */ +#define DBRI_RD_CNT(v) (((v) >> 16) & 0x1fff) /* Valid bytes in the buffer */ /* stream_info[] access */ /* Translate the ALSA direction into the array index */ #define DBRI_STREAMNO(substream) \ - (substream->stream == \ - SNDRV_PCM_STREAM_PLAYBACK? DBRI_PLAY: DBRI_REC) + (substream->stream == \ + SNDRV_PCM_STREAM_PLAYBACK ? DBRI_PLAY: DBRI_REC) /* Return a pointer to dbri_streaminfo */ -#define DBRI_STREAM(dbri, substream) &dbri->stream_info[DBRI_STREAMNO(substream)] - -static struct snd_dbri *dbri_list; /* All DBRI devices */ +#define DBRI_STREAM(dbri, substream) \ + &dbri->stream_info[DBRI_STREAMNO(substream)] /* * Short data pipes transmit LSB first. The CS4215 receives MSB first. Grrr. @@ -609,21 +606,21 @@ The list is terminated with a WAIT command, which generates a CPU interrupt to signal completion. Since the DBRI can run in parallel with the CPU, several means of -synchronization present themselves. The method implemented here is only -use of the dbri_cmdwait() to wait for execution of batch of sent commands. +synchronization present themselves. The method implemented here uses +the dbri_cmdwait() to wait for execution of batch of sent commands. -A circular command buffer is used here. A new command is being added +A circular command buffer is used here. A new command is being added while another can be executed. The scheme works by adding two WAIT commands after each sent batch of commands. When the next batch is prepared it is added after the WAIT commands then the WAITs are replaced with single JUMP -command to the new batch. The the DBRI is forced to reread the last WAIT -command (replaced by the JUMP by then). If the DBRI is still executing +command to the new batch. The the DBRI is forced to reread the last WAIT +command (replaced by the JUMP by then). If the DBRI is still executing previous commands the request to reread the WAIT command is ignored. Every time a routine wants to write commands to the DBRI, it must -first call dbri_cmdlock() and get pointer to a free space in -dbri->dma->cmd buffer. After this, the commands can be written to -the buffer, and dbri_cmdsend() is called with the final pointer value +first call dbri_cmdlock() and get pointer to a free space in +dbri->dma->cmd buffer. After this, the commands can be written to +the buffer, and dbri_cmdsend() is called with the final pointer value to send them to the DBRI. */ @@ -646,18 +643,17 @@ static void dbri_cmdwait(struct snd_dbri *dbri) } spin_unlock_irqrestore(&dbri->lock, flags); - if (maxloops == 0) { + if (maxloops == 0) printk(KERN_ERR "DBRI: Chip never completed command buffer\n"); - } else { + else dprintk(D_CMD, "Chip completed command buffer (%d)\n", MAXLOOPS - maxloops - 1); - } } /* - * Lock the command queue and returns pointer to a space for len cmd words + * Lock the command queue and return pointer to space for len cmd words * It locks the cmdlock spinlock. */ -static s32 *dbri_cmdlock(struct snd_dbri * dbri, int len) +static s32 *dbri_cmdlock(struct snd_dbri *dbri, int len) { /* Space for 2 WAIT cmds (replaced later by 1 JUMP cmd) */ len += 2; @@ -680,7 +676,7 @@ static s32 *dbri_cmdlock(struct snd_dbri * dbri, int len) * * Lock must be held before calling this. */ -static void dbri_cmdsend(struct snd_dbri * dbri, s32 * cmd,int len) +static void dbri_cmdsend(struct snd_dbri *dbri, s32 *cmd, int len) { s32 tmp, addr; static int wait_id = 0; @@ -700,16 +696,17 @@ static void dbri_cmdsend(struct snd_dbri * dbri, s32 * cmd,int len) s32 *ptr; for (ptr = dbri->cmdptr; ptr < cmd+2; ptr++) - dprintk(D_CMD, "cmd: %lx:%08x\n", (unsigned long)ptr, *ptr); + dprintk(D_CMD, "cmd: %lx:%08x\n", + (unsigned long)ptr, *ptr); } else { s32 *ptr = dbri->cmdptr; dprintk(D_CMD, "cmd: %lx:%08x\n", (unsigned long)ptr, *ptr); ptr++; dprintk(D_CMD, "cmd: %lx:%08x\n", (unsigned long)ptr, *ptr); - for (ptr = dbri->dma->cmd; ptr < cmd+2; ptr++) { - dprintk(D_CMD, "cmd: %lx:%08x\n", (unsigned long)ptr, *ptr); - } + for (ptr = dbri->dma->cmd; ptr < cmd+2; ptr++) + dprintk(D_CMD, "cmd: %lx:%08x\n", + (unsigned long)ptr, *ptr); } #endif @@ -723,7 +720,7 @@ static void dbri_cmdsend(struct snd_dbri * dbri, s32 * cmd,int len) } /* Lock must be held when calling this */ -static void dbri_reset(struct snd_dbri * dbri) +static void dbri_reset(struct snd_dbri *dbri) { int i; u32 tmp; @@ -746,7 +743,7 @@ static void dbri_reset(struct snd_dbri * dbri) } /* Lock must not be held before calling this */ -static void dbri_initialize(struct snd_dbri * dbri) +static void __devinit dbri_initialize(struct snd_dbri *dbri) { s32 *cmd; u32 dma_addr; @@ -763,7 +760,7 @@ static void dbri_initialize(struct snd_dbri * dbri) spin_lock_init(&dbri->cmdlock); /* - * Initialize the interrupt ringbuffer. + * Initialize the interrupt ring buffer. */ dma_addr = dbri->dma_dvma + dbri_dma_off(intr, 0); dbri->dma->intr[0] = dma_addr; @@ -801,7 +798,7 @@ list ordering, among other things. The transmit and receive functions here interface closely with the transmit and receive interrupt code. */ -static int pipe_active(struct snd_dbri * dbri, int pipe) +static inline int pipe_active(struct snd_dbri *dbri, int pipe) { return ((pipe >= 0) && (dbri->pipes[pipe].desc != -1)); } @@ -811,20 +808,22 @@ static int pipe_active(struct snd_dbri * dbri, int pipe) * Called on an in-use pipe to clear anything being transmitted or received * Lock must be held before calling this. */ -static void reset_pipe(struct snd_dbri * dbri, int pipe) +static void reset_pipe(struct snd_dbri *dbri, int pipe) { int sdp; int desc; s32 *cmd; if (pipe < 0 || pipe > DBRI_MAX_PIPE) { - printk(KERN_ERR "DBRI: reset_pipe called with illegal pipe number\n"); + printk(KERN_ERR "DBRI: reset_pipe called with " + "illegal pipe number\n"); return; } sdp = dbri->pipes[pipe].sdp; if (sdp == 0) { - printk(KERN_ERR "DBRI: reset_pipe called on uninitialized pipe\n"); + printk(KERN_ERR "DBRI: reset_pipe called " + "on uninitialized pipe\n"); return; } @@ -835,9 +834,10 @@ static void reset_pipe(struct snd_dbri * dbri, int pipe) dbri_cmdsend(dbri, cmd, 3); desc = dbri->pipes[pipe].first_desc; - if ( desc >= 0) + if (desc >= 0) do { - dbri->dma->desc[desc].nda = dbri->dma->desc[desc].ba = 0; + dbri->dma->desc[desc].ba = 0; + dbri->dma->desc[desc].nda = 0; desc = dbri->next_desc[desc]; } while (desc != -1 && desc != dbri->pipes[pipe].first_desc); @@ -848,15 +848,17 @@ static void reset_pipe(struct snd_dbri * dbri, int pipe) /* * Lock must be held before calling this. */ -static void setup_pipe(struct snd_dbri * dbri, int pipe, int sdp) +static void setup_pipe(struct snd_dbri *dbri, int pipe, int sdp) { if (pipe < 0 || pipe > DBRI_MAX_PIPE) { - printk(KERN_ERR "DBRI: setup_pipe called with illegal pipe number\n"); + printk(KERN_ERR "DBRI: setup_pipe called " + "with illegal pipe number\n"); return; } if ((sdp & 0xf800) != sdp) { - printk(KERN_ERR "DBRI: setup_pipe called with strange SDP value\n"); + printk(KERN_ERR "DBRI: setup_pipe called " + "with strange SDP value\n"); /* sdp &= 0xf800; */ } @@ -877,25 +879,26 @@ static void setup_pipe(struct snd_dbri * dbri, int pipe, int sdp) /* * Lock must be held before calling this. */ -static void link_time_slot(struct snd_dbri * dbri, int pipe, +static void link_time_slot(struct snd_dbri *dbri, int pipe, int prevpipe, int nextpipe, int length, int cycle) { s32 *cmd; int val; - if (pipe < 0 || pipe > DBRI_MAX_PIPE + if (pipe < 0 || pipe > DBRI_MAX_PIPE || prevpipe < 0 || prevpipe > DBRI_MAX_PIPE || nextpipe < 0 || nextpipe > DBRI_MAX_PIPE) { - printk(KERN_ERR + printk(KERN_ERR "DBRI: link_time_slot called with illegal pipe number\n"); return; } - if (dbri->pipes[pipe].sdp == 0 + if (dbri->pipes[pipe].sdp == 0 || dbri->pipes[prevpipe].sdp == 0 || dbri->pipes[nextpipe].sdp == 0) { - printk(KERN_ERR "DBRI: link_time_slot called on uninitialized pipe\n"); + printk(KERN_ERR "DBRI: link_time_slot called " + "on uninitialized pipe\n"); return; } @@ -935,17 +938,17 @@ static void link_time_slot(struct snd_dbri * dbri, int pipe, /* * Lock must be held before calling this. */ -static void unlink_time_slot(struct snd_dbri * dbri, int pipe, +static void unlink_time_slot(struct snd_dbri *dbri, int pipe, enum in_or_out direction, int prevpipe, int nextpipe) { s32 *cmd; int val; - if (pipe < 0 || pipe > DBRI_MAX_PIPE + if (pipe < 0 || pipe > DBRI_MAX_PIPE || prevpipe < 0 || prevpipe > DBRI_MAX_PIPE || nextpipe < 0 || nextpipe > DBRI_MAX_PIPE) { - printk(KERN_ERR + printk(KERN_ERR "DBRI: unlink_time_slot called with illegal pipe number\n"); return; } @@ -985,7 +988,7 @@ static void unlink_time_slot(struct snd_dbri * dbri, int pipe, * * Lock must not be held before calling it. */ -static void xmit_fixed(struct snd_dbri * dbri, int pipe, unsigned int data) +static void xmit_fixed(struct snd_dbri *dbri, int pipe, unsigned int data) { s32 *cmd; unsigned long flags; @@ -996,7 +999,8 @@ static void xmit_fixed(struct snd_dbri * dbri, int pipe, unsigned int data) } if (D_SDP_MODE(dbri->pipes[pipe].sdp) == 0) { - printk(KERN_ERR "DBRI: xmit_fixed: Uninitialized pipe %d\n", pipe); + printk(KERN_ERR "DBRI: xmit_fixed: " + "Uninitialized pipe %d\n", pipe); return; } @@ -1006,7 +1010,8 @@ static void xmit_fixed(struct snd_dbri * dbri, int pipe, unsigned int data) } if (!(dbri->pipes[pipe].sdp & D_SDP_TO_SER)) { - printk(KERN_ERR "DBRI: xmit_fixed: Called on receive pipe %d\n", pipe); + printk(KERN_ERR "DBRI: xmit_fixed: Called on receive pipe %d\n", + pipe); return; } @@ -1028,20 +1033,23 @@ static void xmit_fixed(struct snd_dbri * dbri, int pipe, unsigned int data) } -static void recv_fixed(struct snd_dbri * dbri, int pipe, volatile __u32 * ptr) +static void recv_fixed(struct snd_dbri *dbri, int pipe, volatile __u32 *ptr) { if (pipe < 16 || pipe > DBRI_MAX_PIPE) { - printk(KERN_ERR "DBRI: recv_fixed called with illegal pipe number\n"); + printk(KERN_ERR "DBRI: recv_fixed called with " + "illegal pipe number\n"); return; } if (D_SDP_MODE(dbri->pipes[pipe].sdp) != D_SDP_FIXED) { - printk(KERN_ERR "DBRI: recv_fixed called on non-fixed pipe %d\n", pipe); + printk(KERN_ERR "DBRI: recv_fixed called on " + "non-fixed pipe %d\n", pipe); return; } if (dbri->pipes[pipe].sdp & D_SDP_TO_SER) { - printk(KERN_ERR "DBRI: recv_fixed called on transmit pipe %d\n", pipe); + printk(KERN_ERR "DBRI: recv_fixed called on " + "transmit pipe %d\n", pipe); return; } @@ -1064,7 +1072,7 @@ static void recv_fixed(struct snd_dbri * dbri, int pipe, volatile __u32 * ptr) * * Lock must be held before calling this. */ -static int setup_descs(struct snd_dbri * dbri, int streamno, unsigned int period) +static int setup_descs(struct snd_dbri *dbri, int streamno, unsigned int period) { struct dbri_streaminfo *info = &dbri->stream_info[streamno]; __u32 dvma_buffer; @@ -1089,21 +1097,23 @@ static int setup_descs(struct snd_dbri * dbri, int streamno, unsigned int period if (streamno == DBRI_PLAY) { if (!(dbri->pipes[info->pipe].sdp & D_SDP_TO_SER)) { - printk(KERN_ERR "DBRI: setup_descs: Called on receive pipe %d\n", - info->pipe); + printk(KERN_ERR "DBRI: setup_descs: " + "Called on receive pipe %d\n", info->pipe); return -2; } } else { if (dbri->pipes[info->pipe].sdp & D_SDP_TO_SER) { - printk(KERN_ERR + printk(KERN_ERR "DBRI: setup_descs: Called on transmit pipe %d\n", info->pipe); return -2; } - /* Should be able to queue multiple buffers to receive on a pipe */ + /* Should be able to queue multiple buffers + * to receive on a pipe + */ if (pipe_active(dbri, info->pipe)) { - printk(KERN_ERR "DBRI: recv_on_pipe: Called on active pipe %d\n", - info->pipe); + printk(KERN_ERR "DBRI: recv_on_pipe: " + "Called on active pipe %d\n", info->pipe); return -2; } @@ -1113,11 +1123,13 @@ static int setup_descs(struct snd_dbri * dbri, int streamno, unsigned int period /* Free descriptors if pipe has any */ desc = dbri->pipes[info->pipe].first_desc; - if ( desc >= 0) + if (desc >= 0) do { - dbri->dma->desc[desc].nda = dbri->dma->desc[desc].ba = 0; + dbri->dma->desc[desc].ba = 0; + dbri->dma->desc[desc].nda = 0; desc = dbri->next_desc[desc]; - } while (desc != -1 && desc != dbri->pipes[info->pipe].first_desc); + } while (desc != -1 && + desc != dbri->pipes[info->pipe].first_desc); dbri->pipes[info->pipe].desc = -1; dbri->pipes[info->pipe].first_desc = -1; @@ -1130,6 +1142,7 @@ static int setup_descs(struct snd_dbri * dbri, int streamno, unsigned int period if (!dbri->dma->desc[desc].ba) break; } + if (desc == DBRI_NO_DESCS) { printk(KERN_ERR "DBRI: setup_descs: No descriptors\n"); return -1; @@ -1150,8 +1163,7 @@ static int setup_descs(struct snd_dbri * dbri, int streamno, unsigned int period if (streamno == DBRI_PLAY) { dbri->dma->desc[desc].word1 = DBRI_TD_CNT(mylen); dbri->dma->desc[desc].word4 = 0; - dbri->dma->desc[desc].word1 |= - DBRI_TD_F | DBRI_TD_B; + dbri->dma->desc[desc].word1 |= DBRI_TD_F | DBRI_TD_B; } else { dbri->dma->desc[desc].word1 = 0; dbri->dma->desc[desc].word4 = @@ -1172,7 +1184,8 @@ static int setup_descs(struct snd_dbri * dbri, int streamno, unsigned int period } if (first_desc == -1 || last_desc == -1) { - printk(KERN_ERR "DBRI: setup_descs: Not enough descriptors available\n"); + printk(KERN_ERR "DBRI: setup_descs: " + " Not enough descriptors available\n"); return -1; } @@ -1183,14 +1196,14 @@ static int setup_descs(struct snd_dbri * dbri, int streamno, unsigned int period dbri->pipes[info->pipe].desc = first_desc; #ifdef DBRI_DEBUG - for (desc = first_desc; desc != -1; ) { + for (desc = first_desc; desc != -1;) { dprintk(D_DESC, "DESC %d: %08x %08x %08x %08x\n", desc, dbri->dma->desc[desc].word1, dbri->dma->desc[desc].ba, dbri->dma->desc[desc].nda, dbri->dma->desc[desc].word4); desc = dbri->next_desc[desc]; - if ( desc == first_desc ) + if (desc == first_desc) break; } #endif @@ -1213,7 +1226,8 @@ enum master_or_slave { CHImaster, CHIslave }; /* * Lock must not be held before calling it. */ -static void reset_chi(struct snd_dbri * dbri, enum master_or_slave master_or_slave, +static void reset_chi(struct snd_dbri *dbri, + enum master_or_slave master_or_slave, int bits_per_frame) { s32 *cmd; @@ -1222,7 +1236,7 @@ static void reset_chi(struct snd_dbri * dbri, enum master_or_slave master_or_sla /* Set CHI Anchor: Pipe 16 */ cmd = dbri_cmdlock(dbri, 4); - val = D_DTS_VO | D_DTS_VI | D_DTS_INS + val = D_DTS_VO | D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(16) | D_PIPE(16) | D_DTS_PRVOUT(16); *(cmd++) = DBRI_CMD(D_DTS, 0, val); *(cmd++) = D_TS_ANCHOR | D_TS_NEXT(16); @@ -1246,15 +1260,16 @@ static void reset_chi(struct snd_dbri * dbri, enum master_or_slave master_or_sla } else { /* Setup DBRI for CHI Master - generate clock, FS * - * BPF = bits per 8 kHz frame - * 12.288 MHz / CHICM_divisor = clock rate - * FD = 1 - drive CHIFS on rising edge of CHICK + * BPF = bits per 8 kHz frame + * 12.288 MHz / CHICM_divisor = clock rate + * FD = 1 - drive CHIFS on rising edge of CHICK */ int clockrate = bits_per_frame * 8; int divisor = 12288 / clockrate; if (divisor > 255 || divisor * clockrate != 12288) - printk(KERN_ERR "DBRI: illegal bits_per_frame in setup_chi\n"); + printk(KERN_ERR "DBRI: illegal bits_per_frame " + "in setup_chi\n"); *(cmd++) = DBRI_CMD(D_CHI, 0, D_CHI_CHICM(divisor) | D_CHI_FD | D_CHI_BPF(bits_per_frame)); @@ -1288,7 +1303,7 @@ to the DBRI via the CHI interface and few of the DBRI's PIO pins. * Lock must not be held before calling it. */ -static void cs4215_setup_pipes(struct snd_dbri * dbri) +static __devinit void cs4215_setup_pipes(struct snd_dbri *dbri) { unsigned long flags; @@ -1303,9 +1318,9 @@ static void cs4215_setup_pipes(struct snd_dbri * dbri) * not relevant for us (only for doublechecking). * * Control mode: - * Pipe 17: Send timeslots 1-4 (slots 5-8 are readonly) + * Pipe 17: Send timeslots 1-4 (slots 5-8 are read only) * Pipe 18: Receive timeslot 1 (clb). - * Pipe 19: Receive timeslot 7 (version). + * Pipe 19: Receive timeslot 7 (version). */ setup_pipe(dbri, 4, D_SDP_MEM | D_SDP_TO_SER | D_SDP_MSB); @@ -1321,7 +1336,7 @@ static void cs4215_setup_pipes(struct snd_dbri * dbri) dbri_cmdwait(dbri); } -static int cs4215_init_data(struct cs4215 *mm) +static __devinit int cs4215_init_data(struct cs4215 *mm) { /* * No action, memory resetting only. @@ -1355,7 +1370,7 @@ static int cs4215_init_data(struct cs4215 *mm) return 0; } -static void cs4215_setdata(struct snd_dbri * dbri, int muted) +static void cs4215_setdata(struct snd_dbri *dbri, int muted) { if (muted) { dbri->mm.data[0] |= 63; @@ -1387,7 +1402,7 @@ static void cs4215_setdata(struct snd_dbri * dbri, int muted) /* * Set the CS4215 to data mode. */ -static void cs4215_open(struct snd_dbri * dbri) +static void cs4215_open(struct snd_dbri *dbri) { int data_width; u32 tmp; @@ -1452,7 +1467,7 @@ static void cs4215_open(struct snd_dbri * dbri) /* * Send the control information (i.e. audio format) */ -static int cs4215_setctrl(struct snd_dbri * dbri) +static int cs4215_setctrl(struct snd_dbri *dbri) { int i, val; u32 tmp; @@ -1502,9 +1517,9 @@ static int cs4215_setctrl(struct snd_dbri * dbri) /* * Control mode: - * Pipe 17: Send timeslots 1-4 (slots 5-8 are readonly) + * Pipe 17: Send timeslots 1-4 (slots 5-8 are read only) * Pipe 18: Receive timeslot 1 (clb). - * Pipe 19: Receive timeslot 7 (version). + * Pipe 19: Receive timeslot 7 (version). */ link_time_slot(dbri, 17, 16, 16, 32, dbri->mm.offset); @@ -1522,9 +1537,9 @@ static int cs4215_setctrl(struct snd_dbri * dbri) sbus_writel(tmp, dbri->regs + REG0); spin_unlock_irqrestore(&dbri->lock, flags); - for (i = 10; ((dbri->mm.status & 0xe4) != 0x20); --i) { + for (i = 10; ((dbri->mm.status & 0xe4) != 0x20); --i) msleep_interruptible(1); - } + if (i == 0) { dprintk(D_MM, "CS4215 didn't respond to CLB (0x%02x)\n", dbri->mm.status); @@ -1556,7 +1571,7 @@ static int cs4215_setctrl(struct snd_dbri * dbri) * As part of the process we resend the settings for the data * timeslots as well. */ -static int cs4215_prepare(struct snd_dbri * dbri, unsigned int rate, +static int cs4215_prepare(struct snd_dbri *dbri, unsigned int rate, snd_pcm_format_t format, unsigned int channels) { int freq_idx; @@ -1613,7 +1628,7 @@ static int cs4215_prepare(struct snd_dbri * dbri, unsigned int rate, /* * */ -static int cs4215_init(struct snd_dbri * dbri) +static __devinit int cs4215_init(struct snd_dbri *dbri) { u32 reg2 = sbus_readl(dbri->regs + REG2); dprintk(D_MM, "cs4215_init: reg2=0x%x\n", reg2); @@ -1674,7 +1689,7 @@ interrupts are disabled. /* xmit_descs() * - * Starts transmiting the current TD's for recording/playing. + * Starts transmitting the current TD's for recording/playing. * For playback, ALSA has filled the DMA memory with new data (we hope). */ static void xmit_descs(struct snd_dbri *dbri) @@ -1701,7 +1716,8 @@ static void xmit_descs(struct snd_dbri *dbri) *(cmd++) = DBRI_CMD(D_SDP, 0, dbri->pipes[info->pipe].sdp | D_SDP_P | D_SDP_EVERY | D_SDP_C); - *(cmd++) = dbri->dma_dvma + dbri_dma_off(desc, first_td); + *(cmd++) = dbri->dma_dvma + + dbri_dma_off(desc, first_td); dbri_cmdsend(dbri, cmd, 2); /* Reset our admin of the pipe. */ @@ -1722,7 +1738,8 @@ static void xmit_descs(struct snd_dbri *dbri) *(cmd++) = DBRI_CMD(D_SDP, 0, dbri->pipes[info->pipe].sdp | D_SDP_P | D_SDP_EVERY | D_SDP_C); - *(cmd++) = dbri->dma_dvma + dbri_dma_off(desc, first_td); + *(cmd++) = dbri->dma_dvma + + dbri_dma_off(desc, first_td); dbri_cmdsend(dbri, cmd, 2); /* Reset our admin of the pipe. */ @@ -1747,15 +1764,12 @@ static void xmit_descs(struct snd_dbri *dbri) * */ -static void transmission_complete_intr(struct snd_dbri * dbri, int pipe) +static void transmission_complete_intr(struct snd_dbri *dbri, int pipe) { - struct dbri_streaminfo *info; - int td; + struct dbri_streaminfo *info = &dbri->stream_info[DBRI_PLAY]; + int td = dbri->pipes[pipe].desc; int status; - info = &dbri->stream_info[DBRI_PLAY]; - - td = dbri->pipes[pipe].desc; while (td >= 0) { if (td >= DBRI_NO_DESCS) { printk(KERN_ERR "DBRI: invalid td on pipe %d\n", pipe); @@ -1763,9 +1777,8 @@ static void transmission_complete_intr(struct snd_dbri * dbri, int pipe) } status = DBRI_TD_STATUS(dbri->dma->desc[td].word4); - if (!(status & DBRI_TD_TBC)) { + if (!(status & DBRI_TD_TBC)) break; - } dprintk(D_INT, "TD %d, status 0x%02x\n", td, status); @@ -1777,15 +1790,12 @@ static void transmission_complete_intr(struct snd_dbri * dbri, int pipe) } /* Notify ALSA */ - if (spin_is_locked(&dbri->lock)) { - spin_unlock(&dbri->lock); - snd_pcm_period_elapsed(info->substream); - spin_lock(&dbri->lock); - } else - snd_pcm_period_elapsed(info->substream); + spin_unlock(&dbri->lock); + snd_pcm_period_elapsed(info->substream); + spin_lock(&dbri->lock); } -static void reception_complete_intr(struct snd_dbri * dbri, int pipe) +static void reception_complete_intr(struct snd_dbri *dbri, int pipe) { struct dbri_streaminfo *info; int rd = dbri->pipes[pipe].desc; @@ -1809,15 +1819,12 @@ static void reception_complete_intr(struct snd_dbri * dbri, int pipe) rd, DBRI_RD_STATUS(status), DBRI_RD_CNT(status)); /* Notify ALSA */ - if (spin_is_locked(&dbri->lock)) { - spin_unlock(&dbri->lock); - snd_pcm_period_elapsed(info->substream); - spin_lock(&dbri->lock); - } else - snd_pcm_period_elapsed(info->substream); + spin_unlock(&dbri->lock); + snd_pcm_period_elapsed(info->substream); + spin_lock(&dbri->lock); } -static void dbri_process_one_interrupt(struct snd_dbri * dbri, int x) +static void dbri_process_one_interrupt(struct snd_dbri *dbri, int x) { int val = D_INTR_GETVAL(x); int channel = D_INTR_GETCHAN(x); @@ -1889,7 +1896,7 @@ static void dbri_process_one_interrupt(struct snd_dbri * dbri, int x) * right now). Non-zero words require processing and are handed off * to dbri_process_one_interrupt AFTER advancing the pointer. */ -static void dbri_process_interrupt_buffer(struct snd_dbri * dbri) +static void dbri_process_interrupt_buffer(struct snd_dbri *dbri) { s32 x; @@ -1965,20 +1972,20 @@ static irqreturn_t snd_dbri_interrupt(int irq, void *dev_id) PCM Interface ****************************************************************************/ static struct snd_pcm_hardware snd_dbri_pcm_hw = { - .info = (SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP_VALID), - .formats = SNDRV_PCM_FMTBIT_MU_LAW | - SNDRV_PCM_FMTBIT_A_LAW | - SNDRV_PCM_FMTBIT_U8 | - SNDRV_PCM_FMTBIT_S16_BE, - .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_5512, + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID, + .formats = SNDRV_PCM_FMTBIT_MU_LAW | + SNDRV_PCM_FMTBIT_A_LAW | + SNDRV_PCM_FMTBIT_U8 | + SNDRV_PCM_FMTBIT_S16_BE, + .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_5512, .rate_min = 5512, .rate_max = 48000, .channels_min = 1, .channels_max = 2, - .buffer_bytes_max = (64 * 1024), + .buffer_bytes_max = 64 * 1024, .period_bytes_min = 1, .period_bytes_max = DBRI_TD_MAXCNT, .periods_min = 1, @@ -2011,7 +2018,8 @@ static int snd_hw_rule_channels(struct snd_pcm_hw_params *params, snd_interval_any(&ch); if (!(f->bits[0] & SNDRV_PCM_FMTBIT_S16_BE)) { - ch.min = ch.max = 1; + ch.min = 1; + ch.max = 1; ch.integer = 1; return snd_interval_refine(c, &ch); } @@ -2035,14 +2043,14 @@ static int snd_dbri_open(struct snd_pcm_substream *substream) info->pipe = -1; spin_unlock_irqrestore(&dbri->lock, flags); - snd_pcm_hw_rule_add(runtime,0,SNDRV_PCM_HW_PARAM_CHANNELS, + snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, snd_hw_rule_format, NULL, SNDRV_PCM_HW_PARAM_FORMAT, -1); - snd_pcm_hw_rule_add(runtime,0,SNDRV_PCM_HW_PARAM_FORMAT, - snd_hw_rule_channels, NULL, + snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT, + snd_hw_rule_channels, NULL, SNDRV_PCM_HW_PARAM_CHANNELS, -1); - + cs4215_open(dbri); return 0; @@ -2145,7 +2153,7 @@ static int snd_dbri_prepare(struct snd_pcm_substream *substream) spin_lock_irq(&dbri->lock); info->offset = 0; - /* Setup the all the transmit/receive desciptors to cover the + /* Setup the all the transmit/receive descriptors to cover the * whole DMA buffer. */ ret = setup_descs(dbri, DBRI_STREAMNO(substream), @@ -2205,12 +2213,12 @@ static struct snd_pcm_ops snd_dbri_ops = { .pointer = snd_dbri_pointer, }; -static int __devinit snd_dbri_pcm(struct snd_dbri * dbri) +static int __devinit snd_dbri_pcm(struct snd_card *card) { struct snd_pcm *pcm; int err; - if ((err = snd_pcm_new(dbri->card, + if ((err = snd_pcm_new(card, /* ID */ "sun_dbri", /* device */ 0, /* playback count */ 1, @@ -2221,16 +2229,15 @@ static int __devinit snd_dbri_pcm(struct snd_dbri * dbri) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_dbri_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_dbri_ops); - pcm->private_data = dbri; + pcm->private_data = card->private_data; pcm->info_flags = 0; - strcpy(pcm->name, dbri->card->shortname); + strcpy(pcm->name, card->shortname); if ((err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, snd_dma_continuous_data(GFP_KERNEL), - 64 * 1024, 64 * 1024)) < 0) { + 64 * 1024, 64 * 1024)) < 0) return err; - } return 0; } @@ -2245,11 +2252,10 @@ static int snd_cs4215_info_volume(struct snd_kcontrol *kcontrol, uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 2; uinfo->value.integer.min = 0; - if (kcontrol->private_value == DBRI_PLAY) { + if (kcontrol->private_value == DBRI_PLAY) uinfo->value.integer.max = DBRI_MAX_VOLUME; - } else { + else uinfo->value.integer.max = DBRI_MAX_GAIN; - } return 0; } @@ -2271,7 +2277,8 @@ static int snd_cs4215_put_volume(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_dbri *dbri = snd_kcontrol_chip(kcontrol); - struct dbri_streaminfo *info = &dbri->stream_info[kcontrol->private_value]; + struct dbri_streaminfo *info = + &dbri->stream_info[kcontrol->private_value]; int changed = 0; if (info->left_gain != ucontrol->value.integer.value[0]) { @@ -2282,7 +2289,7 @@ static int snd_cs4215_put_volume(struct snd_kcontrol *kcontrol, info->right_gain = ucontrol->value.integer.value[1]; changed = 1; } - if (changed == 1) { + if (changed) { /* First mute outputs, and wait 1/8000 sec (125 us) * to make sure this takes. This avoids clicking noises. */ @@ -2316,18 +2323,16 @@ static int snd_cs4215_get_single(struct snd_kcontrol *kcontrol, int invert = (kcontrol->private_value >> 24) & 1; snd_assert(dbri != NULL, return -EINVAL); - if (elem < 4) { + if (elem < 4) ucontrol->value.integer.value[0] = (dbri->mm.data[elem] >> shift) & mask; - } else { + else ucontrol->value.integer.value[0] = (dbri->mm.ctrl[elem - 4] >> shift) & mask; - } - if (invert == 1) { + if (invert == 1) ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; - } return 0; } @@ -2378,11 +2383,12 @@ static int snd_cs4215_put_single(struct snd_kcontrol *kcontrol, timeslots. Shift is the bit offset in the timeslot, mask defines the number of bits. invert is a boolean for use with attenuation. */ -#define CS4215_SINGLE(xname, entry, shift, mask, invert) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ - .info = snd_cs4215_info_single, \ - .get = snd_cs4215_get_single, .put = snd_cs4215_put_single, \ - .private_value = entry | (shift << 8) | (mask << 16) | (invert << 24) }, +#define CS4215_SINGLE(xname, entry, shift, mask, invert) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ + .info = snd_cs4215_info_single, \ + .get = snd_cs4215_get_single, .put = snd_cs4215_put_single, \ + .private_value = (entry) | ((shift) << 8) | ((mask) << 16) | \ + ((invert) << 24) }, static struct snd_kcontrol_new dbri_controls[] __devinitdata = { { @@ -2411,19 +2417,20 @@ static struct snd_kcontrol_new dbri_controls[] __devinitdata = { CS4215_SINGLE("Mic boost", 4, 4, 1, 1) }; -static int __init snd_dbri_mixer(struct snd_dbri * dbri) +static int __devinit snd_dbri_mixer(struct snd_card *card) { - struct snd_card *card; int idx, err; + struct snd_dbri *dbri; - snd_assert(dbri != NULL && dbri->card != NULL, return -EINVAL); + snd_assert(card != NULL && card->private_data != NULL, return -EINVAL); + dbri = card->private_data; - card = dbri->card; strcpy(card->mixername, card->shortname); for (idx = 0; idx < ARRAY_SIZE(dbri_controls); idx++) { - if ((err = snd_ctl_add(card, - snd_ctl_new1(&dbri_controls[idx], dbri))) < 0) + err = snd_ctl_add(card, + snd_ctl_new1(&dbri_controls[idx], dbri)); + if (err < 0) return err; } @@ -2438,7 +2445,8 @@ static int __init snd_dbri_mixer(struct snd_dbri * dbri) /**************************************************************************** /proc interface ****************************************************************************/ -static void dbri_regs_read(struct snd_info_entry * entry, struct snd_info_buffer *buffer) +static void dbri_regs_read(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) { struct snd_dbri *dbri = entry->private_data; @@ -2449,7 +2457,7 @@ static void dbri_regs_read(struct snd_info_entry * entry, struct snd_info_buffer } #ifdef DBRI_DEBUG -static void dbri_debug_read(struct snd_info_entry * entry, +static void dbri_debug_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { struct snd_dbri *dbri = entry->private_data; @@ -2463,7 +2471,8 @@ static void dbri_debug_read(struct snd_info_entry * entry, "Pipe %d: %s SDP=0x%x desc=%d, " "len=%d next %d\n", pipe, - ((pptr->sdp & D_SDP_TO_SER) ? "output" : "input"), + (pptr->sdp & D_SDP_TO_SER) ? "output" : + "input", pptr->sdp, pptr->desc, pptr->length, pptr->nextpipe); } @@ -2471,15 +2480,16 @@ static void dbri_debug_read(struct snd_info_entry * entry, } #endif -void snd_dbri_proc(struct snd_dbri * dbri) +void __devinit snd_dbri_proc(struct snd_card *card) { + struct snd_dbri *dbri = card->private_data; struct snd_info_entry *entry; - if (! snd_card_proc_new(dbri->card, "regs", &entry)) + if (!snd_card_proc_new(card, "regs", &entry)) snd_info_set_text_ops(entry, dbri, dbri_regs_read); #ifdef DBRI_DEBUG - if (! snd_card_proc_new(dbri->card, "debug", &entry)) { + if (!snd_card_proc_new(card, "debug", &entry)) { snd_info_set_text_ops(entry, dbri, dbri_debug_read); entry->mode = S_IFREG | S_IRUGO; /* Readable only. */ } @@ -2491,19 +2501,18 @@ void snd_dbri_proc(struct snd_dbri * dbri) **************************** Initialization ******************************** **************************************************************************** */ -static void snd_dbri_free(struct snd_dbri * dbri); +static void snd_dbri_free(struct snd_dbri *dbri); -static int __init snd_dbri_create(struct snd_card *card, +static int __devinit snd_dbri_create(struct snd_card *card, struct sbus_dev *sdev, - struct linux_prom_irqs *irq, int dev) + int irq, int dev) { struct snd_dbri *dbri = card->private_data; int err; spin_lock_init(&dbri->lock); - dbri->card = card; dbri->sdev = sdev; - dbri->irq = irq->pri; + dbri->irq = irq; dbri->dma = sbus_alloc_consistent(sdev, sizeof(struct dbri_dma), &dbri->dma_dvma); @@ -2541,13 +2550,10 @@ static int __init snd_dbri_create(struct snd_card *card, return err; } - dbri->next = dbri_list; - dbri_list = dbri; - return 0; } -static void snd_dbri_free(struct snd_dbri * dbri) +static void snd_dbri_free(struct snd_dbri *dbri) { dprintk(D_GEN, "snd_dbri_free\n"); dbri_reset(dbri); @@ -2563,20 +2569,19 @@ static void snd_dbri_free(struct snd_dbri * dbri) (void *)dbri->dma, dbri->dma_dvma); } -static int __init dbri_attach(int prom_node, struct sbus_dev *sdev) +static int __devinit dbri_probe(struct of_device *of_dev, + const struct of_device_id *match) { + struct sbus_dev *sdev = to_sbus_device(&of_dev->dev); struct snd_dbri *dbri; - struct linux_prom_irqs irq; + int irq; struct resource *rp; struct snd_card *card; static int dev = 0; int err; - if (sdev->prom_name[9] < 'e') { - printk(KERN_ERR "DBRI: unsupported chip version %c found.\n", - sdev->prom_name[9]); - return -EIO; - } + dprintk(D_GEN, "DBRI: Found %s in SBUS slot %d\n", + sdev->prom_name, sdev->slot); if (dev >= SNDRV_CARDS) return -ENODEV; @@ -2585,9 +2590,9 @@ static int __init dbri_attach(int prom_node, struct sbus_dev *sdev) return -ENOENT; } - err = prom_getproperty(prom_node, "intr", (char *)&irq, sizeof(irq)); - if (err < 0) { - printk(KERN_ERR "DBRI-%d: Firmware node lacks IRQ property.\n", dev); + irq = sdev->irqs[0]; + if (irq <= 0) { + printk(KERN_ERR "DBRI-%d: No IRQ.\n", dev); return -ENODEV; } @@ -2601,24 +2606,29 @@ static int __init dbri_attach(int prom_node, struct sbus_dev *sdev) rp = &sdev->resource[0]; sprintf(card->longname, "%s at 0x%02lx:0x%016Lx, irq %d", card->shortname, - rp->flags & 0xffL, (unsigned long long)rp->start, irq.pri); + rp->flags & 0xffL, (unsigned long long)rp->start, irq); - if ((err = snd_dbri_create(card, sdev, &irq, dev)) < 0) { + err = snd_dbri_create(card, sdev, irq, dev); + if (err < 0) { snd_card_free(card); return err; } dbri = card->private_data; - if ((err = snd_dbri_pcm(dbri)) < 0) + err = snd_dbri_pcm(card); + if (err < 0) goto _err; - if ((err = snd_dbri_mixer(dbri)) < 0) + err = snd_dbri_mixer(card); + if (err < 0) goto _err; /* /proc file handling */ - snd_dbri_proc(dbri); + snd_dbri_proc(card); + dev_set_drvdata(&of_dev->dev, card); - if ((err = snd_card_register(card)) < 0) + err = snd_card_register(card); + if (err < 0) goto _err; printk(KERN_INFO "audio%d at %p (irq %d) is DBRI(%c)+CS4215(%d)\n", @@ -2628,49 +2638,52 @@ static int __init dbri_attach(int prom_node, struct sbus_dev *sdev) return 0; - _err: +_err: snd_dbri_free(dbri); snd_card_free(card); return err; } -/* Probe for the dbri chip and then attach the driver. */ -static int __init dbri_init(void) +static int __devexit dbri_remove(struct of_device *dev) { - struct sbus_bus *sbus; - struct sbus_dev *sdev; - int found = 0; - - /* Probe each SBUS for the DBRI chip(s). */ - for_all_sbusdev(sdev, sbus) { - /* - * The version is coded in the last character - */ - if (!strncmp(sdev->prom_name, "SUNW,DBRI", 9)) { - dprintk(D_GEN, "DBRI: Found %s in SBUS slot %d\n", - sdev->prom_name, sdev->slot); + struct snd_card *card = dev_get_drvdata(&dev->dev); - if (dbri_attach(sdev->prom_node, sdev) == 0) - found++; - } - } + snd_dbri_free(card->private_data); + snd_card_free(card); + + dev_set_drvdata(&dev->dev, NULL); + + return 0; +} + +static struct of_device_id dbri_match[] = { + { + .name = "SUNW,DBRIe", + }, + { + .name = "SUNW,DBRIf", + }, + {}, +}; + +MODULE_DEVICE_TABLE(of, dbri_match); + +static struct of_platform_driver dbri_sbus_driver = { + .name = "dbri", + .match_table = dbri_match, + .probe = dbri_probe, + .remove = __devexit_p(dbri_remove), +}; - return (found > 0) ? 0 : -EIO; +/* Probe for the dbri chip and then attach the driver. */ +static int __init dbri_init(void) +{ + return of_register_driver(&dbri_sbus_driver, &sbus_bus_type); } static void __exit dbri_exit(void) { - struct snd_dbri *this = dbri_list; - - while (this != NULL) { - struct snd_dbri *next = this->next; - struct snd_card *card = this->card; - - snd_dbri_free(this); - snd_card_free(card); - this = next; - } - dbri_list = NULL; + of_unregister_driver(&dbri_sbus_driver); } module_init(dbri_init); diff --git a/sound/spi/Kconfig b/sound/spi/Kconfig new file mode 100644 index 00000000000..0d08c29213c --- /dev/null +++ b/sound/spi/Kconfig @@ -0,0 +1,31 @@ +#SPI drivers + +menu "SPI devices" + depends on SND != n + +config SND_AT73C213 + tristate "Atmel AT73C213 DAC driver" + depends on ATMEL_SSC + select SND_PCM + help + Say Y here if you want to use the Atmel AT73C213 external DAC. This + DAC can be found on Atmel development boards. + + This driver requires the Atmel SSC driver for sound sink, a + peripheral found on most AT91 and AVR32 microprocessors. + + To compile this driver as a module, choose M here: the module will be + called snd-at73c213. + +config SND_AT73C213_TARGET_BITRATE + int "Target bitrate for AT73C213" + depends on SND_AT73C213 + default "48000" + range 8000 50000 + help + Sets the target bitrate for the bitrate calculator in the driver. + Limited by hardware to be between 8000 Hz and 50000 Hz. + + Set to 48000 Hz by default. + +endmenu diff --git a/sound/spi/Makefile b/sound/spi/Makefile new file mode 100644 index 00000000000..026fb73f887 --- /dev/null +++ b/sound/spi/Makefile @@ -0,0 +1,5 @@ +# Makefile for SPI drivers + +snd-at73c213-objs := at73c213.o + +obj-$(CONFIG_SND_AT73C213) += snd-at73c213.o diff --git a/sound/spi/at73c213.c b/sound/spi/at73c213.c new file mode 100644 index 00000000000..fee869bcc95 --- /dev/null +++ b/sound/spi/at73c213.c @@ -0,0 +1,1129 @@ +/* + * Driver for AT73C213 16-bit stereo DAC connected to Atmel SSC + * + * Copyright (C) 2006-2007 Atmel Norway + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +/*#define DEBUG*/ + +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/dma-mapping.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/io.h> + +#include <sound/driver.h> +#include <sound/initval.h> +#include <sound/control.h> +#include <sound/core.h> +#include <sound/pcm.h> + +#include <linux/atmel-ssc.h> + +#include <linux/spi/spi.h> +#include <linux/spi/at73c213.h> + +#include "at73c213.h" + +#define BITRATE_MIN 8000 /* Hardware limit? */ +#define BITRATE_TARGET CONFIG_SND_AT73C213_TARGET_BITRATE +#define BITRATE_MAX 50000 /* Hardware limit. */ + +/* Initial (hardware reset) AT73C213 register values. */ +static u8 snd_at73c213_original_image[18] = +{ + 0x00, /* 00 - CTRL */ + 0x05, /* 01 - LLIG */ + 0x05, /* 02 - RLIG */ + 0x08, /* 03 - LPMG */ + 0x08, /* 04 - RPMG */ + 0x00, /* 05 - LLOG */ + 0x00, /* 06 - RLOG */ + 0x22, /* 07 - OLC */ + 0x09, /* 08 - MC */ + 0x00, /* 09 - CSFC */ + 0x00, /* 0A - MISC */ + 0x00, /* 0B - */ + 0x00, /* 0C - PRECH */ + 0x05, /* 0D - AUXG */ + 0x00, /* 0E - */ + 0x00, /* 0F - */ + 0x00, /* 10 - RST */ + 0x00, /* 11 - PA_CTRL */ +}; + +struct snd_at73c213 { + struct snd_card *card; + struct snd_pcm *pcm; + struct snd_pcm_substream *substream; + struct at73c213_board_info *board; + int irq; + int period; + unsigned long bitrate; + struct clk *bitclk; + struct ssc_device *ssc; + struct spi_device *spi; + u8 spi_wbuffer[2]; + u8 spi_rbuffer[2]; + /* Image of the SPI registers in AT73C213. */ + u8 reg_image[18]; + /* Protect registers against concurrent access. */ + spinlock_t lock; +}; + +#define get_chip(card) ((struct snd_at73c213 *)card->private_data) + +static int +snd_at73c213_write_reg(struct snd_at73c213 *chip, u8 reg, u8 val) +{ + struct spi_message msg; + struct spi_transfer msg_xfer = { + .len = 2, + .cs_change = 0, + }; + int retval; + + spi_message_init(&msg); + + chip->spi_wbuffer[0] = reg; + chip->spi_wbuffer[1] = val; + + msg_xfer.tx_buf = chip->spi_wbuffer; + msg_xfer.rx_buf = chip->spi_rbuffer; + spi_message_add_tail(&msg_xfer, &msg); + + retval = spi_sync(chip->spi, &msg); + + if (!retval) + chip->reg_image[reg] = val; + + return retval; +} + +static struct snd_pcm_hardware snd_at73c213_playback_hw = { + .info = SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER, + .formats = SNDRV_PCM_FMTBIT_S16_BE, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 8000, /* Replaced by chip->bitrate later. */ + .rate_max = 50000, /* Replaced by chip->bitrate later. */ + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = 64 * 1024 - 1, + .period_bytes_min = 512, + .period_bytes_max = 64 * 1024 - 1, + .periods_min = 4, + .periods_max = 1024, +}; + +/* + * Calculate and set bitrate and divisions. + */ +static int snd_at73c213_set_bitrate(struct snd_at73c213 *chip) +{ + unsigned long ssc_rate = clk_get_rate(chip->ssc->clk); + unsigned long dac_rate_new, ssc_div, status; + unsigned long ssc_div_max, ssc_div_min; + int max_tries; + + /* + * We connect two clocks here, picking divisors so the I2S clocks + * out data at the same rate the DAC clocks it in ... and as close + * as practical to the desired target rate. + * + * The DAC master clock (MCLK) is programmable, and is either 256 + * or (not here) 384 times the I2S output clock (BCLK). + */ + + /* SSC clock / (bitrate * stereo * 16-bit). */ + ssc_div = ssc_rate / (BITRATE_TARGET * 2 * 16); + ssc_div_min = ssc_rate / (BITRATE_MAX * 2 * 16); + ssc_div_max = ssc_rate / (BITRATE_MIN * 2 * 16); + max_tries = (ssc_div_max - ssc_div_min) / 2; + + if (max_tries < 1) + max_tries = 1; + + /* ssc_div must be a power of 2. */ + ssc_div = (ssc_div + 1) & ~1UL; + + if ((ssc_rate / (ssc_div * 2 * 16)) < BITRATE_MIN) { + ssc_div -= 2; + if ((ssc_rate / (ssc_div * 2 * 16)) > BITRATE_MAX) + return -ENXIO; + } + + /* Search for a possible bitrate. */ + do { + /* SSC clock / (ssc divider * 16-bit * stereo). */ + if ((ssc_rate / (ssc_div * 2 * 16)) < BITRATE_MIN) + return -ENXIO; + + /* 256 / (2 * 16) = 8 */ + dac_rate_new = 8 * (ssc_rate / ssc_div); + + status = clk_round_rate(chip->board->dac_clk, dac_rate_new); + if (status < 0) + return status; + + /* Ignore difference smaller than 256 Hz. */ + if ((status/256) == (dac_rate_new/256)) + goto set_rate; + + ssc_div += 2; + } while (--max_tries); + + /* Not able to find a valid bitrate. */ + return -ENXIO; + +set_rate: + status = clk_set_rate(chip->board->dac_clk, status); + if (status < 0) + return status; + + /* Set divider in SSC device. */ + ssc_writel(chip->ssc->regs, CMR, ssc_div/2); + + /* SSC clock / (ssc divider * 16-bit * stereo). */ + chip->bitrate = ssc_rate / (ssc_div * 16 * 2); + + dev_info(&chip->spi->dev, + "at73c213: supported bitrate is %lu (%lu divider)\n", + chip->bitrate, ssc_div); + + return 0; +} + +static int snd_at73c213_pcm_open(struct snd_pcm_substream *substream) +{ + struct snd_at73c213 *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + + snd_at73c213_playback_hw.rate_min = chip->bitrate; + snd_at73c213_playback_hw.rate_max = chip->bitrate; + runtime->hw = snd_at73c213_playback_hw; + chip->substream = substream; + + return 0; +} + +static int snd_at73c213_pcm_close(struct snd_pcm_substream *substream) +{ + struct snd_at73c213 *chip = snd_pcm_substream_chip(substream); + chip->substream = NULL; + return 0; +} + +static int snd_at73c213_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + return snd_pcm_lib_malloc_pages(substream, + params_buffer_bytes(hw_params)); +} + +static int snd_at73c213_pcm_hw_free(struct snd_pcm_substream *substream) +{ + return snd_pcm_lib_free_pages(substream); +} + +static int snd_at73c213_pcm_prepare(struct snd_pcm_substream *substream) +{ + struct snd_at73c213 *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + int block_size; + + block_size = frames_to_bytes(runtime, runtime->period_size); + + chip->period = 0; + + ssc_writel(chip->ssc->regs, PDC_TPR, + (long)runtime->dma_addr); + ssc_writel(chip->ssc->regs, PDC_TCR, runtime->period_size * 2); + ssc_writel(chip->ssc->regs, PDC_TNPR, + (long)runtime->dma_addr + block_size); + ssc_writel(chip->ssc->regs, PDC_TNCR, runtime->period_size * 2); + + return 0; +} + +static int snd_at73c213_pcm_trigger(struct snd_pcm_substream *substream, + int cmd) +{ + struct snd_at73c213 *chip = snd_pcm_substream_chip(substream); + int retval = 0; + + spin_lock(&chip->lock); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + ssc_writel(chip->ssc->regs, IER, SSC_BIT(IER_ENDTX)); + ssc_writel(chip->ssc->regs, PDC_PTCR, SSC_BIT(PDC_PTCR_TXTEN)); + break; + case SNDRV_PCM_TRIGGER_STOP: + ssc_writel(chip->ssc->regs, PDC_PTCR, SSC_BIT(PDC_PTCR_TXTDIS)); + ssc_writel(chip->ssc->regs, IDR, SSC_BIT(IDR_ENDTX)); + break; + default: + dev_dbg(&chip->spi->dev, "spurious command %x\n", cmd); + retval = -EINVAL; + break; + } + + spin_unlock(&chip->lock); + + return retval; +} + +static snd_pcm_uframes_t +snd_at73c213_pcm_pointer(struct snd_pcm_substream *substream) +{ + struct snd_at73c213 *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + snd_pcm_uframes_t pos; + unsigned long bytes; + + bytes = ssc_readl(chip->ssc->regs, PDC_TPR) + - (unsigned long)runtime->dma_addr; + + pos = bytes_to_frames(runtime, bytes); + if (pos >= runtime->buffer_size) + pos -= runtime->buffer_size; + + return pos; +} + +static struct snd_pcm_ops at73c213_playback_ops = { + .open = snd_at73c213_pcm_open, + .close = snd_at73c213_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_at73c213_pcm_hw_params, + .hw_free = snd_at73c213_pcm_hw_free, + .prepare = snd_at73c213_pcm_prepare, + .trigger = snd_at73c213_pcm_trigger, + .pointer = snd_at73c213_pcm_pointer, +}; + +static void snd_at73c213_pcm_free(struct snd_pcm *pcm) +{ + struct snd_at73c213 *chip = snd_pcm_chip(pcm); + if (chip->pcm) { + snd_pcm_lib_preallocate_free_for_all(chip->pcm); + chip->pcm = NULL; + } +} + +static int __devinit snd_at73c213_pcm_new(struct snd_at73c213 *chip, int device) +{ + struct snd_pcm *pcm; + int retval; + + retval = snd_pcm_new(chip->card, chip->card->shortname, + device, 1, 0, &pcm); + if (retval < 0) + goto out; + + pcm->private_data = chip; + pcm->private_free = snd_at73c213_pcm_free; + pcm->info_flags = SNDRV_PCM_INFO_BLOCK_TRANSFER; + strcpy(pcm->name, "at73c213"); + chip->pcm = pcm; + + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &at73c213_playback_ops); + + retval = snd_pcm_lib_preallocate_pages_for_all(chip->pcm, + SNDRV_DMA_TYPE_DEV, &chip->ssc->pdev->dev, + 64 * 1024, 64 * 1024); +out: + return retval; +} + +static irqreturn_t snd_at73c213_interrupt(int irq, void *dev_id) +{ + struct snd_at73c213 *chip = dev_id; + struct snd_pcm_runtime *runtime = chip->substream->runtime; + u32 status; + int offset; + int block_size; + int next_period; + int retval = IRQ_NONE; + + spin_lock(&chip->lock); + + block_size = frames_to_bytes(runtime, runtime->period_size); + status = ssc_readl(chip->ssc->regs, IMR); + + if (status & SSC_BIT(IMR_ENDTX)) { + chip->period++; + if (chip->period == runtime->periods) + chip->period = 0; + next_period = chip->period + 1; + if (next_period == runtime->periods) + next_period = 0; + + offset = block_size * next_period; + + ssc_writel(chip->ssc->regs, PDC_TNPR, + (long)runtime->dma_addr + offset); + ssc_writel(chip->ssc->regs, PDC_TNCR, runtime->period_size * 2); + retval = IRQ_HANDLED; + } + + ssc_readl(chip->ssc->regs, IMR); + spin_unlock(&chip->lock); + + if (status & SSC_BIT(IMR_ENDTX)) + snd_pcm_period_elapsed(chip->substream); + + return retval; +} + +/* + * Mixer functions. + */ +static int snd_at73c213_mono_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_at73c213 *chip = snd_kcontrol_chip(kcontrol); + int reg = kcontrol->private_value & 0xff; + int shift = (kcontrol->private_value >> 8) & 0xff; + int mask = (kcontrol->private_value >> 16) & 0xff; + int invert = (kcontrol->private_value >> 24) & 0xff; + + spin_lock_irq(&chip->lock); + + ucontrol->value.integer.value[0] = + (chip->reg_image[reg] >> shift) & mask; + + if (invert) + ucontrol->value.integer.value[0] = + mask - ucontrol->value.integer.value[0]; + + spin_unlock_irq(&chip->lock); + + return 0; +} + +static int snd_at73c213_mono_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_at73c213 *chip = snd_kcontrol_chip(kcontrol); + int reg = kcontrol->private_value & 0xff; + int shift = (kcontrol->private_value >> 8) & 0xff; + int mask = (kcontrol->private_value >> 16) & 0xff; + int invert = (kcontrol->private_value >> 24) & 0xff; + int change, retval; + unsigned short val; + + val = (ucontrol->value.integer.value[0] & mask); + if (invert) + val = mask - val; + val <<= shift; + + spin_lock_irq(&chip->lock); + + val = (chip->reg_image[reg] & ~(mask << shift)) | val; + change = val != chip->reg_image[reg]; + retval = snd_at73c213_write_reg(chip, reg, val); + + spin_unlock_irq(&chip->lock); + + if (retval) + return retval; + + return change; +} + +static int snd_at73c213_stereo_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + int mask = (kcontrol->private_value >> 24) & 0xff; + + if (mask == 1) + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + else + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = mask; + + return 0; +} + +static int snd_at73c213_stereo_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_at73c213 *chip = snd_kcontrol_chip(kcontrol); + int left_reg = kcontrol->private_value & 0xff; + int right_reg = (kcontrol->private_value >> 8) & 0xff; + int shift_left = (kcontrol->private_value >> 16) & 0x07; + int shift_right = (kcontrol->private_value >> 19) & 0x07; + int mask = (kcontrol->private_value >> 24) & 0xff; + int invert = (kcontrol->private_value >> 22) & 1; + + spin_lock_irq(&chip->lock); + + ucontrol->value.integer.value[0] = + (chip->reg_image[left_reg] >> shift_left) & mask; + ucontrol->value.integer.value[1] = + (chip->reg_image[right_reg] >> shift_right) & mask; + + if (invert) { + ucontrol->value.integer.value[0] = + mask - ucontrol->value.integer.value[0]; + ucontrol->value.integer.value[1] = + mask - ucontrol->value.integer.value[1]; + } + + spin_unlock_irq(&chip->lock); + + return 0; +} + +static int snd_at73c213_stereo_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_at73c213 *chip = snd_kcontrol_chip(kcontrol); + int left_reg = kcontrol->private_value & 0xff; + int right_reg = (kcontrol->private_value >> 8) & 0xff; + int shift_left = (kcontrol->private_value >> 16) & 0x07; + int shift_right = (kcontrol->private_value >> 19) & 0x07; + int mask = (kcontrol->private_value >> 24) & 0xff; + int invert = (kcontrol->private_value >> 22) & 1; + int change, retval; + unsigned short val1, val2; + + val1 = ucontrol->value.integer.value[0] & mask; + val2 = ucontrol->value.integer.value[1] & mask; + if (invert) { + val1 = mask - val1; + val2 = mask - val2; + } + val1 <<= shift_left; + val2 <<= shift_right; + + spin_lock_irq(&chip->lock); + + val1 = (chip->reg_image[left_reg] & ~(mask << shift_left)) | val1; + val2 = (chip->reg_image[right_reg] & ~(mask << shift_right)) | val2; + change = val1 != chip->reg_image[left_reg] + || val2 != chip->reg_image[right_reg]; + retval = snd_at73c213_write_reg(chip, left_reg, val1); + if (retval) { + spin_unlock_irq(&chip->lock); + goto out; + } + retval = snd_at73c213_write_reg(chip, right_reg, val2); + if (retval) { + spin_unlock_irq(&chip->lock); + goto out; + } + + spin_unlock_irq(&chip->lock); + + return change; + +out: + return retval; +} + +static int snd_at73c213_mono_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; +} + +static int snd_at73c213_mono_switch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_at73c213 *chip = snd_kcontrol_chip(kcontrol); + int reg = kcontrol->private_value & 0xff; + int shift = (kcontrol->private_value >> 8) & 0xff; + int invert = (kcontrol->private_value >> 24) & 0xff; + + spin_lock_irq(&chip->lock); + + ucontrol->value.integer.value[0] = + (chip->reg_image[reg] >> shift) & 0x01; + + if (invert) + ucontrol->value.integer.value[0] = + 0x01 - ucontrol->value.integer.value[0]; + + spin_unlock_irq(&chip->lock); + + return 0; +} + +static int snd_at73c213_mono_switch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_at73c213 *chip = snd_kcontrol_chip(kcontrol); + int reg = kcontrol->private_value & 0xff; + int shift = (kcontrol->private_value >> 8) & 0xff; + int mask = (kcontrol->private_value >> 16) & 0xff; + int invert = (kcontrol->private_value >> 24) & 0xff; + int change, retval; + unsigned short val; + + if (ucontrol->value.integer.value[0]) + val = mask; + else + val = 0; + + if (invert) + val = mask - val; + val <<= shift; + + spin_lock_irq(&chip->lock); + + val |= (chip->reg_image[reg] & ~(mask << shift)); + change = val != chip->reg_image[reg]; + + retval = snd_at73c213_write_reg(chip, reg, val); + + spin_unlock_irq(&chip->lock); + + if (retval) + return retval; + + return change; +} + +static int snd_at73c213_pa_volume_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = ((kcontrol->private_value >> 16) & 0xff) - 1; + + return 0; +} + +static int snd_at73c213_line_capture_volume_info( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + /* When inverted will give values 0x10001 => 0. */ + uinfo->value.integer.min = 14; + uinfo->value.integer.max = 31; + + return 0; +} + +static int snd_at73c213_aux_capture_volume_info( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + /* When inverted will give values 0x10001 => 0. */ + uinfo->value.integer.min = 14; + uinfo->value.integer.max = 31; + + return 0; +} + +#define AT73C213_MONO_SWITCH(xname, xindex, reg, shift, mask, invert) \ +{ \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .index = xindex, \ + .info = snd_at73c213_mono_switch_info, \ + .get = snd_at73c213_mono_switch_get, \ + .put = snd_at73c213_mono_switch_put, \ + .private_value = (reg | (shift << 8) | (mask << 16) | (invert << 24)) \ +} + +#define AT73C213_STEREO(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \ +{ \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .index = xindex, \ + .info = snd_at73c213_stereo_info, \ + .get = snd_at73c213_stereo_get, \ + .put = snd_at73c213_stereo_put, \ + .private_value = (left_reg | (right_reg << 8) \ + | (shift_left << 16) | (shift_right << 19) \ + | (mask << 24) | (invert << 22)) \ +} + +static struct snd_kcontrol_new snd_at73c213_controls[] __devinitdata = { +AT73C213_STEREO("Master Playback Volume", 0, DAC_LMPG, DAC_RMPG, 0, 0, 0x1f, 1), +AT73C213_STEREO("Master Playback Switch", 0, DAC_LMPG, DAC_RMPG, 5, 5, 1, 1), +AT73C213_STEREO("PCM Playback Volume", 0, DAC_LLOG, DAC_RLOG, 0, 0, 0x1f, 1), +AT73C213_STEREO("PCM Playback Switch", 0, DAC_LLOG, DAC_RLOG, 5, 5, 1, 1), +AT73C213_MONO_SWITCH("Mono PA Playback Switch", 0, DAC_CTRL, DAC_CTRL_ONPADRV, + 0x01, 0), +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "PA Playback Volume", + .index = 0, + .info = snd_at73c213_pa_volume_info, + .get = snd_at73c213_mono_get, + .put = snd_at73c213_mono_put, + .private_value = PA_CTRL | (PA_CTRL_APAGAIN << 8) | \ + (0x0f << 16) | (1 << 24), +}, +AT73C213_MONO_SWITCH("PA High Gain Playback Switch", 0, PA_CTRL, PA_CTRL_APALP, + 0x01, 1), +AT73C213_MONO_SWITCH("PA Playback Switch", 0, PA_CTRL, PA_CTRL_APAON, 0x01, 0), +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Aux Capture Volume", + .index = 0, + .info = snd_at73c213_aux_capture_volume_info, + .get = snd_at73c213_mono_get, + .put = snd_at73c213_mono_put, + .private_value = DAC_AUXG | (0 << 8) | (0x1f << 16) | (1 << 24), +}, +AT73C213_MONO_SWITCH("Aux Capture Switch", 0, DAC_CTRL, DAC_CTRL_ONAUXIN, + 0x01, 0), +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Line Capture Volume", + .index = 0, + .info = snd_at73c213_line_capture_volume_info, + .get = snd_at73c213_stereo_get, + .put = snd_at73c213_stereo_put, + .private_value = DAC_LLIG | (DAC_RLIG << 8) | (0 << 16) | (0 << 19) + | (0x1f << 24) | (1 << 22), +}, +AT73C213_MONO_SWITCH("Line Capture Switch", 0, DAC_CTRL, 0, 0x03, 0), +}; + +static int __devinit snd_at73c213_mixer(struct snd_at73c213 *chip) +{ + struct snd_card *card; + int errval, idx; + + if (chip == NULL || chip->pcm == NULL) + return -EINVAL; + + card = chip->card; + + strcpy(card->mixername, chip->pcm->name); + + for (idx = 0; idx < ARRAY_SIZE(snd_at73c213_controls); idx++) { + errval = snd_ctl_add(card, + snd_ctl_new1(&snd_at73c213_controls[idx], + chip)); + if (errval < 0) + goto cleanup; + } + + return 0; + +cleanup: + for (idx = 1; idx < ARRAY_SIZE(snd_at73c213_controls) + 1; idx++) { + struct snd_kcontrol *kctl; + kctl = snd_ctl_find_numid(card, idx); + if (kctl) + snd_ctl_remove(card, kctl); + } + return errval; +} + +/* + * Device functions + */ +static int snd_at73c213_ssc_init(struct snd_at73c213 *chip) +{ + /* + * Continuous clock output. + * Starts on falling TF. + * Delay 1 cycle (1 bit). + * Periode is 16 bit (16 - 1). + */ + ssc_writel(chip->ssc->regs, TCMR, + SSC_BF(TCMR_CKO, 1) + | SSC_BF(TCMR_START, 4) + | SSC_BF(TCMR_STTDLY, 1) + | SSC_BF(TCMR_PERIOD, 16 - 1)); + /* + * Data length is 16 bit (16 - 1). + * Transmit MSB first. + * Transmit 2 words each transfer. + * Frame sync length is 16 bit (16 - 1). + * Frame starts on negative pulse. + */ + ssc_writel(chip->ssc->regs, TFMR, + SSC_BF(TFMR_DATLEN, 16 - 1) + | SSC_BIT(TFMR_MSBF) + | SSC_BF(TFMR_DATNB, 1) + | SSC_BF(TFMR_FSLEN, 16 - 1) + | SSC_BF(TFMR_FSOS, 1)); + + return 0; +} + +static int snd_at73c213_chip_init(struct snd_at73c213 *chip) +{ + int retval; + unsigned char dac_ctrl = 0; + + retval = snd_at73c213_set_bitrate(chip); + if (retval) + goto out; + + /* Enable DAC master clock. */ + clk_enable(chip->board->dac_clk); + + /* Initialize at73c213 on SPI bus. */ + retval = snd_at73c213_write_reg(chip, DAC_RST, 0x04); + if (retval) + goto out_clk; + msleep(1); + retval = snd_at73c213_write_reg(chip, DAC_RST, 0x03); + if (retval) + goto out_clk; + + /* Precharge everything. */ + retval = snd_at73c213_write_reg(chip, DAC_PRECH, 0xff); + if (retval) + goto out_clk; + retval = snd_at73c213_write_reg(chip, PA_CTRL, (1<<PA_CTRL_APAPRECH)); + if (retval) + goto out_clk; + retval = snd_at73c213_write_reg(chip, DAC_CTRL, + (1<<DAC_CTRL_ONLNOL) | (1<<DAC_CTRL_ONLNOR)); + if (retval) + goto out_clk; + + msleep(50); + + /* Stop precharging PA. */ + retval = snd_at73c213_write_reg(chip, PA_CTRL, + (1<<PA_CTRL_APALP) | 0x0f); + if (retval) + goto out_clk; + + msleep(450); + + /* Stop precharging DAC, turn on master power. */ + retval = snd_at73c213_write_reg(chip, DAC_PRECH, (1<<DAC_PRECH_ONMSTR)); + if (retval) + goto out_clk; + + msleep(1); + + /* Turn on DAC. */ + dac_ctrl = (1<<DAC_CTRL_ONDACL) | (1<<DAC_CTRL_ONDACR) + | (1<<DAC_CTRL_ONLNOL) | (1<<DAC_CTRL_ONLNOR); + + retval = snd_at73c213_write_reg(chip, DAC_CTRL, dac_ctrl); + if (retval) + goto out_clk; + + /* Mute sound. */ + retval = snd_at73c213_write_reg(chip, DAC_LMPG, 0x3f); + if (retval) + goto out_clk; + retval = snd_at73c213_write_reg(chip, DAC_RMPG, 0x3f); + if (retval) + goto out_clk; + retval = snd_at73c213_write_reg(chip, DAC_LLOG, 0x3f); + if (retval) + goto out_clk; + retval = snd_at73c213_write_reg(chip, DAC_RLOG, 0x3f); + if (retval) + goto out_clk; + retval = snd_at73c213_write_reg(chip, DAC_LLIG, 0x11); + if (retval) + goto out_clk; + retval = snd_at73c213_write_reg(chip, DAC_RLIG, 0x11); + if (retval) + goto out_clk; + retval = snd_at73c213_write_reg(chip, DAC_AUXG, 0x11); + if (retval) + goto out_clk; + + /* Enable I2S device, i.e. clock output. */ + ssc_writel(chip->ssc->regs, CR, SSC_BIT(CR_TXEN)); + + goto out; + +out_clk: + clk_disable(chip->board->dac_clk); +out: + return retval; +} + +static int snd_at73c213_dev_free(struct snd_device *device) +{ + struct snd_at73c213 *chip = device->device_data; + + ssc_writel(chip->ssc->regs, CR, SSC_BIT(CR_TXDIS)); + if (chip->irq >= 0) { + free_irq(chip->irq, chip); + chip->irq = -1; + } + + return 0; +} + +static int __devinit snd_at73c213_dev_init(struct snd_card *card, + struct spi_device *spi) +{ + static struct snd_device_ops ops = { + .dev_free = snd_at73c213_dev_free, + }; + struct snd_at73c213 *chip = get_chip(card); + int irq, retval; + + irq = chip->ssc->irq; + if (irq < 0) + return irq; + + spin_lock_init(&chip->lock); + chip->card = card; + chip->irq = -1; + + retval = request_irq(irq, snd_at73c213_interrupt, 0, "at73c213", chip); + if (retval) { + dev_dbg(&chip->spi->dev, "unable to request irq %d\n", irq); + goto out; + } + chip->irq = irq; + + memcpy(&chip->reg_image, &snd_at73c213_original_image, + sizeof(snd_at73c213_original_image)); + + retval = snd_at73c213_ssc_init(chip); + if (retval) + goto out_irq; + + retval = snd_at73c213_chip_init(chip); + if (retval) + goto out_irq; + + retval = snd_at73c213_pcm_new(chip, 0); + if (retval) + goto out_irq; + + retval = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); + if (retval) + goto out_irq; + + retval = snd_at73c213_mixer(chip); + if (retval) + goto out_snd_dev; + + snd_card_set_dev(card, &spi->dev); + + goto out; + +out_snd_dev: + snd_device_free(card, chip); +out_irq: + free_irq(chip->irq, chip); + chip->irq = -1; +out: + return retval; +} + +static int snd_at73c213_probe(struct spi_device *spi) +{ + struct snd_card *card; + struct snd_at73c213 *chip; + struct at73c213_board_info *board; + int retval; + char id[16]; + + board = spi->dev.platform_data; + if (!board) { + dev_dbg(&spi->dev, "no platform_data\n"); + return -ENXIO; + } + + if (!board->dac_clk) { + dev_dbg(&spi->dev, "no DAC clk\n"); + return -ENXIO; + } + + if (IS_ERR(board->dac_clk)) { + dev_dbg(&spi->dev, "no DAC clk\n"); + return PTR_ERR(board->dac_clk); + } + + retval = -ENOMEM; + + /* Allocate "card" using some unused identifiers. */ + snprintf(id, sizeof id, "at73c213_%d", board->ssc_id); + card = snd_card_new(-1, id, THIS_MODULE, sizeof(struct snd_at73c213)); + if (!card) + goto out; + + chip = card->private_data; + chip->spi = spi; + chip->board = board; + + chip->ssc = ssc_request(board->ssc_id); + if (IS_ERR(chip->ssc)) { + dev_dbg(&spi->dev, "could not get ssc%d device\n", + board->ssc_id); + retval = PTR_ERR(chip->ssc); + goto out_card; + } + + retval = snd_at73c213_dev_init(card, spi); + if (retval) + goto out_ssc; + + strcpy(card->driver, "at73c213"); + strcpy(card->shortname, board->shortname); + sprintf(card->longname, "%s on irq %d", card->shortname, chip->irq); + + retval = snd_card_register(card); + if (retval) + goto out_ssc; + + dev_set_drvdata(&spi->dev, card); + + goto out; + +out_ssc: + ssc_free(chip->ssc); +out_card: + snd_card_free(card); +out: + return retval; +} + +static int __devexit snd_at73c213_remove(struct spi_device *spi) +{ + struct snd_card *card = dev_get_drvdata(&spi->dev); + struct snd_at73c213 *chip = card->private_data; + int retval; + + /* Stop playback. */ + ssc_writel(chip->ssc->regs, CR, SSC_BIT(CR_TXDIS)); + + /* Mute sound. */ + retval = snd_at73c213_write_reg(chip, DAC_LMPG, 0x3f); + if (retval) + goto out; + retval = snd_at73c213_write_reg(chip, DAC_RMPG, 0x3f); + if (retval) + goto out; + retval = snd_at73c213_write_reg(chip, DAC_LLOG, 0x3f); + if (retval) + goto out; + retval = snd_at73c213_write_reg(chip, DAC_RLOG, 0x3f); + if (retval) + goto out; + retval = snd_at73c213_write_reg(chip, DAC_LLIG, 0x11); + if (retval) + goto out; + retval = snd_at73c213_write_reg(chip, DAC_RLIG, 0x11); + if (retval) + goto out; + retval = snd_at73c213_write_reg(chip, DAC_AUXG, 0x11); + if (retval) + goto out; + + /* Turn off PA. */ + retval = snd_at73c213_write_reg(chip, PA_CTRL, + chip->reg_image[PA_CTRL] | 0x0f); + if (retval) + goto out; + msleep(10); + retval = snd_at73c213_write_reg(chip, PA_CTRL, + (1 << PA_CTRL_APALP) | 0x0f); + if (retval) + goto out; + + /* Turn off external DAC. */ + retval = snd_at73c213_write_reg(chip, DAC_CTRL, 0x0c); + if (retval) + goto out; + msleep(2); + retval = snd_at73c213_write_reg(chip, DAC_CTRL, 0x00); + if (retval) + goto out; + + /* Turn off master power. */ + retval = snd_at73c213_write_reg(chip, DAC_PRECH, 0x00); + if (retval) + goto out; + +out: + /* Stop DAC master clock. */ + clk_disable(chip->board->dac_clk); + + ssc_free(chip->ssc); + snd_card_free(card); + dev_set_drvdata(&spi->dev, NULL); + + return 0; +} + +#ifdef CONFIG_PM +static int snd_at73c213_suspend(struct spi_device *spi, pm_message_t msg) +{ + struct snd_card *card = dev_get_drvdata(&spi->dev); + struct snd_at73c213 *chip = card->private_data; + + ssc_writel(chip->ssc->regs, CR, SSC_BIT(CR_TXDIS)); + clk_disable(chip->board->dac_clk); + + return 0; +} + +static int snd_at73c213_resume(struct spi_device *spi) +{ + struct snd_card *card = dev_get_drvdata(&spi->dev); + struct snd_at73c213 *chip = card->private_data; + + clk_enable(chip->board->dac_clk); + ssc_writel(chip->ssc->regs, CR, SSC_BIT(CR_TXEN)); + + return 0; +} +#else +#define snd_at73c213_suspend NULL +#define snd_at73c213_resume NULL +#endif + +static struct spi_driver at73c213_driver = { + .driver = { + .name = "at73c213", + }, + .probe = snd_at73c213_probe, + .suspend = snd_at73c213_suspend, + .resume = snd_at73c213_resume, + .remove = __devexit_p(snd_at73c213_remove), +}; + +static int __init at73c213_init(void) +{ + return spi_register_driver(&at73c213_driver); +} +module_init(at73c213_init); + +static void __exit at73c213_exit(void) +{ + spi_unregister_driver(&at73c213_driver); +} +module_exit(at73c213_exit); + +MODULE_AUTHOR("Hans-Christian Egtvedt <hcegtvedt@atmel.com>"); +MODULE_DESCRIPTION("Sound driver for AT73C213 with Atmel SSC"); +MODULE_LICENSE("GPL"); diff --git a/sound/spi/at73c213.h b/sound/spi/at73c213.h new file mode 100644 index 00000000000..fd8b372df5d --- /dev/null +++ b/sound/spi/at73c213.h @@ -0,0 +1,119 @@ +/* + * Driver for the AT73C213 16-bit stereo DAC on Atmel ATSTK1000 + * + * Copyright (C) 2006 - 2007 Atmel Corporation + * + * 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. + * + * The full GNU General Public License is included in this + * distribution in the file called COPYING. + */ + +#ifndef _SND_AT73C213_H +#define _SND_AT73C213_H + +/* DAC control register */ +#define DAC_CTRL 0x00 +#define DAC_CTRL_ONPADRV 7 +#define DAC_CTRL_ONAUXIN 6 +#define DAC_CTRL_ONDACR 5 +#define DAC_CTRL_ONDACL 4 +#define DAC_CTRL_ONLNOR 3 +#define DAC_CTRL_ONLNOL 2 +#define DAC_CTRL_ONLNIR 1 +#define DAC_CTRL_ONLNIL 0 + +/* DAC left line in gain register */ +#define DAC_LLIG 0x01 +#define DAC_LLIG_LLIG 0 + +/* DAC right line in gain register */ +#define DAC_RLIG 0x02 +#define DAC_RLIG_RLIG 0 + +/* DAC Left Master Playback Gain Register */ +#define DAC_LMPG 0x03 +#define DAC_LMPG_LMPG 0 + +/* DAC Right Master Playback Gain Register */ +#define DAC_RMPG 0x04 +#define DAC_RMPG_RMPG 0 + +/* DAC Left Line Out Gain Register */ +#define DAC_LLOG 0x05 +#define DAC_LLOG_LLOG 0 + +/* DAC Right Line Out Gain Register */ +#define DAC_RLOG 0x06 +#define DAC_RLOG_RLOG 0 + +/* DAC Output Level Control Register */ +#define DAC_OLC 0x07 +#define DAC_OLC_RSHORT 7 +#define DAC_OLC_ROLC 4 +#define DAC_OLC_LSHORT 3 +#define DAC_OLC_LOLC 0 + +/* DAC Mixer Control Register */ +#define DAC_MC 0x08 +#define DAC_MC_INVR 5 +#define DAC_MC_INVL 4 +#define DAC_MC_RMSMIN2 3 +#define DAC_MC_RMSMIN1 2 +#define DAC_MC_LMSMIN2 1 +#define DAC_MC_LMSMIN1 0 + +/* DAC Clock and Sampling Frequency Control Register */ +#define DAC_CSFC 0x09 +#define DAC_CSFC_OVRSEL 4 + +/* DAC Miscellaneous Register */ +#define DAC_MISC 0x0A +#define DAC_MISC_VCMCAPSEL 7 +#define DAC_MISC_DINTSEL 4 +#define DAC_MISC_DITHEN 3 +#define DAC_MISC_DEEMPEN 2 +#define DAC_MISC_NBITS 0 + +/* DAC Precharge Control Register */ +#define DAC_PRECH 0x0C +#define DAC_PRECH_PRCHGPDRV 7 +#define DAC_PRECH_PRCHGAUX1 6 +#define DAC_PRECH_PRCHGLNOR 5 +#define DAC_PRECH_PRCHGLNOL 4 +#define DAC_PRECH_PRCHGLNIR 3 +#define DAC_PRECH_PRCHGLNIL 2 +#define DAC_PRECH_PRCHG 1 +#define DAC_PRECH_ONMSTR 0 + +/* DAC Auxiliary Input Gain Control Register */ +#define DAC_AUXG 0x0D +#define DAC_AUXG_AUXG 0 + +/* DAC Reset Register */ +#define DAC_RST 0x10 +#define DAC_RST_RESMASK 2 +#define DAC_RST_RESFILZ 1 +#define DAC_RST_RSTZ 0 + +/* Power Amplifier Control Register */ +#define PA_CTRL 0x11 +#define PA_CTRL_APAON 6 +#define PA_CTRL_APAPRECH 5 +#define PA_CTRL_APALP 4 +#define PA_CTRL_APAGAIN 0 + +#endif /* _SND_AT73C213_H */ diff --git a/sound/synth/Makefile b/sound/synth/Makefile index 986291dcb91..e99fd76caa1 100644 --- a/sound/synth/Makefile +++ b/sound/synth/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-util-mem-objs := util_mem.o diff --git a/sound/synth/emux/Makefile b/sound/synth/emux/Makefile index 32a102d2670..b69035240cf 100644 --- a/sound/synth/emux/Makefile +++ b/sound/synth/emux/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-emux-synth-objs := emux.o emux_synth.o emux_seq.o emux_nrpn.o \ diff --git a/sound/synth/util_mem.c b/sound/synth/util_mem.c index 1d9b11f345f..6fc3d2b2519 100644 --- a/sound/synth/util_mem.c +++ b/sound/synth/util_mem.c @@ -116,7 +116,7 @@ __snd_util_memblk_new(struct snd_util_memhdr *hdr, unsigned int units, if (blk == NULL) return NULL; - if (! prev || prev == &hdr->block) + if (prev == &hdr->block) blk->offset = 0; else { struct snd_util_memblk *p = get_memblk(prev); diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig index 315360f3127..706143826af 100644 --- a/sound/usb/Kconfig +++ b/sound/usb/Kconfig @@ -40,6 +40,7 @@ config SND_USB_CAIAQ namely: * Native Instruments RigKontrol2 + * Native Instruments RigKontrol3 * Native Instruments Kore Controller * Native Instruments Audio Kontrol 1 * Native Instruments Audio 8 DJ @@ -55,6 +56,7 @@ config SND_USB_CAIAQ_INPUT alpha dials and analog pedals on the following products: * Native Instruments RigKontrol2 + * Native Instruments RigKontrol3 * Native Instruments Audio Kontrol 1 endmenu diff --git a/sound/usb/caiaq/caiaq-audio.c b/sound/usb/caiaq/caiaq-audio.c index 0414d766ba0..0666908a236 100644 --- a/sound/usb/caiaq/caiaq-audio.c +++ b/sound/usb/caiaq/caiaq-audio.c @@ -648,6 +648,7 @@ int __devinit snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev) dev->samplerates = dev->pcm_info.rates; switch (dev->chip.usb_id) { case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1): + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3): dev->samplerates |= SNDRV_PCM_RATE_88200; dev->samplerates |= SNDRV_PCM_RATE_192000; break; diff --git a/sound/usb/caiaq/caiaq-device.c b/sound/usb/caiaq/caiaq-device.c index 4709347326f..58af8142c57 100644 --- a/sound/usb/caiaq/caiaq-device.c +++ b/sound/usb/caiaq/caiaq-device.c @@ -41,9 +41,10 @@ #endif MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>"); -MODULE_DESCRIPTION("caiaq USB audio, version 1.1.0"); +MODULE_DESCRIPTION("caiaq USB audio, version 1.2.0"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2}," + "{Native Instruments, RigKontrol3}," "{Native Instruments, Kore Controller}," "{Native Instruments, Audio Kontrol 1}" "{Native Instruments, Audio 8 DJ}}"); @@ -85,6 +86,11 @@ static struct usb_device_id snd_usb_id_table[] = { { .match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = USB_VID_NATIVEINSTRUMENTS, + .idProduct = USB_PID_RIGKONTROL3 + }, + { + .match_flags = USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = USB_VID_NATIVEINSTRUMENTS, .idProduct = USB_PID_KORECONTROLLER }, { @@ -226,7 +232,7 @@ int snd_usb_caiaq_set_auto_msg (struct snd_usb_caiaqdev *dev, static void setup_card(struct snd_usb_caiaqdev *dev) { int ret; - char val[3]; + char val[4]; /* device-specific startup specials */ switch (dev->chip.usb_id) { @@ -237,6 +243,14 @@ static void setup_card(struct snd_usb_caiaqdev *dev) val[2] = 0x01; send_command(dev, EP1_CMD_WRITE_IO, val, 3); break; + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3): + /* RigKontrol2 - display two centered dashes ('--') */ + val[0] = 0x00; + val[1] = 0x40; + val[2] = 0x40; + val[3] = 0x00; + send_command(dev, EP1_CMD_WRITE_IO, val, 4); + break; case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1): /* Audio Kontrol 1 - make USB-LED stop blinking */ val[0] = 0x00; diff --git a/sound/usb/caiaq/caiaq-device.h b/sound/usb/caiaq/caiaq-device.h index 088d5ec241f..79bc5be2df7 100644 --- a/sound/usb/caiaq/caiaq-device.h +++ b/sound/usb/caiaq/caiaq-device.h @@ -6,6 +6,7 @@ #define USB_VID_NATIVEINSTRUMENTS 0x17cc #define USB_PID_RIGKONTROL2 0x1969 +#define USB_PID_RIGKONTROL3 0x1940 #define USB_PID_KORECONTROLLER 0x4711 #define USB_PID_AK1 0x0815 #define USB_PID_AUDIO8DJ 0x1978 diff --git a/sound/usb/caiaq/caiaq-input.c b/sound/usb/caiaq/caiaq-input.c index 3acd12db695..cd536ca20e5 100644 --- a/sound/usb/caiaq/caiaq-input.c +++ b/sound/usb/caiaq/caiaq-input.c @@ -34,6 +34,8 @@ static unsigned char keycode_ak1[] = { KEY_C, KEY_B, KEY_A }; static unsigned char keycode_rk2[] = { KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7 }; +static unsigned char keycode_rk3[] = { KEY_1, KEY_2, KEY_3, KEY_4, + KEY_5, KEY_6, KEY_7, KEY_5, KEY_6 }; #define DEG90 (range/2) #define DEG180 (range) @@ -107,7 +109,8 @@ static unsigned int decode_erp(unsigned char a, unsigned char b) static void snd_caiaq_input_read_analog(struct snd_usb_caiaqdev *dev, - const char *buf, unsigned int len) + const unsigned char *buf, + unsigned int len) { switch(dev->input_dev->id.product) { case USB_PID_RIGKONTROL2: @@ -116,6 +119,12 @@ static void snd_caiaq_input_read_analog(struct snd_usb_caiaqdev *dev, input_report_abs(dev->input_dev, ABS_Z, (buf[2] << 8) |buf[3]); input_sync(dev->input_dev); break; + case USB_PID_RIGKONTROL3: + input_report_abs(dev->input_dev, ABS_X, (buf[0] << 8) |buf[1]); + input_report_abs(dev->input_dev, ABS_Y, (buf[2] << 8) |buf[3]); + input_report_abs(dev->input_dev, ABS_Z, (buf[4] << 8) |buf[5]); + input_sync(dev->input_dev); + break; } } @@ -128,7 +137,7 @@ static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *dev, case USB_PID_AK1: i = decode_erp(buf[0], buf[1]); input_report_abs(dev->input_dev, ABS_X, i); - input_sync(dev->input_dev); + input_sync(dev->input_dev); break; } } @@ -191,8 +200,9 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev) switch (dev->chip.usb_id) { case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2): - input->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - input->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_Z); + input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + input->absbit[0] = BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) | + BIT_MASK(ABS_Z); input->keycode = keycode_rk2; input->keycodesize = sizeof(char); input->keycodemax = ARRAY_SIZE(keycode_rk2); @@ -204,9 +214,23 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev) input_set_abs_params(input, ABS_Z, 0, 4096, 0, 10); snd_usb_caiaq_set_auto_msg(dev, 1, 10, 0); break; - case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1): + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3): input->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - input->absbit[0] = BIT(ABS_X); + input->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_Z); + input->keycode = keycode_rk3; + input->keycodesize = sizeof(char); + input->keycodemax = ARRAY_SIZE(keycode_rk3); + for (i=0; i<ARRAY_SIZE(keycode_rk3); i++) + set_bit(keycode_rk3[i], input->keybit); + + input_set_abs_params(input, ABS_X, 0, 1024, 0, 10); + input_set_abs_params(input, ABS_Y, 0, 1024, 0, 10); + input_set_abs_params(input, ABS_Z, 0, 1024, 0, 10); + snd_usb_caiaq_set_auto_msg(dev, 1, 10, 0); + break; + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1): + input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + input->absbit[0] = BIT_MASK(ABS_X); input->keycode = keycode_ak1; input->keycodesize = sizeof(char); input->keycodemax = ARRAY_SIZE(keycode_ak1); @@ -238,7 +262,6 @@ void snd_usb_caiaq_input_free(struct snd_usb_caiaqdev *dev) return; input_unregister_device(dev->input_dev); - input_free_device(dev->input_dev); dev->input_dev = NULL; } diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 7bd5852fcc0..967b823eace 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -123,7 +123,6 @@ struct audioformat { unsigned int rate_min, rate_max; /* min/max rates */ unsigned int nr_rates; /* number of rate table entries */ unsigned int *rate_table; /* rate table */ - unsigned int needs_knot; /* any unusual rates? */ }; struct snd_usb_substream; @@ -1309,7 +1308,11 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) /* close the old interface */ if (subs->interface >= 0 && subs->interface != fmt->iface) { - usb_set_interface(subs->dev, subs->interface, 0); + if (usb_set_interface(subs->dev, subs->interface, 0) < 0) { + snd_printk(KERN_ERR "%d:%d:%d: return to setting 0 failed\n", + dev->devnum, fmt->iface, fmt->altsetting); + return -EIO; + } subs->interface = -1; subs->format = 0; } @@ -1761,7 +1764,7 @@ static int check_hw_params_convention(struct snd_usb_substream *subs) channels[f->format] |= (1 << f->channels); rates[f->format] |= f->rates; /* needs knot? */ - if (f->needs_knot) + if (f->rates & SNDRV_PCM_RATE_KNOT) goto __out; } /* check whether channels and rates match for all formats */ @@ -1817,7 +1820,7 @@ static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime, if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS) return 0; count += fp->nr_rates; - if (fp->needs_knot) + if (fp->rates & SNDRV_PCM_RATE_KNOT) needs_knot = 1; } if (!needs_knot) @@ -2453,7 +2456,7 @@ static int parse_audio_format_rates(struct snd_usb_audio *chip, struct audioform unsigned char *fmt, int offset) { int nr_rates = fmt[offset]; - int found; + if (fmt[0] < offset + 1 + 3 * (nr_rates ? nr_rates : 2)) { snd_printk(KERN_ERR "%d:%u:%d : invalid FORMAT_TYPE desc\n", chip->dev->devnum, fp->iface, fp->altsetting); @@ -2464,20 +2467,15 @@ static int parse_audio_format_rates(struct snd_usb_audio *chip, struct audioform /* * build the rate table and bitmap flags */ - int r, idx, c; + int r, idx; unsigned int nonzero_rates = 0; - /* this table corresponds to the SNDRV_PCM_RATE_XXX bit */ - static unsigned int conv_rates[] = { - 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, - 64000, 88200, 96000, 176400, 192000 - }; + fp->rate_table = kmalloc(sizeof(int) * nr_rates, GFP_KERNEL); if (fp->rate_table == NULL) { snd_printk(KERN_ERR "cannot malloc\n"); return -1; } - fp->needs_knot = 0; fp->nr_rates = nr_rates; fp->rate_min = fp->rate_max = combine_triple(&fmt[8]); for (r = 0, idx = offset + 1; r < nr_rates; r++, idx += 3) { @@ -2493,23 +2491,12 @@ static int parse_audio_format_rates(struct snd_usb_audio *chip, struct audioform fp->rate_min = rate; else if (rate > fp->rate_max) fp->rate_max = rate; - found = 0; - for (c = 0; c < (int)ARRAY_SIZE(conv_rates); c++) { - if (rate == conv_rates[c]) { - found = 1; - fp->rates |= (1 << c); - break; - } - } - if (!found) - fp->needs_knot = 1; + fp->rates |= snd_pcm_rate_to_rate_bit(rate); } if (!nonzero_rates) { hwc_debug("All rates were zero. Skipping format!\n"); return -1; } - if (fp->needs_knot) - fp->rates |= SNDRV_PCM_RATE_KNOT; } else { /* continuous rates */ fp->rates = SNDRV_PCM_RATE_CONTINUOUS; @@ -2857,6 +2844,10 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) /* skip non-supported classes */ continue; } + if (snd_usb_get_speed(dev) == USB_SPEED_LOW) { + snd_printk(KERN_ERR "low speed audio streaming not supported\n"); + continue; + } if (! parse_audio_endpoints(chip, j)) { usb_set_interface(dev, j, 0); /* reset the current interface */ usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1L); @@ -2876,7 +2867,7 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip, struct audioformat *fp; struct usb_host_interface *alts; int stream, err; - int *rate_table = NULL; + unsigned *rate_table = NULL; fp = kmemdup(quirk->data, sizeof(*fp), GFP_KERNEL); if (! fp) { @@ -3399,7 +3390,8 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, *rchip = NULL; - if (snd_usb_get_speed(dev) != USB_SPEED_FULL && + if (snd_usb_get_speed(dev) != USB_SPEED_LOW && + snd_usb_get_speed(dev) != USB_SPEED_FULL && snd_usb_get_speed(dev) != USB_SPEED_HIGH) { snd_printk(KERN_ERR "unknown device speed %d\n", snd_usb_get_speed(dev)); return -ENXIO; @@ -3473,7 +3465,9 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, usb_make_path(dev, card->longname + len, sizeof(card->longname) - len); strlcat(card->longname, - snd_usb_get_speed(dev) == USB_SPEED_FULL ? ", full speed" : ", high speed", + snd_usb_get_speed(dev) == USB_SPEED_LOW ? ", low speed" : + snd_usb_get_speed(dev) == USB_SPEED_FULL ? ", full speed" : + ", high speed", sizeof(card->longname)); snd_usb_audio_create_proc(chip); diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c index 99295f9b769..6330788c1c2 100644 --- a/sound/usb/usbmidi.c +++ b/sound/usb/usbmidi.c @@ -407,6 +407,20 @@ static void snd_usbmidi_maudio_broken_running_status_input( } /* + * CME protocol: like the standard protocol, but SysEx commands are sent as a + * single USB packet preceded by a 0x0F byte. + */ +static void snd_usbmidi_cme_input(struct snd_usb_midi_in_endpoint *ep, + uint8_t *buffer, int buffer_length) +{ + if (buffer_length < 2 || (buffer[0] & 0x0f) != 0x0f) + snd_usbmidi_standard_input(ep, buffer, buffer_length); + else + snd_usbmidi_input_data(ep, buffer[0] >> 4, + &buffer[1], buffer_length - 1); +} + +/* * Adds one USB MIDI packet to the output buffer. */ static void snd_usbmidi_output_standard_packet(struct urb* urb, uint8_t p0, @@ -572,6 +586,12 @@ static struct usb_protocol_ops snd_usbmidi_maudio_broken_running_status_ops = { .output_packet = snd_usbmidi_output_standard_packet, }; +static struct usb_protocol_ops snd_usbmidi_cme_ops = { + .input = snd_usbmidi_cme_input, + .output = snd_usbmidi_standard_output, + .output_packet = snd_usbmidi_output_standard_packet, +}; + /* * Novation USB MIDI protocol: number of data bytes is in the first byte * (when receiving) (+1!) or in the second byte (when sending); data begins @@ -963,8 +983,10 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi* umidi, snd_usbmidi_out_endpoint_delete(ep); return -ENOMEM; } - /* we never use interrupt output pipes */ - pipe = usb_sndbulkpipe(umidi->chip->dev, ep_info->out_ep); + if (ep_info->out_interval) + pipe = usb_sndintpipe(umidi->chip->dev, ep_info->out_ep); + else + pipe = usb_sndbulkpipe(umidi->chip->dev, ep_info->out_ep); if (umidi->chip->usb_id == USB_ID(0x0a92, 0x1020)) /* ESI M4U */ /* FIXME: we need more URBs to get reasonable bandwidth here: */ ep->max_transfer = 4; @@ -976,8 +998,14 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi* umidi, snd_usbmidi_out_endpoint_delete(ep); return -ENOMEM; } - usb_fill_bulk_urb(ep->urb, umidi->chip->dev, pipe, buffer, - ep->max_transfer, snd_usbmidi_out_urb_complete, ep); + if (ep_info->out_interval) + usb_fill_int_urb(ep->urb, umidi->chip->dev, pipe, buffer, + ep->max_transfer, snd_usbmidi_out_urb_complete, + ep, ep_info->out_interval); + else + usb_fill_bulk_urb(ep->urb, umidi->chip->dev, + pipe, buffer, ep->max_transfer, + snd_usbmidi_out_urb_complete, ep); ep->urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; spin_lock_init(&ep->buffer_lock); @@ -1323,6 +1351,13 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi, endpoints[epidx].out_ep = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) endpoints[epidx].out_interval = ep->bInterval; + else if (snd_usb_get_speed(umidi->chip->dev) == USB_SPEED_LOW) + /* + * Low speed bulk transfers don't exist, so + * force interrupt transfers for devices like + * ESI MIDI Mate that try to use them anyway. + */ + endpoints[epidx].out_interval = 1; endpoints[epidx].out_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1; snd_printdd(KERN_INFO "EP %02X: %d jack(s)\n", ep->bEndpointAddress, ms_ep->bNumEmbMIDIJack); @@ -1336,6 +1371,8 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi, endpoints[epidx].in_ep = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) endpoints[epidx].in_interval = ep->bInterval; + else if (snd_usb_get_speed(umidi->chip->dev) == USB_SPEED_LOW) + endpoints[epidx].in_interval = 1; endpoints[epidx].in_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1; snd_printdd(KERN_INFO "EP %02X: %d jack(s)\n", ep->bEndpointAddress, ms_ep->bNumEmbMIDIJack); @@ -1690,6 +1727,7 @@ int snd_usb_create_midi_interface(struct snd_usb_audio* chip, err = snd_usbmidi_detect_endpoints(umidi, &endpoints[0], 1); break; case QUIRK_MIDI_CME: + umidi->usb_protocol_ops = &snd_usbmidi_cme_ops; err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); break; default: diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index 325d4b6b54a..5e329690cfb 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -1483,7 +1483,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, unsi struct snd_kcontrol *kctl; char **namelist; - if (! num_ins || desc[0] < 6 + num_ins) { + if (! num_ins || desc[0] < 5 + num_ins) { snd_printk(KERN_ERR "invalid SELECTOR UNIT descriptor %d\n", unitid); return -EINVAL; } @@ -1888,14 +1888,7 @@ static int snd_usb_soundblaster_remote_init(struct usb_mixer_interface *mixer) return 0; } -static int snd_audigy2nx_led_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_audigy2nx_led_info snd_ctl_boolean_mono_info static int snd_audigy2nx_led_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h index 5a2f518c662..743568f8990 100644 --- a/sound/usb/usbquirks.h +++ b/sound/usb/usbquirks.h @@ -88,7 +88,19 @@ .bInterfaceClass = USB_CLASS_AUDIO, .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL }, - +/* E-Mu devices */ +{ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = 0x041e, + .idProduct = 0x3f02, + .bInterfaceClass = USB_CLASS_AUDIO, +}, +{ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = 0x041e, + .idProduct = 0x3f04, + .bInterfaceClass = USB_CLASS_AUDIO, +}, /* * Yamaha devices */ @@ -1254,7 +1266,28 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, /* TODO: add Edirol PC-80 support */ - /* TODO: add Edirol UA-1EX support */ +{ + USB_DEVICE(0x0582, 0x0096), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .vendor_name = "EDIROL", + .product_name = "UA-1EX", + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const struct snd_usb_audio_quirk[]) { + { + .ifnum = 0, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = -1 + } + } + } +}, { USB_DEVICE(0x0582, 0x009a), .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { @@ -1567,6 +1600,40 @@ YAMAHA_DEVICE(0x7010, "UB99"), } } }, +{ + USB_DEVICE(0x0763, 0x2019), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + /* .vendor_name = "M-Audio", */ + /* .product_name = "Ozone Academic", */ + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = & (const struct snd_usb_audio_quirk[]) { + { + .ifnum = 0, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 3, + .type = QUIRK_MIDI_MIDIMAN, + .data = & (const struct snd_usb_midi_endpoint_info) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + }, + { + .ifnum = -1 + } + } + } +}, /* Casio devices */ { @@ -1709,6 +1776,24 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, +/* Stanton/N2IT Final Scratch v1 device ('Scratchamp') */ +{ + USB_DEVICE(0x103d, 0x0100), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .vendor_name = "Stanton", + .product_name = "ScratchAmp", + .ifnum = QUIRK_NO_INTERFACE + } +}, +{ + USB_DEVICE(0x103d, 0x0101), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .vendor_name = "Stanton", + .product_name = "ScratchAmp", + .ifnum = QUIRK_NO_INTERFACE + } +}, + /* Novation EMS devices */ { USB_DEVICE_VENDOR_SPEC(0x1235, 0x0001), @@ -1738,6 +1823,17 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, +/* */ +{ + /* aka. Serato Scratch Live DJ Box */ + USB_DEVICE(0x13e5, 0x0001), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .vendor_name = "Rane", + .product_name = "SL-1", + .ifnum = QUIRK_NO_INTERFACE + } +}, + /* Miditech devices */ { USB_DEVICE(0x4752, 0x0011), |