diff options
Diffstat (limited to 'sound')
85 files changed, 2452 insertions, 3056 deletions
diff --git a/sound/Kconfig b/sound/Kconfig index 439e15c8faa3..b3e53e616ec9 100644 --- a/sound/Kconfig +++ b/sound/Kconfig @@ -58,7 +58,7 @@ config SOUND_OSS_CORE_PRECLAIM Please read Documentation/feature-removal-schedule.txt for details. - If unusre, say Y. + If unsure, say Y. source "sound/oss/dmasound/Kconfig" diff --git a/sound/arm/Makefile b/sound/arm/Makefile index 5a549ed6c8aa..8c0c851d4641 100644 --- a/sound/arm/Makefile +++ b/sound/arm/Makefile @@ -3,7 +3,7 @@ # obj-$(CONFIG_SND_ARMAACI) += snd-aaci.o -snd-aaci-objs := aaci.o devdma.o +snd-aaci-objs := aaci.o obj-$(CONFIG_SND_PXA2XX_PCM) += snd-pxa2xx-pcm.o snd-pxa2xx-pcm-objs := pxa2xx-pcm.o diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c index 1f0f8213e2d5..1497dce1b04a 100644 --- a/sound/arm/aaci.c +++ b/sound/arm/aaci.c @@ -18,10 +18,7 @@ #include <linux/interrupt.h> #include <linux/err.h> #include <linux/amba/bus.h> - -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/sizes.h> +#include <linux/io.h> #include <sound/core.h> #include <sound/initval.h> @@ -30,7 +27,6 @@ #include <sound/pcm_params.h> #include "aaci.h" -#include "devdma.h" #define DRIVER_NAME "aaci-pl041" @@ -492,7 +488,7 @@ static int aaci_pcm_hw_free(struct snd_pcm_substream *substream) /* * Clear out the DMA and any allocated buffers. */ - devdma_hw_free(NULL, substream); + snd_pcm_lib_free_pages(substream); return 0; } @@ -504,21 +500,19 @@ static int aaci_pcm_hw_params(struct snd_pcm_substream *substream, int err; aaci_pcm_hw_free(substream); + if (aacirun->pcm_open) { + snd_ac97_pcm_close(aacirun->pcm); + aacirun->pcm_open = 0; + } - err = devdma_hw_alloc(NULL, substream, - params_buffer_bytes(params)); + err = snd_pcm_lib_malloc_pages(substream, + params_buffer_bytes(params)); if (err < 0) goto out; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - err = snd_ac97_pcm_open(aacirun->pcm, params_rate(params), - params_channels(params), - aacirun->pcm->r[0].slots); - else - err = snd_ac97_pcm_open(aacirun->pcm, params_rate(params), - params_channels(params), - aacirun->pcm->r[1].slots); - + err = snd_ac97_pcm_open(aacirun->pcm, params_rate(params), + params_channels(params), + aacirun->pcm->r[0].slots); if (err) goto out; @@ -534,7 +528,7 @@ static int aaci_pcm_prepare(struct snd_pcm_substream *substream) struct aaci_runtime *aacirun = runtime->private_data; aacirun->start = (void *)runtime->dma_area; - aacirun->end = aacirun->start + runtime->dma_bytes; + aacirun->end = aacirun->start + snd_pcm_lib_buffer_bytes(substream); aacirun->ptr = aacirun->start; aacirun->period = aacirun->bytes = frames_to_bytes(runtime, runtime->period_size); @@ -551,11 +545,6 @@ static snd_pcm_uframes_t aaci_pcm_pointer(struct snd_pcm_substream *substream) return bytes_to_frames(runtime, bytes); } -static int aaci_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma) -{ - return devdma_mmap(NULL, substream, vma); -} - /* * Playback specific ALSA stuff @@ -722,7 +711,6 @@ static struct snd_pcm_ops aaci_playback_ops = { .prepare = aaci_pcm_prepare, .trigger = aaci_pcm_playback_trigger, .pointer = aaci_pcm_pointer, - .mmap = aaci_pcm_mmap, }; static int aaci_pcm_capture_hw_params(struct snd_pcm_substream *substream, @@ -850,7 +838,6 @@ static struct snd_pcm_ops aaci_capture_ops = { .prepare = aaci_pcm_capture_prepare, .trigger = aaci_pcm_capture_trigger, .pointer = aaci_pcm_pointer, - .mmap = aaci_pcm_mmap, }; /* @@ -1040,6 +1027,8 @@ static int __devinit aaci_init_pcm(struct aaci *aaci) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &aaci_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &aaci_capture_ops); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + NULL, 0, 64 * 104); } return ret; diff --git a/sound/arm/devdma.c b/sound/arm/devdma.c deleted file mode 100644 index 9d1e6665b546..000000000000 --- a/sound/arm/devdma.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - * linux/sound/arm/devdma.c - * - * Copyright (C) 2003-2004 Russell King, All rights reserved. - * - * 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. - * - * ARM DMA shim for ALSA. - */ -#include <linux/device.h> -#include <linux/dma-mapping.h> - -#include <sound/core.h> -#include <sound/pcm.h> - -#include "devdma.h" - -void devdma_hw_free(struct device *dev, struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_dma_buffer *buf = runtime->dma_buffer_p; - - if (runtime->dma_area == NULL) - return; - - if (buf != &substream->dma_buffer) { - dma_free_coherent(buf->dev.dev, buf->bytes, buf->area, buf->addr); - kfree(runtime->dma_buffer_p); - } - - snd_pcm_set_runtime_buffer(substream, NULL); -} - -int devdma_hw_alloc(struct device *dev, struct snd_pcm_substream *substream, size_t size) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_dma_buffer *buf = runtime->dma_buffer_p; - int ret = 0; - - if (buf) { - if (buf->bytes >= size) - goto out; - devdma_hw_free(dev, substream); - } - - if (substream->dma_buffer.area != NULL && substream->dma_buffer.bytes >= size) { - buf = &substream->dma_buffer; - } else { - buf = kmalloc(sizeof(struct snd_dma_buffer), GFP_KERNEL); - if (!buf) - goto nomem; - - buf->dev.type = SNDRV_DMA_TYPE_DEV; - buf->dev.dev = dev; - buf->area = dma_alloc_coherent(dev, size, &buf->addr, GFP_KERNEL); - buf->bytes = size; - buf->private_data = NULL; - - if (!buf->area) - goto free; - } - snd_pcm_set_runtime_buffer(substream, buf); - ret = 1; - out: - runtime->dma_bytes = size; - return ret; - - free: - kfree(buf); - nomem: - return -ENOMEM; -} - -int devdma_mmap(struct device *dev, struct snd_pcm_substream *substream, struct vm_area_struct *vma) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - return dma_mmap_coherent(dev, vma, runtime->dma_area, runtime->dma_addr, runtime->dma_bytes); -} diff --git a/sound/arm/devdma.h b/sound/arm/devdma.h deleted file mode 100644 index d025329c8a0f..000000000000 --- a/sound/arm/devdma.h +++ /dev/null @@ -1,3 +0,0 @@ -void devdma_hw_free(struct device *dev, struct snd_pcm_substream *substream); -int devdma_hw_alloc(struct device *dev, struct snd_pcm_substream *substream, size_t size); -int devdma_mmap(struct device *dev, struct snd_pcm_substream *substream, struct vm_area_struct *vma); diff --git a/sound/core/control.c b/sound/core/control.c index a8b7fabe645e..268ab7471224 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -75,7 +75,7 @@ static int snd_ctl_open(struct inode *inode, struct file *file) ctl->card = card; ctl->prefer_pcm_subdevice = -1; ctl->prefer_rawmidi_subdevice = -1; - ctl->pid = current->pid; + ctl->pid = get_pid(task_pid(current)); file->private_data = ctl; write_lock_irqsave(&card->ctl_files_rwlock, flags); list_add_tail(&ctl->list, &card->ctl_files); @@ -125,6 +125,7 @@ static int snd_ctl_release(struct inode *inode, struct file *file) control->vd[idx].owner = NULL; up_write(&card->controls_rwsem); snd_ctl_empty_read_queue(ctl); + put_pid(ctl->pid); kfree(ctl); module_put(card->module); snd_card_file_remove(card, file); @@ -672,7 +673,7 @@ static int snd_ctl_elem_info(struct snd_ctl_file *ctl, info->access |= SNDRV_CTL_ELEM_ACCESS_LOCK; if (vd->owner == ctl) info->access |= SNDRV_CTL_ELEM_ACCESS_OWNER; - info->owner = vd->owner_pid; + info->owner = pid_vnr(vd->owner->pid); } else { info->owner = -1; } @@ -827,7 +828,6 @@ static int snd_ctl_elem_lock(struct snd_ctl_file *file, result = -EBUSY; else { vd->owner = file; - vd->owner_pid = current->pid; result = 0; } } @@ -858,7 +858,6 @@ static int snd_ctl_elem_unlock(struct snd_ctl_file *file, result = -EPERM; else { vd->owner = NULL; - vd->owner_pid = 0; result = 0; } } @@ -1120,7 +1119,7 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file, goto __kctl_end; } if (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { - if (file && vd->owner != NULL && vd->owner != file) { + if (vd->owner != NULL && vd->owner != file) { err = -EPERM; goto __kctl_end; } diff --git a/sound/core/isadma.c b/sound/core/isadma.c index 79f0f16af339..950e19ba91fc 100644 --- a/sound/core/isadma.c +++ b/sound/core/isadma.c @@ -85,16 +85,24 @@ EXPORT_SYMBOL(snd_dma_disable); unsigned int snd_dma_pointer(unsigned long dma, unsigned int size) { unsigned long flags; - unsigned int result; + unsigned int result, result1; flags = claim_dma_lock(); clear_dma_ff(dma); if (!isa_dma_bridge_buggy) disable_dma(dma); result = get_dma_residue(dma); + /* + * HACK - read the counter again and choose higher value in order to + * avoid reading during counter lower byte roll over if the + * isa_dma_bridge_buggy is set. + */ + result1 = get_dma_residue(dma); if (!isa_dma_bridge_buggy) enable_dma(dma); release_dma_lock(flags); + if (unlikely(result < result1)) + result = result1; #ifdef CONFIG_SND_DEBUG if (result > size) snd_printk(KERN_ERR "pointer (0x%x) for DMA #%ld is greater than transfer size (0x%x)\n", result, dma, size); diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c index 772423889eb3..54e2eb56e4c2 100644 --- a/sound/core/oss/mixer_oss.c +++ b/sound/core/oss/mixer_oss.c @@ -1251,7 +1251,9 @@ static void snd_mixer_oss_build(struct snd_mixer_oss *mixer) { SOUND_MIXER_SYNTH, "FM", 0 }, /* fallback */ { SOUND_MIXER_SYNTH, "Music", 0 }, /* fallback */ { SOUND_MIXER_PCM, "PCM", 0 }, - { SOUND_MIXER_SPEAKER, "PC Speaker", 0 }, + { SOUND_MIXER_SPEAKER, "Beep", 0 }, + { SOUND_MIXER_SPEAKER, "PC Speaker", 0 }, /* fallback */ + { SOUND_MIXER_SPEAKER, "Speaker", 0 }, /* fallback */ { SOUND_MIXER_LINE, "Line", 0 }, { SOUND_MIXER_MIC, "Mic", 0 }, { SOUND_MIXER_CD, "CD", 0 }, diff --git a/sound/core/pcm.c b/sound/core/pcm.c index c69c60b2a48a..6884ae031f6f 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -435,6 +435,7 @@ static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry, return; } snd_iprintf(buffer, "state: %s\n", snd_pcm_state_name(status.state)); + snd_iprintf(buffer, "owner_pid : %d\n", pid_vnr(substream->pid)); snd_iprintf(buffer, "trigger_time: %ld.%09ld\n", status.trigger_tstamp.tv_sec, status.trigger_tstamp.tv_nsec); snd_iprintf(buffer, "tstamp : %ld.%09ld\n", @@ -809,7 +810,7 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, card = pcm->card; read_lock(&card->ctl_files_rwlock); list_for_each_entry(kctl, &card->ctl_files, list) { - if (kctl->pid == current->pid) { + if (kctl->pid == task_pid(current)) { prefer_subdevice = kctl->prefer_pcm_subdevice; if (prefer_subdevice != -1) break; @@ -900,6 +901,7 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, substream->private_data = pcm->private_data; substream->ref_count = 1; substream->f_flags = file->f_flags; + substream->pid = get_pid(task_pid(current)); pstr->substream_opened++; *rsubstream = substream; return 0; @@ -921,6 +923,8 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream) kfree(runtime->hw_constraints.rules); kfree(runtime); substream->runtime = NULL; + put_pid(substream->pid); + substream->pid = NULL; substream->pstr->substream_opened--; } diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index ab73edf2c89a..29ab46a12e11 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -26,6 +26,7 @@ #include <linux/time.h> #include <linux/pm_qos_params.h> #include <linux/uio.h> +#include <linux/dma-mapping.h> #include <sound/core.h> #include <sound/control.h> #include <sound/info.h> @@ -3061,6 +3062,27 @@ static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file } #endif /* coherent mmap */ +static inline struct page * +snd_pcm_default_page_ops(struct snd_pcm_substream *substream, unsigned long ofs) +{ + void *vaddr = substream->runtime->dma_area + ofs; +#if defined(CONFIG_MIPS) && defined(CONFIG_DMA_NONCOHERENT) + if (substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV) + return virt_to_page(CAC_ADDR(vaddr)); +#endif +#if defined(CONFIG_PPC32) && defined(CONFIG_NOT_COHERENT_CACHE) + if (substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV) { + dma_addr_t addr = substream->runtime->dma_addr + ofs; + addr -= get_dma_offset(substream->dma_buffer.dev.dev); + /* assume dma_handle set via pfn_to_phys() in + * mm/dma-noncoherent.c + */ + return pfn_to_page(addr >> PAGE_SHIFT); + } +#endif + return virt_to_page(vaddr); +} + /* * fault callback for mmapping a RAM page */ @@ -3071,7 +3093,6 @@ static int snd_pcm_mmap_data_fault(struct vm_area_struct *area, struct snd_pcm_runtime *runtime; unsigned long offset; struct page * page; - void *vaddr; size_t dma_bytes; if (substream == NULL) @@ -3081,36 +3102,53 @@ static int snd_pcm_mmap_data_fault(struct vm_area_struct *area, dma_bytes = PAGE_ALIGN(runtime->dma_bytes); if (offset > dma_bytes - PAGE_SIZE) return VM_FAULT_SIGBUS; - if (substream->ops->page) { + if (substream->ops->page) page = substream->ops->page(substream, offset); - if (!page) - return VM_FAULT_SIGBUS; - } else { - vaddr = runtime->dma_area + offset; - page = virt_to_page(vaddr); - } + else + page = snd_pcm_default_page_ops(substream, offset); + if (!page) + return VM_FAULT_SIGBUS; get_page(page); vmf->page = page; return 0; } -static const struct vm_operations_struct snd_pcm_vm_ops_data = -{ +static const struct vm_operations_struct snd_pcm_vm_ops_data = { + .open = snd_pcm_mmap_data_open, + .close = snd_pcm_mmap_data_close, +}; + +static const struct vm_operations_struct snd_pcm_vm_ops_data_fault = { .open = snd_pcm_mmap_data_open, .close = snd_pcm_mmap_data_close, .fault = snd_pcm_mmap_data_fault, }; +#ifndef ARCH_HAS_DMA_MMAP_COHERENT +/* This should be defined / handled globally! */ +#ifdef CONFIG_ARM +#define ARCH_HAS_DMA_MMAP_COHERENT +#endif +#endif + /* * mmap the DMA buffer on RAM */ static int snd_pcm_default_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *area) { - area->vm_ops = &snd_pcm_vm_ops_data; - area->vm_private_data = substream; area->vm_flags |= VM_RESERVED; - atomic_inc(&substream->mmap_count); +#ifdef ARCH_HAS_DMA_MMAP_COHERENT + if (!substream->ops->page && + substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV) + return dma_mmap_coherent(substream->dma_buffer.dev.dev, + area, + substream->runtime->dma_area, + substream->runtime->dma_addr, + area->vm_end - area->vm_start); +#endif /* ARCH_HAS_DMA_MMAP_COHERENT */ + /* mmap with fault handler */ + area->vm_ops = &snd_pcm_vm_ops_data_fault; return 0; } @@ -3118,12 +3156,6 @@ static int snd_pcm_default_mmap(struct snd_pcm_substream *substream, * mmap the DMA buffer on I/O memory area */ #if SNDRV_PCM_INFO_MMAP_IOMEM -static const struct vm_operations_struct snd_pcm_vm_ops_data_mmio = -{ - .open = snd_pcm_mmap_data_open, - .close = snd_pcm_mmap_data_close, -}; - int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, struct vm_area_struct *area) { @@ -3133,8 +3165,6 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, #ifdef pgprot_noncached area->vm_page_prot = pgprot_noncached(area->vm_page_prot); #endif - area->vm_ops = &snd_pcm_vm_ops_data_mmio; - area->vm_private_data = substream; area->vm_flags |= VM_IO; size = area->vm_end - area->vm_start; offset = area->vm_pgoff << PAGE_SHIFT; @@ -3142,7 +3172,6 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, (substream->runtime->dma_addr + offset) >> PAGE_SHIFT, size, area->vm_page_prot)) return -EAGAIN; - atomic_inc(&substream->mmap_count); return 0; } @@ -3159,6 +3188,7 @@ int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file, long size; unsigned long offset; size_t dma_bytes; + int err; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { if (!(area->vm_flags & (VM_WRITE|VM_READ))) @@ -3183,10 +3213,15 @@ int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file, if (offset > dma_bytes - size) return -EINVAL; + area->vm_ops = &snd_pcm_vm_ops_data; + area->vm_private_data = substream; if (substream->ops->mmap) - return substream->ops->mmap(substream, area); + err = substream->ops->mmap(substream, area); else - return snd_pcm_default_mmap(substream, area); + err = snd_pcm_default_mmap(substream, area); + if (!err) + atomic_inc(&substream->mmap_count); + return err; } EXPORT_SYMBOL(snd_pcm_mmap_data); diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index c0adc14c91f0..2f766123b158 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -242,13 +242,12 @@ static int assign_substream(struct snd_rawmidi *rmidi, int subdevice, return -ENXIO; if (subdevice >= 0 && subdevice >= s->substream_count) return -ENODEV; - if (s->substream_opened >= s->substream_count) - return -EAGAIN; list_for_each_entry(substream, &s->substreams, list) { if (substream->opened) { if (stream == SNDRV_RAWMIDI_STREAM_INPUT || - !(mode & SNDRV_RAWMIDI_LFLG_APPEND)) + !(mode & SNDRV_RAWMIDI_LFLG_APPEND) || + !substream->append) continue; } if (subdevice < 0 || subdevice == substream->number) { @@ -266,18 +265,23 @@ static int open_substream(struct snd_rawmidi *rmidi, { int err; - err = snd_rawmidi_runtime_create(substream); - if (err < 0) - return err; - err = substream->ops->open(substream); - if (err < 0) - return err; - substream->opened = 1; - if (substream->use_count++ == 0) + if (substream->use_count == 0) { + err = snd_rawmidi_runtime_create(substream); + if (err < 0) + return err; + err = substream->ops->open(substream); + if (err < 0) { + snd_rawmidi_runtime_free(substream); + return err; + } + substream->opened = 1; substream->active_sensing = 0; - if (mode & SNDRV_RAWMIDI_LFLG_APPEND) - substream->append = 1; - rmidi->streams[substream->stream].substream_opened++; + if (mode & SNDRV_RAWMIDI_LFLG_APPEND) + substream->append = 1; + substream->pid = get_pid(task_pid(current)); + rmidi->streams[substream->stream].substream_opened++; + } + substream->use_count++; return 0; } @@ -297,27 +301,27 @@ static int rawmidi_open_priv(struct snd_rawmidi *rmidi, int subdevice, int mode, SNDRV_RAWMIDI_STREAM_INPUT, mode, &sinput); if (err < 0) - goto __error; + return err; } if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) { err = assign_substream(rmidi, subdevice, SNDRV_RAWMIDI_STREAM_OUTPUT, mode, &soutput); if (err < 0) - goto __error; + return err; } if (sinput) { err = open_substream(rmidi, sinput, mode); if (err < 0) - goto __error; + return err; } if (soutput) { err = open_substream(rmidi, soutput, mode); if (err < 0) { if (sinput) close_substream(rmidi, sinput, 0); - goto __error; + return err; } } @@ -325,13 +329,6 @@ static int rawmidi_open_priv(struct snd_rawmidi *rmidi, int subdevice, int mode, rfile->input = sinput; rfile->output = soutput; return 0; - - __error: - if (sinput && sinput->runtime) - snd_rawmidi_runtime_free(sinput); - if (soutput && soutput->runtime) - snd_rawmidi_runtime_free(soutput); - return err; } /* called from sound/core/seq/seq_midi.c */ @@ -415,7 +412,7 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file) subdevice = -1; read_lock(&card->ctl_files_rwlock); list_for_each_entry(kctl, &card->ctl_files, list) { - if (kctl->pid == current->pid) { + if (kctl->pid == task_pid(current)) { subdevice = kctl->prefer_rawmidi_subdevice; if (subdevice != -1) break; @@ -468,7 +465,6 @@ static void close_substream(struct snd_rawmidi *rmidi, struct snd_rawmidi_substream *substream, int cleanup) { - rmidi->streams[substream->stream].substream_opened--; if (--substream->use_count) return; @@ -493,6 +489,9 @@ static void close_substream(struct snd_rawmidi *rmidi, snd_rawmidi_runtime_free(substream); substream->opened = 0; substream->append = 0; + put_pid(substream->pid); + substream->pid = NULL; + rmidi->streams[substream->stream].substream_opened--; } static void rawmidi_release_priv(struct snd_rawmidi_file *rfile) @@ -1340,6 +1339,9 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry, substream->number, (unsigned long) substream->bytes); if (substream->opened) { + snd_iprintf(buffer, + " Owner PID : %d\n", + pid_vnr(substream->pid)); runtime = substream->runtime; snd_iprintf(buffer, " Mode : %s\n" @@ -1361,6 +1363,9 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry, substream->number, (unsigned long) substream->bytes); if (substream->opened) { + snd_iprintf(buffer, + " Owner PID : %d\n", + pid_vnr(substream->pid)); runtime = substream->runtime; snd_iprintf(buffer, " Buffer size : %lu\n" diff --git a/sound/drivers/pcsp/pcsp.c b/sound/drivers/pcsp/pcsp.c index b60cef257b58..f165c77d6273 100644 --- a/sound/drivers/pcsp/pcsp.c +++ b/sound/drivers/pcsp/pcsp.c @@ -26,6 +26,7 @@ MODULE_ALIAS("platform:pcspkr"); static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */ static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */ static int enable = SNDRV_DEFAULT_ENABLE1; /* Enable this card */ +static int nopcm; /* Disable PCM capability of the driver */ module_param(index, int, 0444); MODULE_PARM_DESC(index, "Index value for pcsp soundcard."); @@ -33,6 +34,8 @@ module_param(id, charp, 0444); MODULE_PARM_DESC(id, "ID string for pcsp soundcard."); module_param(enable, bool, 0444); MODULE_PARM_DESC(enable, "Enable PC-Speaker sound."); +module_param(nopcm, bool, 0444); +MODULE_PARM_DESC(nopcm, "Disable PC-Speaker PCM sound. Only beeps remain."); struct snd_pcsp pcsp_chip; @@ -43,13 +46,16 @@ static int __devinit snd_pcsp_create(struct snd_card *card) int err; int div, min_div, order; - hrtimer_get_res(CLOCK_MONOTONIC, &tp); - if (tp.tv_sec || tp.tv_nsec > PCSP_MAX_PERIOD_NS) { - printk(KERN_ERR "PCSP: Timer resolution is not sufficient " - "(%linS)\n", tp.tv_nsec); - printk(KERN_ERR "PCSP: Make sure you have HPET and ACPI " - "enabled.\n"); - return -EIO; + if (!nopcm) { + hrtimer_get_res(CLOCK_MONOTONIC, &tp); + if (tp.tv_sec || tp.tv_nsec > PCSP_MAX_PERIOD_NS) { + printk(KERN_ERR "PCSP: Timer resolution is not sufficient " + "(%linS)\n", tp.tv_nsec); + printk(KERN_ERR "PCSP: Make sure you have HPET and ACPI " + "enabled.\n"); + printk(KERN_ERR "PCSP: Turned into nopcm mode.\n"); + nopcm = 1; + } } if (loops_per_jiffy >= PCSP_MIN_LPJ && tp.tv_nsec <= PCSP_MIN_PERIOD_NS) @@ -107,12 +113,14 @@ static int __devinit snd_card_pcsp_probe(int devnum, struct device *dev) snd_card_free(card); return err; } - err = snd_pcsp_new_pcm(&pcsp_chip); - if (err < 0) { - snd_card_free(card); - return err; + if (!nopcm) { + err = snd_pcsp_new_pcm(&pcsp_chip); + if (err < 0) { + snd_card_free(card); + return err; + } } - err = snd_pcsp_new_mixer(&pcsp_chip); + err = snd_pcsp_new_mixer(&pcsp_chip, nopcm); if (err < 0) { snd_card_free(card); return err; diff --git a/sound/drivers/pcsp/pcsp.h b/sound/drivers/pcsp/pcsp.h index 174dd2ff0f22..1e123077923d 100644 --- a/sound/drivers/pcsp/pcsp.h +++ b/sound/drivers/pcsp/pcsp.h @@ -83,6 +83,6 @@ extern enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle); extern void pcsp_sync_stop(struct snd_pcsp *chip); extern int snd_pcsp_new_pcm(struct snd_pcsp *chip); -extern int snd_pcsp_new_mixer(struct snd_pcsp *chip); +extern int snd_pcsp_new_mixer(struct snd_pcsp *chip, int nopcm); #endif diff --git a/sound/drivers/pcsp/pcsp_mixer.c b/sound/drivers/pcsp/pcsp_mixer.c index 903bc846763f..6f633f4f3b96 100644 --- a/sound/drivers/pcsp/pcsp_mixer.c +++ b/sound/drivers/pcsp/pcsp_mixer.c @@ -119,24 +119,43 @@ static int pcsp_pcspkr_put(struct snd_kcontrol *kcontrol, .put = pcsp_##ctl_type##_put, \ } -static struct snd_kcontrol_new __devinitdata snd_pcsp_controls[] = { +static struct snd_kcontrol_new __devinitdata snd_pcsp_controls_pcm[] = { PCSP_MIXER_CONTROL(enable, "Master Playback Switch"), PCSP_MIXER_CONTROL(treble, "BaseFRQ Playback Volume"), - PCSP_MIXER_CONTROL(pcspkr, "PC Speaker Playback Switch"), }; -int __devinit snd_pcsp_new_mixer(struct snd_pcsp *chip) +static struct snd_kcontrol_new __devinitdata snd_pcsp_controls_spkr[] = { + PCSP_MIXER_CONTROL(pcspkr, "Beep Playback Switch"), +}; + +static int __devinit snd_pcsp_ctls_add(struct snd_pcsp *chip, + struct snd_kcontrol_new *ctls, int num) { - struct snd_card *card = chip->card; int i, err; + struct snd_card *card = chip->card; + for (i = 0; i < num; i++) { + err = snd_ctl_add(card, snd_ctl_new1(ctls + i, chip)); + if (err < 0) + return err; + } + return 0; +} + +int __devinit snd_pcsp_new_mixer(struct snd_pcsp *chip, int nopcm) +{ + int err; + struct snd_card *card = chip->card; - for (i = 0; i < ARRAY_SIZE(snd_pcsp_controls); i++) { - err = snd_ctl_add(card, - snd_ctl_new1(snd_pcsp_controls + i, - chip)); + if (!nopcm) { + err = snd_pcsp_ctls_add(chip, snd_pcsp_controls_pcm, + ARRAY_SIZE(snd_pcsp_controls_pcm)); if (err < 0) return err; } + err = snd_pcsp_ctls_add(chip, snd_pcsp_controls_spkr, + ARRAY_SIZE(snd_pcsp_controls_spkr)); + if (err < 0) + return err; strcpy(card->mixername, "PC-Speaker"); diff --git a/sound/i2c/cs8427.c b/sound/i2c/cs8427.c index 020a5d512472..04ae8704cdcd 100644 --- a/sound/i2c/cs8427.c +++ b/sound/i2c/cs8427.c @@ -23,6 +23,7 @@ #include <linux/slab.h> #include <linux/delay.h> #include <linux/init.h> +#include <linux/bitrev.h> #include <asm/unaligned.h> #include <sound/core.h> #include <sound/control.h> @@ -55,18 +56,6 @@ struct cs8427 { struct cs8427_stream capture; }; -static unsigned char swapbits(unsigned char val) -{ - int bit; - unsigned char res = 0; - for (bit = 0; bit < 8; bit++) { - res <<= 1; - res |= val & 1; - val >>= 1; - } - return res; -} - int snd_cs8427_reg_write(struct snd_i2c_device *device, unsigned char reg, unsigned char val) { @@ -149,7 +138,7 @@ static int snd_cs8427_send_corudata(struct snd_i2c_device *device, } data[0] = CS8427_REG_AUTOINC | CS8427_REG_CORU_DATABUF; for (idx = 0; idx < count; idx++) - data[idx + 1] = swapbits(ndata[idx]); + data[idx + 1] = bitrev8(ndata[idx]); if (snd_i2c_sendbytes(device, data, count + 1) != count + 1) return -EIO; return 1; diff --git a/sound/i2c/other/tea575x-tuner.c b/sound/i2c/other/tea575x-tuner.c index d31c373e076d..c4c6ef73f9bf 100644 --- a/sound/i2c/other/tea575x-tuner.c +++ b/sound/i2c/other/tea575x-tuner.c @@ -225,7 +225,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv, case V4L2_CID_AUDIO_MUTE: if (tea->ops->mute) { tea->ops->mute(tea, ctrl->value); - tea->mute = 1; + tea->mute = ctrl->value; return 0; } } diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig index 51a7e3777e17..02fe81ca88fd 100644 --- a/sound/isa/Kconfig +++ b/sound/isa/Kconfig @@ -372,15 +372,21 @@ config SND_SGALAXY config SND_SSCAPE tristate "Ensoniq SoundScape driver" - select SND_HWDEP select SND_MPU401_UART select SND_WSS_LIB + select FW_LOADER help Say Y here to include support for Ensoniq SoundScape - soundcards. + and Ensoniq OEM soundcards. The PCM audio is supported on SoundScape Classic, Elite, PnP - and VIVO cards. The MIDI support is very experimental. + and VIVO cards. The supported OEM cards are SPEA Media FX and + Reveal SC-600. + The MIDI support is very experimental and requires binary + firmware files called "scope.cod" and "sndscape.co?" where the + ? is digit 0, 1, 2, 3 or 4. The firmware files can be found + in DOS or Windows driver packages. One has to put the firmware + files into the /lib/firmware directory. To compile this driver as a module, choose M here: the module will be called snd-sscape. diff --git a/sound/isa/cmi8330.c b/sound/isa/cmi8330.c index 02f79d252718..8246aae32ab4 100644 --- a/sound/isa/cmi8330.c +++ b/sound/isa/cmi8330.c @@ -237,7 +237,7 @@ WSS_DOUBLE("Wavetable Capture Volume", 0, CMI8330_WAVGAIN, CMI8330_WAVGAIN, 4, 0, 15, 0), WSS_SINGLE("3D Control - Switch", 0, CMI8330_RMUX3D, 5, 1, 1), -WSS_SINGLE("PC Speaker Playback Volume", 0, +WSS_SINGLE("Beep Playback Volume", 0, CMI8330_OUTPUTVOL, 3, 3, 0), WSS_DOUBLE("FM Playback Switch", 0, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1), @@ -262,7 +262,7 @@ SB_DOUBLE("SB Line Playback Switch", SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, SB_DOUBLE("SB Line Playback Volume", SB_DSP4_LINE_DEV, (SB_DSP4_LINE_DEV + 1), 3, 3, 31), SB_SINGLE("SB Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1), SB_SINGLE("SB Mic Playback Volume", SB_DSP4_MIC_DEV, 3, 31), -SB_SINGLE("SB PC Speaker Volume", SB_DSP4_SPEAKER_DEV, 6, 3), +SB_SINGLE("SB Beep Volume", SB_DSP4_SPEAKER_DEV, 6, 3), SB_DOUBLE("SB Capture Volume", SB_DSP4_IGAIN_DEV, (SB_DSP4_IGAIN_DEV + 1), 6, 6, 3), SB_DOUBLE("SB Playback Volume", SB_DSP4_OGAIN_DEV, (SB_DSP4_OGAIN_DEV + 1), 6, 6, 3), SB_SINGLE("SB Mic Auto Gain", SB_DSP4_MIC_AGC, 0, 1), diff --git a/sound/isa/cs423x/cs4236.c b/sound/isa/cs423x/cs4236.c index a076a6ce8071..93fa6720d197 100644 --- a/sound/isa/cs423x/cs4236.c +++ b/sound/isa/cs423x/cs4236.c @@ -394,21 +394,15 @@ static int __devinit snd_cs423x_probe(struct snd_card *card, int dev) return -EBUSY; } - err = snd_wss_create(card, port[dev], cport[dev], + err = snd_cs4236_create(card, port[dev], cport[dev], irq[dev], dma1[dev], dma2[dev], WSS_HW_DETECT3, 0, &chip); if (err < 0) return err; + + acard->chip = chip; if (chip->hardware & WSS_HW_CS4236B_MASK) { - snd_wss_free(chip); - err = snd_cs4236_create(card, - port[dev], cport[dev], - irq[dev], dma1[dev], dma2[dev], - WSS_HW_DETECT, 0, &chip); - if (err < 0) - return err; - acard->chip = chip; err = snd_cs4236_pcm(chip, 0, &pcm); if (err < 0) @@ -418,7 +412,6 @@ static int __devinit snd_cs423x_probe(struct snd_card *card, int dev) if (err < 0) return err; } else { - acard->chip = chip; err = snd_wss_pcm(chip, 0, &pcm); if (err < 0) return err; diff --git a/sound/isa/cs423x/cs4236_lib.c b/sound/isa/cs423x/cs4236_lib.c index 38835f31298b..c5adca300632 100644 --- a/sound/isa/cs423x/cs4236_lib.c +++ b/sound/isa/cs423x/cs4236_lib.c @@ -87,6 +87,8 @@ #include <sound/core.h> #include <sound/wss.h> #include <sound/asoundef.h> +#include <sound/initval.h> +#include <sound/tlv.h> /* * @@ -264,7 +266,10 @@ static void snd_cs4236_resume(struct snd_wss *chip) } #endif /* CONFIG_PM */ - +/* + * This function does no fail if the chip is not CS4236B or compatible. + * It just an equivalent to the snd_wss_create() then. + */ int snd_cs4236_create(struct snd_card *card, unsigned long port, unsigned long cport, @@ -281,21 +286,17 @@ int snd_cs4236_create(struct snd_card *card, *rchip = NULL; if (hardware == WSS_HW_DETECT) hardware = WSS_HW_DETECT3; - if (cport < 0x100) { - snd_printk(KERN_ERR "please, specify control port " - "for CS4236+ chips\n"); - return -ENODEV; - } + err = snd_wss_create(card, port, cport, irq, dma1, dma2, hardware, hwshare, &chip); if (err < 0) return err; - if (!(chip->hardware & WSS_HW_CS4236B_MASK)) { - snd_printk(KERN_ERR "CS4236+: MODE3 and extended registers " - "not available, hardware=0x%x\n", chip->hardware); - snd_device_free(card, chip); - return -ENODEV; + if ((chip->hardware & WSS_HW_CS4236B_MASK) == 0) { + snd_printd("chip is not CS4236+, hardware=0x%x\n", + chip->hardware); + *rchip = chip; + return 0; } #if 0 { @@ -308,9 +309,16 @@ int snd_cs4236_create(struct snd_card *card, idx, snd_cs4236_ctrl_in(chip, idx)); } #endif + if (cport < 0x100 || cport == SNDRV_AUTO_PORT) { + snd_printk(KERN_ERR "please, specify control port " + "for CS4236+ chips\n"); + snd_device_free(card, chip); + return -ENODEV; + } ver1 = snd_cs4236_ctrl_in(chip, 1); ver2 = snd_cs4236_ext_in(chip, CS4236_VERSION); - snd_printdd("CS4236: [0x%lx] C1 (version) = 0x%x, ext = 0x%x\n", cport, ver1, ver2); + snd_printdd("CS4236: [0x%lx] C1 (version) = 0x%x, ext = 0x%x\n", + cport, ver1, ver2); if (ver1 != ver2) { snd_printk(KERN_ERR "CS4236+ chip detected, but " "control port 0x%lx is not valid\n", cport); @@ -321,13 +329,17 @@ int snd_cs4236_create(struct snd_card *card, snd_cs4236_ctrl_out(chip, 2, 0xff); snd_cs4236_ctrl_out(chip, 3, 0x00); snd_cs4236_ctrl_out(chip, 4, 0x80); - snd_cs4236_ctrl_out(chip, 5, ((IEC958_AES1_CON_PCM_CODER & 3) << 6) | IEC958_AES0_CON_EMPHASIS_NONE); + reg = ((IEC958_AES1_CON_PCM_CODER & 3) << 6) | + IEC958_AES0_CON_EMPHASIS_NONE; + snd_cs4236_ctrl_out(chip, 5, reg); snd_cs4236_ctrl_out(chip, 6, IEC958_AES1_CON_PCM_CODER >> 2); snd_cs4236_ctrl_out(chip, 7, 0x00); - /* 0x8c for C8 is valid for Turtle Beach Malibu - the IEC-958 output */ - /* is working with this setup, other hardware should have */ - /* different signal paths and this value should be selectable */ - /* in the future */ + /* + * 0x8c for C8 is valid for Turtle Beach Malibu - the IEC-958 + * output is working with this setup, other hardware should + * have different signal paths and this value should be + * selectable in the future + */ snd_cs4236_ctrl_out(chip, 8, 0x8c); chip->rate_constraint = snd_cs4236_xrate; chip->set_playback_format = snd_cs4236_playback_format; @@ -339,9 +351,10 @@ int snd_cs4236_create(struct snd_card *card, /* initialize extended registers */ for (reg = 0; reg < sizeof(snd_cs4236_ext_map); reg++) - snd_cs4236_ext_out(chip, CS4236_I23VAL(reg), snd_cs4236_ext_map[reg]); + snd_cs4236_ext_out(chip, CS4236_I23VAL(reg), + snd_cs4236_ext_map[reg]); - /* initialize compatible but more featured registers */ + /* initialize compatible but more featured registers */ snd_wss_out(chip, CS4231_LEFT_INPUT, 0x40); snd_wss_out(chip, CS4231_RIGHT_INPUT, 0x40); snd_wss_out(chip, CS4231_AUX1_LEFT_INPUT, 0xff); @@ -387,6 +400,14 @@ int snd_cs4236_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm) .get = snd_cs4236_get_single, .put = snd_cs4236_put_single, \ .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) } +#define CS4236_SINGLE_TLV(xname, xindex, reg, shift, mask, invert, xtlv) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ + .info = snd_cs4236_info_single, \ + .get = snd_cs4236_get_single, .put = snd_cs4236_put_single, \ + .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24), \ + .tlv = { .p = (xtlv) } } + static int snd_cs4236_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { int mask = (kcontrol->private_value >> 16) & 0xff; @@ -490,6 +511,16 @@ static int snd_cs4236_put_singlec(struct snd_kcontrol *kcontrol, struct snd_ctl_ .get = snd_cs4236_get_double, .put = snd_cs4236_put_double, \ .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) } +#define CS4236_DOUBLE_TLV(xname, xindex, left_reg, right_reg, shift_left, \ + shift_right, mask, invert, xtlv) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ + .info = snd_cs4236_info_double, \ + .get = snd_cs4236_get_double, .put = snd_cs4236_put_double, \ + .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | \ + (shift_right << 19) | (mask << 24) | (invert << 22), \ + .tlv = { .p = (xtlv) } } + static int snd_cs4236_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { int mask = (kcontrol->private_value >> 24) & 0xff; @@ -560,12 +591,23 @@ static int snd_cs4236_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e return change; } -#define CS4236_DOUBLE1(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \ +#define CS4236_DOUBLE1(xname, xindex, left_reg, right_reg, shift_left, \ + shift_right, mask, invert) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ .info = snd_cs4236_info_double, \ .get = snd_cs4236_get_double1, .put = snd_cs4236_put_double1, \ .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) } +#define CS4236_DOUBLE1_TLV(xname, xindex, left_reg, right_reg, shift_left, \ + shift_right, mask, invert, xtlv) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ + .info = snd_cs4236_info_double, \ + .get = snd_cs4236_get_double1, .put = snd_cs4236_put_double1, \ + .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | \ + (shift_right << 19) | (mask << 24) | (invert << 22), \ + .tlv = { .p = (xtlv) } } + static int snd_cs4236_get_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_wss *chip = snd_kcontrol_chip(kcontrol); @@ -619,16 +661,18 @@ static int snd_cs4236_put_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_ return change; } -#define CS4236_MASTER_DIGITAL(xname, xindex) \ +#define CS4236_MASTER_DIGITAL(xname, xindex, xtlv) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ .info = snd_cs4236_info_double, \ .get = snd_cs4236_get_master_digital, .put = snd_cs4236_put_master_digital, \ - .private_value = 71 << 24 } + .private_value = 71 << 24, \ + .tlv = { .p = (xtlv) } } static inline int snd_cs4236_mixer_master_digital_invert_volume(int vol) { return (vol < 64) ? 63 - vol : 64 + (71 - vol); -} +} static int snd_cs4236_get_master_digital(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -661,11 +705,13 @@ static int snd_cs4236_put_master_digital(struct snd_kcontrol *kcontrol, struct s return change; } -#define CS4235_OUTPUT_ACCU(xname, xindex) \ +#define CS4235_OUTPUT_ACCU(xname, xindex, xtlv) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ .info = snd_cs4236_info_double, \ .get = snd_cs4235_get_output_accu, .put = snd_cs4235_put_output_accu, \ - .private_value = 3 << 24 } + .private_value = 3 << 24, \ + .tlv = { .p = (xtlv) } } static inline int snd_cs4235_mixer_output_accu_get_volume(int vol) { @@ -720,41 +766,56 @@ static int snd_cs4235_put_output_accu(struct snd_kcontrol *kcontrol, struct snd_ return change; } +static const DECLARE_TLV_DB_SCALE(db_scale_7bit, -9450, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_6bit_12db_max, -8250, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_5bit_22db_max, -2400, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_2bit, -1800, 600, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0); + static struct snd_kcontrol_new snd_cs4236_controls[] = { CS4236_DOUBLE("Master Digital Playback Switch", 0, CS4236_LEFT_MASTER, CS4236_RIGHT_MASTER, 7, 7, 1, 1), CS4236_DOUBLE("Master Digital Capture Switch", 0, CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1), -CS4236_MASTER_DIGITAL("Master Digital Volume", 0), +CS4236_MASTER_DIGITAL("Master Digital Volume", 0, db_scale_7bit), -CS4236_DOUBLE("Capture Boost Volume", 0, - CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1), +CS4236_DOUBLE_TLV("Capture Boost Volume", 0, + CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1, + db_scale_2bit), WSS_DOUBLE("PCM Playback Switch", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1), -WSS_DOUBLE("PCM Playback Volume", 0, - CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1), +WSS_DOUBLE_TLV("PCM Playback Volume", 0, + CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1, + db_scale_6bit), CS4236_DOUBLE("DSP Playback Switch", 0, CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 7, 7, 1, 1), -CS4236_DOUBLE("DSP Playback Volume", 0, - CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 0, 0, 63, 1), +CS4236_DOUBLE_TLV("DSP Playback Volume", 0, + CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 0, 0, 63, 1, + db_scale_6bit), CS4236_DOUBLE("FM Playback Switch", 0, CS4236_LEFT_FM, CS4236_RIGHT_FM, 7, 7, 1, 1), -CS4236_DOUBLE("FM Playback Volume", 0, - CS4236_LEFT_FM, CS4236_RIGHT_FM, 0, 0, 63, 1), +CS4236_DOUBLE_TLV("FM Playback Volume", 0, + CS4236_LEFT_FM, CS4236_RIGHT_FM, 0, 0, 63, 1, + db_scale_6bit), CS4236_DOUBLE("Wavetable Playback Switch", 0, CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 7, 7, 1, 1), -CS4236_DOUBLE("Wavetable Playback Volume", 0, - CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 0, 0, 63, 1), +CS4236_DOUBLE_TLV("Wavetable Playback Volume", 0, + CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 0, 0, 63, 1, + db_scale_6bit_12db_max), WSS_DOUBLE("Synth Playback Switch", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1), -WSS_DOUBLE("Synth Volume", 0, - CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1), +WSS_DOUBLE_TLV("Synth Volume", 0, + CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1, + db_scale_5bit_12db_max), WSS_DOUBLE("Synth Capture Switch", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 6, 6, 1, 1), WSS_DOUBLE("Synth Capture Bypass", 0, @@ -764,14 +825,16 @@ CS4236_DOUBLE("Mic Playback Switch", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 6, 6, 1, 1), CS4236_DOUBLE("Mic Capture Switch", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 7, 7, 1, 1), -CS4236_DOUBLE("Mic Volume", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 0, 0, 31, 1), -CS4236_DOUBLE("Mic Playback Boost", 0, +CS4236_DOUBLE_TLV("Mic Volume", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, + 0, 0, 31, 1, db_scale_5bit_22db_max), +CS4236_DOUBLE("Mic Playback Boost (+20dB)", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 5, 5, 1, 0), WSS_DOUBLE("Line Playback Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1), -WSS_DOUBLE("Line Volume", 0, - CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1), +WSS_DOUBLE_TLV("Line Volume", 0, + CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1, + db_scale_5bit_12db_max), WSS_DOUBLE("Line Capture Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 6, 6, 1, 1), WSS_DOUBLE("Line Capture Bypass", 0, @@ -779,57 +842,63 @@ WSS_DOUBLE("Line Capture Bypass", 0, WSS_DOUBLE("CD Playback Switch", 0, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1), -WSS_DOUBLE("CD Volume", 0, - CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1), +WSS_DOUBLE_TLV("CD Volume", 0, + CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1, + db_scale_5bit_12db_max), WSS_DOUBLE("CD Capture Switch", 0, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 6, 6, 1, 1), CS4236_DOUBLE1("Mono Output Playback Switch", 0, CS4231_MONO_CTRL, CS4236_RIGHT_MIX_CTRL, 6, 7, 1, 1), -CS4236_DOUBLE1("Mono Playback Switch", 0, +CS4236_DOUBLE1("Beep Playback Switch", 0, CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, 7, 1, 1), -WSS_SINGLE("Mono Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1), -WSS_SINGLE("Mono Playback Bypass", 0, CS4231_MONO_CTRL, 5, 1, 0), +WSS_SINGLE_TLV("Beep Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1, + db_scale_4bit), +WSS_SINGLE("Beep Bypass Playback Switch", 0, CS4231_MONO_CTRL, 5, 1, 0), -WSS_DOUBLE("Capture Volume", 0, - CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0), +WSS_DOUBLE_TLV("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, + 0, 0, 15, 0, db_scale_rec_gain), WSS_DOUBLE("Analog Loopback Capture Switch", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 7, 7, 1, 0), -WSS_SINGLE("Digital Loopback Playback Switch", 0, CS4231_LOOPBACK, 0, 1, 0), -CS4236_DOUBLE1("Digital Loopback Playback Volume", 0, - CS4231_LOOPBACK, CS4236_RIGHT_LOOPBACK, 2, 0, 63, 1) +WSS_SINGLE("Loopback Digital Playback Switch", 0, CS4231_LOOPBACK, 0, 1, 0), +CS4236_DOUBLE1_TLV("Loopback Digital Playback Volume", 0, + CS4231_LOOPBACK, CS4236_RIGHT_LOOPBACK, 2, 0, 63, 1, + db_scale_6bit), }; +static const DECLARE_TLV_DB_SCALE(db_scale_5bit_6db_max, -5600, 200, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_2bit_16db_max, -2400, 800, 0); + static struct snd_kcontrol_new snd_cs4235_controls[] = { -WSS_DOUBLE("Master Switch", 0, +WSS_DOUBLE("Master Playback Switch", 0, CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 7, 7, 1, 1), -WSS_DOUBLE("Master Volume", 0, - CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 0, 0, 31, 1), - -CS4235_OUTPUT_ACCU("Playback Volume", 0), +WSS_DOUBLE_TLV("Master Playback Volume", 0, + CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 0, 0, 31, 1, + db_scale_5bit_6db_max), -CS4236_DOUBLE("Master Digital Playback Switch", 0, - CS4236_LEFT_MASTER, CS4236_RIGHT_MASTER, 7, 7, 1, 1), -CS4236_DOUBLE("Master Digital Capture Switch", 0, - CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1), -CS4236_MASTER_DIGITAL("Master Digital Volume", 0), +CS4235_OUTPUT_ACCU("Playback Volume", 0, db_scale_2bit_16db_max), -WSS_DOUBLE("Master Digital Playback Switch", 1, +WSS_DOUBLE("Synth Playback Switch", 1, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1), -WSS_DOUBLE("Master Digital Capture Switch", 1, +WSS_DOUBLE("Synth Capture Switch", 1, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 6, 6, 1, 1), -WSS_DOUBLE("Master Digital Volume", 1, - CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1), +WSS_DOUBLE_TLV("Synth Volume", 1, + CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1, + db_scale_5bit_12db_max), -CS4236_DOUBLE("Capture Volume", 0, - CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1), +CS4236_DOUBLE_TLV("Capture Volume", 0, + CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1, + db_scale_2bit), -WSS_DOUBLE("PCM Switch", 0, +WSS_DOUBLE("PCM Playback Switch", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1), -WSS_DOUBLE("PCM Volume", 0, - CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1), +WSS_DOUBLE("PCM Capture Switch", 0, + CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1), +WSS_DOUBLE_TLV("PCM Volume", 0, + CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1, + db_scale_6bit), CS4236_DOUBLE("DSP Switch", 0, CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 7, 7, 1, 1), @@ -842,29 +911,29 @@ CS4236_DOUBLE("Mic Capture Switch", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 7, 7, 1, 1), CS4236_DOUBLE("Mic Playback Switch", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 6, 6, 1, 1), -CS4236_SINGLE("Mic Volume", 0, CS4236_LEFT_MIC, 0, 31, 1), -CS4236_SINGLE("Mic Playback Boost", 0, CS4236_LEFT_MIC, 5, 1, 0), +CS4236_SINGLE_TLV("Mic Volume", 0, CS4236_LEFT_MIC, 0, 31, 1, + db_scale_5bit_22db_max), +CS4236_SINGLE("Mic Boost (+20dB)", 0, CS4236_LEFT_MIC, 5, 1, 0), -WSS_DOUBLE("Aux Playback Switch", 0, +WSS_DOUBLE("Line Playback Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1), -WSS_DOUBLE("Aux Capture Switch", 0, +WSS_DOUBLE("Line Capture Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 6, 6, 1, 1), -WSS_DOUBLE("Aux Volume", 0, - CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1), +WSS_DOUBLE_TLV("Line Volume", 0, + CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1, + db_scale_5bit_12db_max), -WSS_DOUBLE("Aux Playback Switch", 1, +WSS_DOUBLE("CD Playback Switch", 1, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1), -WSS_DOUBLE("Aux Capture Switch", 1, +WSS_DOUBLE("CD Capture Switch", 1, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 6, 6, 1, 1), -WSS_DOUBLE("Aux Volume", 1, - CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1), - -CS4236_DOUBLE1("Master Mono Switch", 0, - CS4231_MONO_CTRL, CS4236_RIGHT_MIX_CTRL, 6, 7, 1, 1), +WSS_DOUBLE_TLV("CD Volume", 1, + CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1, + db_scale_5bit_12db_max), -CS4236_DOUBLE1("Mono Switch", 0, +CS4236_DOUBLE1("Beep Playback Switch", 0, CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, 7, 1, 1), -WSS_SINGLE("Mono Volume", 0, CS4231_MONO_CTRL, 0, 15, 1), +WSS_SINGLE("Beep Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1), WSS_DOUBLE("Analog Loopback Switch", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 7, 7, 1, 0), diff --git a/sound/isa/es1688/es1688_lib.c b/sound/isa/es1688/es1688_lib.c index 4c6e14f87f2d..c76bb00c9d15 100644 --- a/sound/isa/es1688/es1688_lib.c +++ b/sound/isa/es1688/es1688_lib.c @@ -982,7 +982,7 @@ ES1688_DOUBLE("CD Playback Volume", 0, ES1688_CD_DEV, ES1688_CD_DEV, 4, 0, 15, 0 ES1688_DOUBLE("FM Playback Volume", 0, ES1688_FM_DEV, ES1688_FM_DEV, 4, 0, 15, 0), ES1688_DOUBLE("Mic Playback Volume", 0, ES1688_MIC_DEV, ES1688_MIC_DEV, 4, 0, 15, 0), ES1688_DOUBLE("Aux Playback Volume", 0, ES1688_AUX_DEV, ES1688_AUX_DEV, 4, 0, 15, 0), -ES1688_SINGLE("PC Speaker Playback Volume", 0, ES1688_SPEAKER_DEV, 0, 7, 0), +ES1688_SINGLE("Beep Playback Volume", 0, ES1688_SPEAKER_DEV, 0, 7, 0), ES1688_DOUBLE("Capture Volume", 0, ES1688_RECLEV_DEV, ES1688_RECLEV_DEV, 4, 0, 15, 0), ES1688_SINGLE("Capture Switch", 0, ES1688_REC_DEV, 4, 1, 1), { diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c index 8cfbff73a835..9a43baae7250 100644 --- a/sound/isa/es18xx.c +++ b/sound/isa/es18xx.c @@ -102,8 +102,6 @@ struct snd_es18xx { unsigned long port; /* port of ESS chip */ - unsigned long mpu_port; /* MPU-401 port of ESS chip */ - unsigned long fm_port; /* FM port */ unsigned long ctrl_port; /* Control port of ESS chip */ struct resource *res_port; struct resource *res_mpu_port; @@ -116,12 +114,9 @@ struct snd_es18xx { unsigned short audio2_vol; /* volume level of audio2 */ unsigned short active; /* active channel mask */ - unsigned int dma1_size; - unsigned int dma2_size; unsigned int dma1_shift; unsigned int dma2_shift; - struct snd_card *card; struct snd_pcm *pcm; struct snd_pcm_substream *playback_a_substream; struct snd_pcm_substream *capture_a_substream; @@ -136,14 +131,9 @@ struct snd_es18xx { spinlock_t reg_lock; spinlock_t mixer_lock; - spinlock_t ctrl_lock; #ifdef CONFIG_PM unsigned char pm_reg; #endif -}; - -struct snd_audiodrive { - struct snd_es18xx *chip; #ifdef CONFIG_PNP struct pnp_dev *dev; struct pnp_dev *devc; @@ -359,7 +349,7 @@ static inline int snd_es18xx_mixer_writable(struct snd_es18xx *chip, unsigned ch } -static int snd_es18xx_reset(struct snd_es18xx *chip) +static int __devinit snd_es18xx_reset(struct snd_es18xx *chip) { int i; outb(0x03, chip->port + 0x06); @@ -495,8 +485,6 @@ static int snd_es18xx_playback1_prepare(struct snd_es18xx *chip, unsigned int size = snd_pcm_lib_buffer_bytes(substream); unsigned int count = snd_pcm_lib_period_bytes(substream); - chip->dma2_size = size; - snd_es18xx_rate_set(chip, substream, DAC2); /* Transfer Count Reload */ @@ -596,8 +584,6 @@ static int snd_es18xx_capture_prepare(struct snd_pcm_substream *substream) unsigned int size = snd_pcm_lib_buffer_bytes(substream); unsigned int count = snd_pcm_lib_period_bytes(substream); - chip->dma1_size = size; - snd_es18xx_reset_fifo(chip); /* Set stereo/mono */ @@ -664,8 +650,6 @@ static int snd_es18xx_playback2_prepare(struct snd_es18xx *chip, unsigned int size = snd_pcm_lib_buffer_bytes(substream); unsigned int count = snd_pcm_lib_period_bytes(substream); - chip->dma1_size = size; - snd_es18xx_reset_fifo(chip); /* Set stereo/mono */ @@ -755,7 +739,8 @@ static int snd_es18xx_playback_trigger(struct snd_pcm_substream *substream, static irqreturn_t snd_es18xx_interrupt(int irq, void *dev_id) { - struct snd_es18xx *chip = dev_id; + struct snd_card *card = dev_id; + struct snd_es18xx *chip = card->private_data; unsigned char status; if (chip->caps & ES18XX_CONTROL) { @@ -805,12 +790,16 @@ static irqreturn_t snd_es18xx_interrupt(int irq, void *dev_id) int split = 0; if (chip->caps & ES18XX_HWV) { split = snd_es18xx_mixer_read(chip, 0x64) & 0x80; - snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->hw_switch->id); - snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->hw_volume->id); + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &chip->hw_switch->id); + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &chip->hw_volume->id); } if (!split) { - snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->master_switch->id); - snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->master_volume->id); + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &chip->master_switch->id); + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &chip->master_volume->id); } /* ack interrupt */ snd_es18xx_mixer_write(chip, 0x66, 0x00); @@ -821,17 +810,18 @@ static irqreturn_t snd_es18xx_interrupt(int irq, void *dev_id) static snd_pcm_uframes_t snd_es18xx_playback_pointer(struct snd_pcm_substream *substream) { struct snd_es18xx *chip = snd_pcm_substream_chip(substream); + unsigned int size = snd_pcm_lib_buffer_bytes(substream); int pos; if (substream->number == 0 && (chip->caps & ES18XX_PCM2)) { if (!(chip->active & DAC2)) return 0; - pos = snd_dma_pointer(chip->dma2, chip->dma2_size); + pos = snd_dma_pointer(chip->dma2, size); return pos >> chip->dma2_shift; } else { if (!(chip->active & DAC1)) return 0; - pos = snd_dma_pointer(chip->dma1, chip->dma1_size); + pos = snd_dma_pointer(chip->dma1, size); return pos >> chip->dma1_shift; } } @@ -839,11 +829,12 @@ static snd_pcm_uframes_t snd_es18xx_playback_pointer(struct snd_pcm_substream *s static snd_pcm_uframes_t snd_es18xx_capture_pointer(struct snd_pcm_substream *substream) { struct snd_es18xx *chip = snd_pcm_substream_chip(substream); + unsigned int size = snd_pcm_lib_buffer_bytes(substream); int pos; if (!(chip->active & ADC1)) return 0; - pos = snd_dma_pointer(chip->dma1, chip->dma1_size); + pos = snd_dma_pointer(chip->dma1, size); return pos >> chip->dma1_shift; } @@ -974,9 +965,6 @@ static int snd_es18xx_capture_close(struct snd_pcm_substream *substream) static int snd_es18xx_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts4Source[4] = { - "Mic", "CD", "Line", "Master" - }; static char *texts5Source[5] = { "Mic", "CD", "Line", "Master", "Mix" }; @@ -994,7 +982,8 @@ static int snd_es18xx_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_ele uinfo->value.enumerated.items = 4; if (uinfo->value.enumerated.item > 3) uinfo->value.enumerated.item = 3; - strcpy(uinfo->value.enumerated.name, texts4Source[uinfo->value.enumerated.item]); + strcpy(uinfo->value.enumerated.name, + texts5Source[uinfo->value.enumerated.item]); break; case 0x1887: case 0x1888: @@ -1313,7 +1302,7 @@ ES18XX_DOUBLE("Aux Capture Volume", 0, 0x6c, 0x6c, 4, 0, 15, 0) * The chipset specific mixer controls */ static struct snd_kcontrol_new snd_es18xx_opt_speaker = - ES18XX_SINGLE("PC Speaker Playback Volume", 0, 0x3c, 0, 7, 0); + ES18XX_SINGLE("Beep Playback Volume", 0, 0x3c, 0, 7, 0); static struct snd_kcontrol_new snd_es18xx_opt_1869[] = { ES18XX_SINGLE("Capture Switch", 0, 0x1c, 4, 1, 1), @@ -1378,11 +1367,9 @@ ES18XX_SINGLE("Hardware Master Volume Split", 0, 0x64, 7, 1, 0), static int __devinit snd_es18xx_config_read(struct snd_es18xx *chip, unsigned char reg) { int data; - unsigned long flags; - spin_lock_irqsave(&chip->ctrl_lock, flags); + outb(reg, chip->ctrl_port); data = inb(chip->ctrl_port + 1); - spin_unlock_irqrestore(&chip->ctrl_lock, flags); return data; } @@ -1398,7 +1385,9 @@ static void __devinit snd_es18xx_config_write(struct snd_es18xx *chip, #endif } -static int __devinit snd_es18xx_initialize(struct snd_es18xx *chip) +static int __devinit snd_es18xx_initialize(struct snd_es18xx *chip, + unsigned long mpu_port, + unsigned long fm_port) { int mask = 0; @@ -1412,15 +1401,15 @@ static int __devinit snd_es18xx_initialize(struct snd_es18xx *chip) if (chip->caps & ES18XX_CONTROL) { /* Hardware volume IRQ */ snd_es18xx_config_write(chip, 0x27, chip->irq); - if (chip->fm_port > 0 && chip->fm_port != SNDRV_AUTO_PORT) { + if (fm_port > 0 && fm_port != SNDRV_AUTO_PORT) { /* FM I/O */ - snd_es18xx_config_write(chip, 0x62, chip->fm_port >> 8); - snd_es18xx_config_write(chip, 0x63, chip->fm_port & 0xff); + snd_es18xx_config_write(chip, 0x62, fm_port >> 8); + snd_es18xx_config_write(chip, 0x63, fm_port & 0xff); } - if (chip->mpu_port > 0 && chip->mpu_port != SNDRV_AUTO_PORT) { + if (mpu_port > 0 && mpu_port != SNDRV_AUTO_PORT) { /* MPU-401 I/O */ - snd_es18xx_config_write(chip, 0x64, chip->mpu_port >> 8); - snd_es18xx_config_write(chip, 0x65, chip->mpu_port & 0xff); + snd_es18xx_config_write(chip, 0x64, mpu_port >> 8); + snd_es18xx_config_write(chip, 0x65, mpu_port & 0xff); /* MPU-401 IRQ */ snd_es18xx_config_write(chip, 0x28, chip->irq); } @@ -1507,11 +1496,12 @@ static int __devinit snd_es18xx_initialize(struct snd_es18xx *chip) snd_es18xx_mixer_write(chip, 0x7A, 0x68); /* Enable and set hardware volume interrupt */ snd_es18xx_mixer_write(chip, 0x64, 0x06); - if (chip->mpu_port > 0 && chip->mpu_port != SNDRV_AUTO_PORT) { + if (mpu_port > 0 && mpu_port != SNDRV_AUTO_PORT) { /* MPU401 share irq with audio Joystick enabled FM enabled */ - snd_es18xx_mixer_write(chip, 0x40, 0x43 | (chip->mpu_port & 0xf0) >> 1); + snd_es18xx_mixer_write(chip, 0x40, + 0x43 | (mpu_port & 0xf0) >> 1); } snd_es18xx_mixer_write(chip, 0x7f, ((irqmask + 1) << 1) | 0x01); } @@ -1629,7 +1619,9 @@ static int __devinit snd_es18xx_identify(struct snd_es18xx *chip) return 0; } -static int __devinit snd_es18xx_probe(struct snd_es18xx *chip) +static int __devinit snd_es18xx_probe(struct snd_es18xx *chip, + unsigned long mpu_port, + unsigned long fm_port) { if (snd_es18xx_identify(chip) < 0) { snd_printk(KERN_ERR PFX "[0x%lx] ESS chip not found\n", chip->port); @@ -1650,8 +1642,6 @@ static int __devinit snd_es18xx_probe(struct snd_es18xx *chip) chip->caps = ES18XX_PCM2 | ES18XX_SPATIALIZER | ES18XX_RECMIX | ES18XX_NEW_RATE | ES18XX_AUXB | ES18XX_I2S | ES18XX_CONTROL | ES18XX_HWV; break; case 0x1887: - chip->caps = ES18XX_PCM2 | ES18XX_RECMIX | ES18XX_AUXB | ES18XX_DUPLEX_SAME; - break; case 0x1888: chip->caps = ES18XX_PCM2 | ES18XX_RECMIX | ES18XX_AUXB | ES18XX_DUPLEX_SAME; break; @@ -1666,7 +1656,7 @@ static int __devinit snd_es18xx_probe(struct snd_es18xx *chip) if (chip->dma1 == chip->dma2) chip->caps &= ~(ES18XX_PCM2 | ES18XX_DUPLEX_SAME); - return snd_es18xx_initialize(chip); + return snd_es18xx_initialize(chip, mpu_port, fm_port); } static struct snd_pcm_ops snd_es18xx_playback_ops = { @@ -1691,8 +1681,10 @@ static struct snd_pcm_ops snd_es18xx_capture_ops = { .pointer = snd_es18xx_capture_pointer, }; -static int __devinit snd_es18xx_pcm(struct snd_es18xx *chip, int device, struct snd_pcm ** rpcm) +static int __devinit snd_es18xx_pcm(struct snd_card *card, int device, + struct snd_pcm **rpcm) { + struct snd_es18xx *chip = card->private_data; struct snd_pcm *pcm; char str[16]; int err; @@ -1701,9 +1693,9 @@ static int __devinit snd_es18xx_pcm(struct snd_es18xx *chip, int device, struct *rpcm = NULL; sprintf(str, "ES%x", chip->version); if (chip->caps & ES18XX_PCM2) - err = snd_pcm_new(chip->card, str, device, 2, 1, &pcm); + err = snd_pcm_new(card, str, device, 2, 1, &pcm); else - err = snd_pcm_new(chip->card, str, device, 1, 1, &pcm); + err = snd_pcm_new(card, str, device, 1, 1, &pcm); if (err < 0) return err; @@ -1734,10 +1726,9 @@ static int __devinit snd_es18xx_pcm(struct snd_es18xx *chip, int device, struct #ifdef CONFIG_PM static int snd_es18xx_suspend(struct snd_card *card, pm_message_t state) { - struct snd_audiodrive *acard = card->private_data; - struct snd_es18xx *chip = acard->chip; + struct snd_es18xx *chip = card->private_data; - snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot); + snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); snd_pcm_suspend_all(chip->pcm); @@ -1752,24 +1743,25 @@ static int snd_es18xx_suspend(struct snd_card *card, pm_message_t state) static int snd_es18xx_resume(struct snd_card *card) { - struct snd_audiodrive *acard = card->private_data; - struct snd_es18xx *chip = acard->chip; + struct snd_es18xx *chip = card->private_data; /* restore PM register, we won't wake till (not 0x07) i/o activity though */ snd_es18xx_write(chip, ES18XX_PM, chip->pm_reg ^= ES18XX_PM_FM); - snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0); + snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0; } #endif /* CONFIG_PM */ -static int snd_es18xx_free(struct snd_es18xx *chip) +static int snd_es18xx_free(struct snd_card *card) { + struct snd_es18xx *chip = card->private_data; + release_and_free_resource(chip->res_port); release_and_free_resource(chip->res_ctrl_port); release_and_free_resource(chip->res_mpu_port); if (chip->irq >= 0) - free_irq(chip->irq, (void *) chip); + free_irq(chip->irq, (void *) card); if (chip->dma1 >= 0) { disable_dma(chip->dma1); free_dma(chip->dma1); @@ -1778,93 +1770,82 @@ static int snd_es18xx_free(struct snd_es18xx *chip) disable_dma(chip->dma2); free_dma(chip->dma2); } - kfree(chip); return 0; } static int snd_es18xx_dev_free(struct snd_device *device) { - struct snd_es18xx *chip = device->device_data; - return snd_es18xx_free(chip); + return snd_es18xx_free(device->card); } static int __devinit snd_es18xx_new_device(struct snd_card *card, unsigned long port, unsigned long mpu_port, unsigned long fm_port, - int irq, int dma1, int dma2, - struct snd_es18xx ** rchip) + int irq, int dma1, int dma2) { - struct snd_es18xx *chip; + struct snd_es18xx *chip = card->private_data; static struct snd_device_ops ops = { .dev_free = snd_es18xx_dev_free, }; int err; - *rchip = NULL; - chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (chip == NULL) - return -ENOMEM; spin_lock_init(&chip->reg_lock); spin_lock_init(&chip->mixer_lock); - spin_lock_init(&chip->ctrl_lock); - chip->card = card; chip->port = port; - chip->mpu_port = mpu_port; - chip->fm_port = fm_port; chip->irq = -1; chip->dma1 = -1; chip->dma2 = -1; chip->audio2_vol = 0x00; chip->active = 0; - if ((chip->res_port = request_region(port, 16, "ES18xx")) == NULL) { - snd_es18xx_free(chip); + chip->res_port = request_region(port, 16, "ES18xx"); + if (chip->res_port == NULL) { + snd_es18xx_free(card); snd_printk(KERN_ERR PFX "unable to grap ports 0x%lx-0x%lx\n", port, port + 16 - 1); return -EBUSY; } - if (request_irq(irq, snd_es18xx_interrupt, IRQF_DISABLED, "ES18xx", (void *) chip)) { - snd_es18xx_free(chip); + if (request_irq(irq, snd_es18xx_interrupt, IRQF_DISABLED, "ES18xx", + (void *) card)) { + snd_es18xx_free(card); snd_printk(KERN_ERR PFX "unable to grap IRQ %d\n", irq); return -EBUSY; } chip->irq = irq; if (request_dma(dma1, "ES18xx DMA 1")) { - snd_es18xx_free(chip); + snd_es18xx_free(card); snd_printk(KERN_ERR PFX "unable to grap DMA1 %d\n", dma1); return -EBUSY; } chip->dma1 = dma1; if (dma2 != dma1 && request_dma(dma2, "ES18xx DMA 2")) { - snd_es18xx_free(chip); + snd_es18xx_free(card); snd_printk(KERN_ERR PFX "unable to grap DMA2 %d\n", dma2); return -EBUSY; } chip->dma2 = dma2; - if (snd_es18xx_probe(chip) < 0) { - snd_es18xx_free(chip); - return -ENODEV; - } - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { - snd_es18xx_free(chip); + if (snd_es18xx_probe(chip, mpu_port, fm_port) < 0) { + snd_es18xx_free(card); + return -ENODEV; + } + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); + if (err < 0) { + snd_es18xx_free(card); return err; } - *rchip = chip; return 0; } -static int __devinit snd_es18xx_mixer(struct snd_es18xx *chip) +static int __devinit snd_es18xx_mixer(struct snd_card *card) { - struct snd_card *card; + struct snd_es18xx *chip = card->private_data; int err; unsigned int idx; - card = chip->card; - strcpy(card->mixername, chip->pcm->name); for (idx = 0; idx < ARRAY_SIZE(snd_es18xx_base_controls); idx++) { @@ -1986,7 +1967,7 @@ 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_ISAPNP; /* Enable this card */ #ifdef CONFIG_PNP -static int isapnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1}; +static int isapnp[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; #endif static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x220,0x240,0x260,0x280 */ #ifndef CONFIG_PNP @@ -2063,11 +2044,11 @@ static int __devinit snd_audiodrive_pnp_init_main(int dev, struct pnp_dev *pdev) return 0; } -static int __devinit snd_audiodrive_pnp(int dev, struct snd_audiodrive *acard, +static int __devinit snd_audiodrive_pnp(int dev, struct snd_es18xx *chip, struct pnp_dev *pdev) { - acard->dev = pdev; - if (snd_audiodrive_pnp_init_main(dev, acard->dev) < 0) + chip->dev = pdev; + if (snd_audiodrive_pnp_init_main(dev, chip->dev) < 0) return -EBUSY; return 0; } @@ -2093,26 +2074,26 @@ static struct pnp_card_device_id snd_audiodrive_pnpids[] = { MODULE_DEVICE_TABLE(pnp_card, snd_audiodrive_pnpids); -static int __devinit snd_audiodrive_pnpc(int dev, struct snd_audiodrive *acard, +static int __devinit snd_audiodrive_pnpc(int dev, struct snd_es18xx *chip, struct pnp_card_link *card, const struct pnp_card_device_id *id) { - acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL); - if (acard->dev == NULL) + chip->dev = pnp_request_card_device(card, id->devs[0].id, NULL); + if (chip->dev == NULL) return -EBUSY; - acard->devc = pnp_request_card_device(card, id->devs[1].id, NULL); - if (acard->devc == NULL) + chip->devc = pnp_request_card_device(card, id->devs[1].id, NULL); + if (chip->devc == NULL) return -EBUSY; /* Control port initialization */ - if (pnp_activate_dev(acard->devc) < 0) { + if (pnp_activate_dev(chip->devc) < 0) { snd_printk(KERN_ERR PFX "PnP control configure failure (out of resources?)\n"); return -EAGAIN; } snd_printdd("pnp: port=0x%llx\n", - (unsigned long long)pnp_port_start(acard->devc, 0)); - if (snd_audiodrive_pnp_init_main(dev, acard->dev) < 0) + (unsigned long long)pnp_port_start(chip->devc, 0)); + if (snd_audiodrive_pnp_init_main(dev, chip->dev) < 0) return -EBUSY; return 0; @@ -2128,24 +2109,20 @@ static int __devinit snd_audiodrive_pnpc(int dev, struct snd_audiodrive *acard, static int snd_es18xx_card_new(int dev, struct snd_card **cardp) { return snd_card_create(index[dev], id[dev], THIS_MODULE, - sizeof(struct snd_audiodrive), cardp); + sizeof(struct snd_es18xx), cardp); } static int __devinit snd_audiodrive_probe(struct snd_card *card, int dev) { - struct snd_audiodrive *acard = card->private_data; - struct snd_es18xx *chip; + struct snd_es18xx *chip = card->private_data; struct snd_opl3 *opl3; int err; - if ((err = snd_es18xx_new_device(card, - port[dev], - mpu_port[dev], - fm_port[dev], - irq[dev], dma1[dev], dma2[dev], - &chip)) < 0) + err = snd_es18xx_new_device(card, + port[dev], mpu_port[dev], fm_port[dev], + irq[dev], dma1[dev], dma2[dev]); + if (err < 0) return err; - acard->chip = chip; sprintf(card->driver, "ES%x", chip->version); @@ -2161,26 +2138,32 @@ static int __devinit snd_audiodrive_probe(struct snd_card *card, int dev) chip->port, irq[dev], dma1[dev]); - if ((err = snd_es18xx_pcm(chip, 0, NULL)) < 0) + err = snd_es18xx_pcm(card, 0, NULL); + if (err < 0) return err; - if ((err = snd_es18xx_mixer(chip)) < 0) + err = snd_es18xx_mixer(card); + if (err < 0) return err; if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) { - if (snd_opl3_create(card, chip->fm_port, chip->fm_port + 2, OPL3_HW_OPL3, 0, &opl3) < 0) { - snd_printk(KERN_WARNING PFX "opl3 not detected at 0x%lx\n", chip->fm_port); + if (snd_opl3_create(card, fm_port[dev], fm_port[dev] + 2, + OPL3_HW_OPL3, 0, &opl3) < 0) { + snd_printk(KERN_WARNING PFX + "opl3 not detected at 0x%lx\n", + fm_port[dev]); } else { - if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) + err = snd_opl3_hwdep_new(opl3, 0, 1, NULL); + if (err < 0) return err; } } if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) { - if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_ES18XX, - chip->mpu_port, 0, - irq[dev], 0, - &chip->rmidi)) < 0) + err = snd_mpu401_uart_new(card, 0, MPU401_HW_ES18XX, + mpu_port[dev], 0, + irq[dev], 0, &chip->rmidi); + if (err < 0) return err; } diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c index 02e30d7c6a93..6123c7531110 100644 --- a/sound/isa/opti9xx/miro.c +++ b/sound/isa/opti9xx/miro.c @@ -25,6 +25,7 @@ #include <linux/init.h> #include <linux/err.h> #include <linux/isa.h> +#include <linux/pnp.h> #include <linux/delay.h> #include <linux/slab.h> #include <linux/ioport.h> @@ -40,7 +41,7 @@ #define SNDRV_LEGACY_FIND_FREE_IRQ #define SNDRV_LEGACY_FIND_FREE_DMA #include <sound/initval.h> -#include "miro.h" +#include <sound/aci.h> MODULE_AUTHOR("Martin Langer <martin-langer@gmx.de>"); MODULE_LICENSE("GPL"); @@ -60,6 +61,9 @@ static int dma1 = SNDRV_DEFAULT_DMA1; /* 0,1,3 */ static int dma2 = SNDRV_DEFAULT_DMA1; /* 0,1,3 */ static int wss; static int ide; +#ifdef CONFIG_PNP +static int isapnp = 1; /* Enable ISA PnP detection */ +#endif module_param(index, int, 0444); MODULE_PARM_DESC(index, "Index value for miro soundcard."); @@ -83,6 +87,10 @@ module_param(wss, int, 0444); MODULE_PARM_DESC(wss, "wss mode"); module_param(ide, int, 0444); MODULE_PARM_DESC(ide, "enable ide port"); +#ifdef CONFIG_PNP +module_param(isapnp, bool, 0444); +MODULE_PARM_DESC(isapnp, "Enable ISA PnP detection for specified soundcard."); +#endif #define OPTi9XX_HW_DETECT 0 #define OPTi9XX_HW_82C928 1 @@ -96,7 +104,6 @@ MODULE_PARM_DESC(ide, "enable ide port"); #define OPTi9XX_MC_REG(n) n - struct snd_miro { unsigned short hardware; unsigned char password; @@ -110,7 +117,6 @@ struct snd_miro { unsigned long pwd_reg; spinlock_t lock; - struct snd_card *card; struct snd_pcm *pcm; long wss_base; @@ -118,23 +124,13 @@ struct snd_miro { int dma1; int dma2; - long fm_port; - long mpu_port; int mpu_irq; - unsigned long aci_port; - int aci_vendor; - int aci_product; - int aci_version; - int aci_amp; - int aci_preamp; - int aci_solomode; - - struct mutex aci_mutex; + struct snd_miro_aci *aci; }; -static void snd_miro_proc_init(struct snd_miro * miro); +static struct snd_miro_aci aci_device; static char * snd_opti9xx_names[] = { "unkown", @@ -143,17 +139,33 @@ static char * snd_opti9xx_names[] = { "82C930", "82C931", "82C933" }; +static int snd_miro_pnp_is_probed; + +#ifdef CONFIG_PNP + +static struct pnp_card_device_id snd_miro_pnpids[] = { + /* PCM20 and PCM12 in PnP mode */ + { .id = "MIR0924", + .devs = { { "MIR0000" }, { "MIR0002" }, { "MIR0005" } }, }, + { .id = "" } +}; + +MODULE_DEVICE_TABLE(pnp_card, snd_miro_pnpids); + +#endif /* CONFIG_PNP */ + /* * ACI control */ -static int aci_busy_wait(struct snd_miro * miro) +static int aci_busy_wait(struct snd_miro_aci *aci) { long timeout; unsigned char byte; - for (timeout = 1; timeout <= ACI_MINTIME+30; timeout++) { - if (((byte=inb(miro->aci_port + ACI_REG_BUSY)) & 1) == 0) { + for (timeout = 1; timeout <= ACI_MINTIME + 30; timeout++) { + byte = inb(aci->aci_port + ACI_REG_BUSY); + if ((byte & 1) == 0) { if (timeout >= ACI_MINTIME) snd_printd("aci ready in round %ld.\n", timeout-ACI_MINTIME); @@ -179,10 +191,10 @@ static int aci_busy_wait(struct snd_miro * miro) return -EBUSY; } -static inline int aci_write(struct snd_miro * miro, unsigned char byte) +static inline int aci_write(struct snd_miro_aci *aci, unsigned char byte) { - if (aci_busy_wait(miro) >= 0) { - outb(byte, miro->aci_port + ACI_REG_COMMAND); + if (aci_busy_wait(aci) >= 0) { + outb(byte, aci->aci_port + ACI_REG_COMMAND); return 0; } else { snd_printk(KERN_ERR "aci busy, aci_write(0x%x) stopped.\n", byte); @@ -190,12 +202,12 @@ static inline int aci_write(struct snd_miro * miro, unsigned char byte) } } -static inline int aci_read(struct snd_miro * miro) +static inline int aci_read(struct snd_miro_aci *aci) { unsigned char byte; - if (aci_busy_wait(miro) >= 0) { - byte=inb(miro->aci_port + ACI_REG_STATUS); + if (aci_busy_wait(aci) >= 0) { + byte = inb(aci->aci_port + ACI_REG_STATUS); return byte; } else { snd_printk(KERN_ERR "aci busy, aci_read() stopped.\n"); @@ -203,39 +215,49 @@ static inline int aci_read(struct snd_miro * miro) } } -static int aci_cmd(struct snd_miro * miro, int write1, int write2, int write3) +int snd_aci_cmd(struct snd_miro_aci *aci, int write1, int write2, int write3) { int write[] = {write1, write2, write3}; int value, i; - if (mutex_lock_interruptible(&miro->aci_mutex)) + if (mutex_lock_interruptible(&aci->aci_mutex)) return -EINTR; for (i=0; i<3; i++) { if (write[i]< 0 || write[i] > 255) break; else { - value = aci_write(miro, write[i]); + value = aci_write(aci, write[i]); if (value < 0) goto out; } } - value = aci_read(miro); + value = aci_read(aci); -out: mutex_unlock(&miro->aci_mutex); +out: mutex_unlock(&aci->aci_mutex); return value; } +EXPORT_SYMBOL(snd_aci_cmd); + +static int aci_getvalue(struct snd_miro_aci *aci, unsigned char index) +{ + return snd_aci_cmd(aci, ACI_STATUS, index, -1); +} -static int aci_getvalue(struct snd_miro * miro, unsigned char index) +static int aci_setvalue(struct snd_miro_aci *aci, unsigned char index, + int value) { - return aci_cmd(miro, ACI_STATUS, index, -1); + return snd_aci_cmd(aci, index, value, -1); } -static int aci_setvalue(struct snd_miro * miro, unsigned char index, int value) +struct snd_miro_aci *snd_aci_get_aci(void) { - return aci_cmd(miro, index, value, -1); + if (aci_device.aci_port == 0) + return NULL; + return &aci_device; } +EXPORT_SYMBOL(snd_aci_get_aci); /* * MIXER part @@ -249,8 +271,10 @@ static int snd_miro_get_capture(struct snd_kcontrol *kcontrol, struct snd_miro *miro = snd_kcontrol_chip(kcontrol); int value; - if ((value = aci_getvalue(miro, ACI_S_GENERAL)) < 0) { - snd_printk(KERN_ERR "snd_miro_get_capture() failed: %d\n", value); + value = aci_getvalue(miro->aci, ACI_S_GENERAL); + if (value < 0) { + snd_printk(KERN_ERR "snd_miro_get_capture() failed: %d\n", + value); return value; } @@ -267,13 +291,15 @@ static int snd_miro_put_capture(struct snd_kcontrol *kcontrol, value = !(ucontrol->value.integer.value[0]); - if ((error = aci_setvalue(miro, ACI_SET_SOLOMODE, value)) < 0) { - snd_printk(KERN_ERR "snd_miro_put_capture() failed: %d\n", error); + error = aci_setvalue(miro->aci, ACI_SET_SOLOMODE, value); + if (error < 0) { + snd_printk(KERN_ERR "snd_miro_put_capture() failed: %d\n", + error); return error; } - change = (value != miro->aci_solomode); - miro->aci_solomode = value; + change = (value != miro->aci->aci_solomode); + miro->aci->aci_solomode = value; return change; } @@ -295,7 +321,7 @@ static int snd_miro_get_preamp(struct snd_kcontrol *kcontrol, struct snd_miro *miro = snd_kcontrol_chip(kcontrol); int value; - if (miro->aci_version <= 176) { + if (miro->aci->aci_version <= 176) { /* OSS says it's not readable with versions < 176. @@ -303,12 +329,14 @@ static int snd_miro_get_preamp(struct snd_kcontrol *kcontrol, which is a PCM12 with aci_version = 176. */ - ucontrol->value.integer.value[0] = miro->aci_preamp; + ucontrol->value.integer.value[0] = miro->aci->aci_preamp; return 0; } - if ((value = aci_getvalue(miro, ACI_GET_PREAMP)) < 0) { - snd_printk(KERN_ERR "snd_miro_get_preamp() failed: %d\n", value); + value = aci_getvalue(miro->aci, ACI_GET_PREAMP); + if (value < 0) { + snd_printk(KERN_ERR "snd_miro_get_preamp() failed: %d\n", + value); return value; } @@ -325,13 +353,15 @@ static int snd_miro_put_preamp(struct snd_kcontrol *kcontrol, value = ucontrol->value.integer.value[0]; - if ((error = aci_setvalue(miro, ACI_SET_PREAMP, value)) < 0) { - snd_printk(KERN_ERR "snd_miro_put_preamp() failed: %d\n", error); + error = aci_setvalue(miro->aci, ACI_SET_PREAMP, value); + if (error < 0) { + snd_printk(KERN_ERR "snd_miro_put_preamp() failed: %d\n", + error); return error; } - change = (value != miro->aci_preamp); - miro->aci_preamp = value; + change = (value != miro->aci->aci_preamp); + miro->aci->aci_preamp = value; return change; } @@ -342,7 +372,7 @@ static int snd_miro_get_amp(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_miro *miro = snd_kcontrol_chip(kcontrol); - ucontrol->value.integer.value[0] = miro->aci_amp; + ucontrol->value.integer.value[0] = miro->aci->aci_amp; return 0; } @@ -355,13 +385,14 @@ static int snd_miro_put_amp(struct snd_kcontrol *kcontrol, value = ucontrol->value.integer.value[0]; - if ((error = aci_setvalue(miro, ACI_SET_POWERAMP, value)) < 0) { + error = aci_setvalue(miro->aci, ACI_SET_POWERAMP, value); + if (error < 0) { snd_printk(KERN_ERR "snd_miro_put_amp() to %d failed: %d\n", value, error); return error; } - change = (value != miro->aci_amp); - miro->aci_amp = value; + change = (value != miro->aci->aci_amp); + miro->aci->aci_amp = value; return change; } @@ -410,12 +441,14 @@ static int snd_miro_get_double(struct snd_kcontrol *kcontrol, int right_reg = kcontrol->private_value & 0xff; int left_reg = right_reg + 1; - if ((right_val = aci_getvalue(miro, right_reg)) < 0) { + right_val = aci_getvalue(miro->aci, right_reg); + if (right_val < 0) { snd_printk(KERN_ERR "aci_getvalue(%d) failed: %d\n", right_reg, right_val); return right_val; } - if ((left_val = aci_getvalue(miro, left_reg)) < 0) { + left_val = aci_getvalue(miro->aci, left_reg); + if (left_val < 0) { snd_printk(KERN_ERR "aci_getvalue(%d) failed: %d\n", left_reg, left_val); return left_val; } @@ -451,6 +484,7 @@ static int snd_miro_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_miro *miro = snd_kcontrol_chip(kcontrol); + struct snd_miro_aci *aci = miro->aci; int left, right, left_old, right_old; int setreg_left, setreg_right, getreg_left, getreg_right; int change, error; @@ -459,21 +493,21 @@ static int snd_miro_put_double(struct snd_kcontrol *kcontrol, right = ucontrol->value.integer.value[1]; setreg_right = (kcontrol->private_value >> 8) & 0xff; - if (setreg_right == ACI_SET_MASTER) { - setreg_left = setreg_right + 1; - } else { - setreg_left = setreg_right + 8; - } + setreg_left = setreg_right + 8; + if (setreg_right == ACI_SET_MASTER) + setreg_left -= 7; getreg_right = kcontrol->private_value & 0xff; getreg_left = getreg_right + 1; - if ((left_old = aci_getvalue(miro, getreg_left)) < 0) { + left_old = aci_getvalue(aci, getreg_left); + if (left_old < 0) { snd_printk(KERN_ERR "aci_getvalue(%d) failed: %d\n", getreg_left, left_old); return left_old; } - if ((right_old = aci_getvalue(miro, getreg_right)) < 0) { + right_old = aci_getvalue(aci, getreg_right); + if (right_old < 0) { snd_printk(KERN_ERR "aci_getvalue(%d) failed: %d\n", getreg_right, right_old); return right_old; } @@ -492,13 +526,15 @@ static int snd_miro_put_double(struct snd_kcontrol *kcontrol, right_old = 0x80 - right_old; if (left >= 0) { - if ((error = aci_setvalue(miro, setreg_left, left)) < 0) { + error = aci_setvalue(aci, setreg_left, left); + if (error < 0) { snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n", left, error); return error; } } else { - if ((error = aci_setvalue(miro, setreg_left, 0x80 - left)) < 0) { + error = aci_setvalue(aci, setreg_left, 0x80 - left); + if (error < 0) { snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n", 0x80 - left, error); return error; @@ -506,13 +542,15 @@ static int snd_miro_put_double(struct snd_kcontrol *kcontrol, } if (right >= 0) { - if ((error = aci_setvalue(miro, setreg_right, right)) < 0) { + error = aci_setvalue(aci, setreg_right, right); + if (error < 0) { snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n", right, error); return error; } } else { - if ((error = aci_setvalue(miro, setreg_right, 0x80 - right)) < 0) { + error = aci_setvalue(aci, setreg_right, 0x80 - right); + if (error < 0) { snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n", 0x80 - right, error); return error; @@ -530,12 +568,14 @@ static int snd_miro_put_double(struct snd_kcontrol *kcontrol, left_old = 0x20 - left_old; right_old = 0x20 - right_old; - if ((error = aci_setvalue(miro, setreg_left, 0x20 - left)) < 0) { + error = aci_setvalue(aci, setreg_left, 0x20 - left); + if (error < 0) { snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n", 0x20 - left, error); return error; } - if ((error = aci_setvalue(miro, setreg_right, 0x20 - right)) < 0) { + error = aci_setvalue(aci, setreg_right, 0x20 - right); + if (error < 0) { snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n", 0x20 - right, error); return error; @@ -633,11 +673,13 @@ static unsigned char aci_init_values[][2] __devinitdata = { static int __devinit snd_set_aci_init_values(struct snd_miro *miro) { int idx, error; + struct snd_miro_aci *aci = miro->aci; /* enable WSS on PCM1 */ - if ((miro->aci_product == 'A') && wss) { - if ((error = aci_setvalue(miro, ACI_SET_WSS, wss)) < 0) { + if ((aci->aci_product == 'A') && wss) { + error = aci_setvalue(aci, ACI_SET_WSS, wss); + if (error < 0) { snd_printk(KERN_ERR "enabling WSS mode failed\n"); return error; } @@ -646,7 +688,8 @@ static int __devinit snd_set_aci_init_values(struct snd_miro *miro) /* enable IDE port */ if (ide) { - if ((error = aci_setvalue(miro, ACI_SET_IDE, ide)) < 0) { + error = aci_setvalue(aci, ACI_SET_IDE, ide); + if (error < 0) { snd_printk(KERN_ERR "enabling IDE port failed\n"); return error; } @@ -654,32 +697,31 @@ static int __devinit snd_set_aci_init_values(struct snd_miro *miro) /* set common aci values */ - for (idx = 0; idx < ARRAY_SIZE(aci_init_values); idx++) - if ((error = aci_setvalue(miro, aci_init_values[idx][0], - aci_init_values[idx][1])) < 0) { + for (idx = 0; idx < ARRAY_SIZE(aci_init_values); idx++) { + error = aci_setvalue(aci, aci_init_values[idx][0], + aci_init_values[idx][1]); + if (error < 0) { snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n", aci_init_values[idx][0], error); return error; } - - miro->aci_amp = 0; - miro->aci_preamp = 0; - miro->aci_solomode = 1; + } + aci->aci_amp = 0; + aci->aci_preamp = 0; + aci->aci_solomode = 1; return 0; } -static int __devinit snd_miro_mixer(struct snd_miro *miro) +static int __devinit snd_miro_mixer(struct snd_card *card, + struct snd_miro *miro) { - struct snd_card *card; unsigned int idx; int err; - if (snd_BUG_ON(!miro || !miro->card)) + if (snd_BUG_ON(!miro || !card)) return -EINVAL; - card = miro->card; - switch (miro->hardware) { case OPTi9XX_HW_82C924: strcpy(card->mixername, "ACI & OPTi924"); @@ -697,7 +739,8 @@ static int __devinit snd_miro_mixer(struct snd_miro *miro) return err; } - if ((miro->aci_product == 'A') || (miro->aci_product == 'B')) { + if ((miro->aci->aci_product == 'A') || + (miro->aci->aci_product == 'B')) { /* PCM1/PCM12 with power-amp and Line 2 */ if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_line_control[0], miro))) < 0) return err; @@ -705,16 +748,17 @@ static int __devinit snd_miro_mixer(struct snd_miro *miro) return err; } - if ((miro->aci_product == 'B') || (miro->aci_product == 'C')) { + if ((miro->aci->aci_product == 'B') || + (miro->aci->aci_product == 'C')) { /* PCM12/PCM20 with mic-preamp */ if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_preamp_control[0], miro))) < 0) return err; - if (miro->aci_version >= 176) + if (miro->aci->aci_version >= 176) if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_capture_control[0], miro))) < 0) return err; } - if (miro->aci_product == 'C') { + if (miro->aci->aci_product == 'C') { /* PCM20 with radio and 7 band equalizer */ if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_radio_control[0], miro))) < 0) return err; @@ -757,21 +801,26 @@ static int __devinit snd_miro_init(struct snd_miro *chip, chip->irq = -1; chip->dma1 = -1; chip->dma2 = -1; - chip->fm_port = -1; chip->mpu_port = -1; chip->mpu_irq = -1; + chip->pwd_reg = 3; + +#ifdef CONFIG_PNP + if (isapnp && chip->mc_base) + /* PnP resource gives the least 10 bits */ + chip->mc_base |= 0xc00; + else +#endif + chip->mc_base = 0xf8c; + switch (hardware) { case OPTi9XX_HW_82C929: - chip->mc_base = 0xf8c; chip->password = 0xe3; - chip->pwd_reg = 3; break; case OPTi9XX_HW_82C924: - chip->mc_base = 0xf8c; chip->password = 0xe5; - chip->pwd_reg = 3; break; default: @@ -853,14 +902,15 @@ static void snd_miro_proc_read(struct snd_info_entry * entry, struct snd_info_buffer *buffer) { struct snd_miro *miro = (struct snd_miro *) entry->private_data; + struct snd_miro_aci *aci = miro->aci; char* model = "unknown"; /* miroSOUND PCM1 pro, early PCM12 */ if ((miro->hardware == OPTi9XX_HW_82C929) && - (miro->aci_vendor == 'm') && - (miro->aci_product == 'A')) { - switch(miro->aci_version) { + (aci->aci_vendor == 'm') && + (aci->aci_product == 'A')) { + switch (aci->aci_version) { case 3: model = "miroSOUND PCM1 pro"; break; @@ -873,9 +923,9 @@ static void snd_miro_proc_read(struct snd_info_entry * entry, /* miroSOUND PCM12, PCM12 (Rev. E), PCM12 pnp */ if ((miro->hardware == OPTi9XX_HW_82C924) && - (miro->aci_vendor == 'm') && - (miro->aci_product == 'B')) { - switch(miro->aci_version) { + (aci->aci_vendor == 'm') && + (aci->aci_product == 'B')) { + switch (aci->aci_version) { case 4: model = "miroSOUND PCM12"; break; @@ -891,9 +941,9 @@ static void snd_miro_proc_read(struct snd_info_entry * entry, /* miroSOUND PCM20 radio */ if ((miro->hardware == OPTi9XX_HW_82C924) && - (miro->aci_vendor == 'm') && - (miro->aci_product == 'C')) { - switch(miro->aci_version) { + (aci->aci_vendor == 'm') && + (aci->aci_product == 'C')) { + switch (aci->aci_version) { case 7: model = "miroSOUND PCM20 radio (Rev. E)"; break; @@ -917,17 +967,17 @@ static void snd_miro_proc_read(struct snd_info_entry * entry, snd_iprintf(buffer, "ACI information:\n"); snd_iprintf(buffer, " vendor : "); - switch(miro->aci_vendor) { + switch (aci->aci_vendor) { case 'm': snd_iprintf(buffer, "Miro\n"); break; default: - snd_iprintf(buffer, "unknown (0x%x)\n", miro->aci_vendor); + snd_iprintf(buffer, "unknown (0x%x)\n", aci->aci_vendor); break; } snd_iprintf(buffer, " product : "); - switch(miro->aci_product) { + switch (aci->aci_product) { case 'A': snd_iprintf(buffer, "miroSOUND PCM1 pro / (early) PCM12\n"); break; @@ -938,26 +988,27 @@ static void snd_miro_proc_read(struct snd_info_entry * entry, snd_iprintf(buffer, "miroSOUND PCM20 radio\n"); break; default: - snd_iprintf(buffer, "unknown (0x%x)\n", miro->aci_product); + snd_iprintf(buffer, "unknown (0x%x)\n", aci->aci_product); break; } snd_iprintf(buffer, " firmware: %d (0x%x)\n", - miro->aci_version, miro->aci_version); + aci->aci_version, aci->aci_version); snd_iprintf(buffer, " port : 0x%lx-0x%lx\n", - miro->aci_port, miro->aci_port+2); + aci->aci_port, aci->aci_port+2); snd_iprintf(buffer, " wss : 0x%x\n", wss); snd_iprintf(buffer, " ide : 0x%x\n", ide); - snd_iprintf(buffer, " solomode: 0x%x\n", miro->aci_solomode); - snd_iprintf(buffer, " amp : 0x%x\n", miro->aci_amp); - snd_iprintf(buffer, " preamp : 0x%x\n", miro->aci_preamp); + snd_iprintf(buffer, " solomode: 0x%x\n", aci->aci_solomode); + snd_iprintf(buffer, " amp : 0x%x\n", aci->aci_amp); + snd_iprintf(buffer, " preamp : 0x%x\n", aci->aci_preamp); } -static void __devinit snd_miro_proc_init(struct snd_miro * miro) +static void __devinit snd_miro_proc_init(struct snd_card *card, + struct snd_miro *miro) { struct snd_info_entry *entry; - if (! snd_card_proc_new(miro->card, "miro", &entry)) + if (!snd_card_proc_new(card, "miro", &entry)) snd_info_set_text_ops(entry, miro, snd_miro_proc_read); } @@ -974,37 +1025,40 @@ static int __devinit snd_miro_configure(struct snd_miro *chip) unsigned char mpu_irq_bits; unsigned long flags; + snd_miro_write_mask(chip, OPTi9XX_MC_REG(1), 0x80, 0x80); + snd_miro_write_mask(chip, OPTi9XX_MC_REG(2), 0x20, 0x20); /* OPL4 */ + snd_miro_write_mask(chip, OPTi9XX_MC_REG(5), 0x02, 0x02); + switch (chip->hardware) { case OPTi9XX_HW_82C924: snd_miro_write_mask(chip, OPTi9XX_MC_REG(6), 0x02, 0x02); - snd_miro_write_mask(chip, OPTi9XX_MC_REG(1), 0x80, 0x80); - snd_miro_write_mask(chip, OPTi9XX_MC_REG(2), 0x20, 0x20); /* OPL4 */ snd_miro_write_mask(chip, OPTi9XX_MC_REG(3), 0xf0, 0xff); - snd_miro_write_mask(chip, OPTi9XX_MC_REG(5), 0x02, 0x02); break; case OPTi9XX_HW_82C929: /* untested init commands for OPTi929 */ - snd_miro_write_mask(chip, OPTi9XX_MC_REG(1), 0x80, 0x80); - snd_miro_write_mask(chip, OPTi9XX_MC_REG(2), 0x20, 0x20); /* OPL4 */ snd_miro_write_mask(chip, OPTi9XX_MC_REG(4), 0x00, 0x0c); - snd_miro_write_mask(chip, OPTi9XX_MC_REG(5), 0x02, 0x02); break; default: snd_printk(KERN_ERR "chip %d not supported\n", chip->hardware); return -EINVAL; } - switch (chip->wss_base) { - case 0x530: + /* PnP resource says it decodes only 10 bits of address */ + switch (chip->wss_base & 0x3ff) { + case 0x130: + chip->wss_base = 0x530; wss_base_bits = 0x00; break; - case 0x604: + case 0x204: + chip->wss_base = 0x604; wss_base_bits = 0x03; break; - case 0xe80: + case 0x280: + chip->wss_base = 0xe80; wss_base_bits = 0x01; break; - case 0xf40: + case 0x340: + chip->wss_base = 0xf40; wss_base_bits = 0x02; break; default: @@ -1122,75 +1176,92 @@ __skip_mpu: return 0; } +static int __devinit snd_miro_opti_check(struct snd_miro *chip) +{ + unsigned char value; + + chip->res_mc_base = request_region(chip->mc_base, chip->mc_base_size, + "OPTi9xx MC"); + if (chip->res_mc_base == NULL) + return -ENOMEM; + + value = snd_miro_read(chip, OPTi9XX_MC_REG(1)); + if (value != 0xff && value != inb(chip->mc_base + OPTi9XX_MC_REG(1))) + if (value == snd_miro_read(chip, OPTi9XX_MC_REG(1))) + return 0; + + release_and_free_resource(chip->res_mc_base); + chip->res_mc_base = NULL; + + return -ENODEV; +} + static int __devinit snd_card_miro_detect(struct snd_card *card, struct snd_miro *chip) { int i, err; - unsigned char value; for (i = OPTi9XX_HW_82C929; i <= OPTi9XX_HW_82C924; i++) { if ((err = snd_miro_init(chip, i)) < 0) return err; - if ((chip->res_mc_base = request_region(chip->mc_base, chip->mc_base_size, "OPTi9xx MC")) == NULL) - continue; - - value = snd_miro_read(chip, OPTi9XX_MC_REG(1)); - if ((value != 0xff) && (value != inb(chip->mc_base + 1))) - if (value == snd_miro_read(chip, OPTi9XX_MC_REG(1))) - return 1; - - release_and_free_resource(chip->res_mc_base); - chip->res_mc_base = NULL; - + err = snd_miro_opti_check(chip); + if (err == 0) + return 1; } return -ENODEV; } static int __devinit snd_card_miro_aci_detect(struct snd_card *card, - struct snd_miro * miro) + struct snd_miro *miro) { unsigned char regval; int i; + struct snd_miro_aci *aci = &aci_device; + + miro->aci = aci; - mutex_init(&miro->aci_mutex); + mutex_init(&aci->aci_mutex); /* get ACI port from OPTi9xx MC 4 */ - miro->mc_base = 0xf8c; regval=inb(miro->mc_base + 4); - miro->aci_port = (regval & 0x10) ? 0x344: 0x354; + aci->aci_port = (regval & 0x10) ? 0x344 : 0x354; - if ((miro->res_aci_port = request_region(miro->aci_port, 3, "miro aci")) == NULL) { + miro->res_aci_port = request_region(aci->aci_port, 3, "miro aci"); + if (miro->res_aci_port == NULL) { snd_printk(KERN_ERR "aci i/o area 0x%lx-0x%lx already used.\n", - miro->aci_port, miro->aci_port+2); + aci->aci_port, aci->aci_port+2); return -ENOMEM; } /* force ACI into a known state */ for (i = 0; i < 3; i++) - if (aci_cmd(miro, ACI_ERROR_OP, -1, -1) < 0) { + if (snd_aci_cmd(aci, ACI_ERROR_OP, -1, -1) < 0) { snd_printk(KERN_ERR "can't force aci into known state.\n"); return -ENXIO; } - if ((miro->aci_vendor=aci_cmd(miro, ACI_READ_IDCODE, -1, -1)) < 0 || - (miro->aci_product=aci_cmd(miro, ACI_READ_IDCODE, -1, -1)) < 0) { - snd_printk(KERN_ERR "can't read aci id on 0x%lx.\n", miro->aci_port); + aci->aci_vendor = snd_aci_cmd(aci, ACI_READ_IDCODE, -1, -1); + aci->aci_product = snd_aci_cmd(aci, ACI_READ_IDCODE, -1, -1); + if (aci->aci_vendor < 0 || aci->aci_product < 0) { + snd_printk(KERN_ERR "can't read aci id on 0x%lx.\n", + aci->aci_port); return -ENXIO; } - if ((miro->aci_version=aci_cmd(miro, ACI_READ_VERSION, -1, -1)) < 0) { + aci->aci_version = snd_aci_cmd(aci, ACI_READ_VERSION, -1, -1); + if (aci->aci_version < 0) { snd_printk(KERN_ERR "can't read aci version on 0x%lx.\n", - miro->aci_port); + aci->aci_port); return -ENXIO; } - if (aci_cmd(miro, ACI_INIT, -1, -1) < 0 || - aci_cmd(miro, ACI_ERROR_OP, ACI_ERROR_OP, ACI_ERROR_OP) < 0 || - aci_cmd(miro, ACI_ERROR_OP, ACI_ERROR_OP, ACI_ERROR_OP) < 0) { + if (snd_aci_cmd(aci, ACI_INIT, -1, -1) < 0 || + snd_aci_cmd(aci, ACI_ERROR_OP, ACI_ERROR_OP, ACI_ERROR_OP) < 0 || + snd_aci_cmd(aci, ACI_ERROR_OP, ACI_ERROR_OP, ACI_ERROR_OP) < 0) { snd_printk(KERN_ERR "can't initialize aci.\n"); return -ENXIO; } @@ -1201,157 +1272,80 @@ static int __devinit snd_card_miro_aci_detect(struct snd_card *card, static void snd_card_miro_free(struct snd_card *card) { struct snd_miro *miro = card->private_data; - + release_and_free_resource(miro->res_aci_port); + if (miro->aci) + miro->aci->aci_port = 0; release_and_free_resource(miro->res_mc_base); } -static int __devinit snd_miro_match(struct device *devptr, unsigned int n) -{ - return 1; -} - -static int __devinit snd_miro_probe(struct device *devptr, unsigned int n) +static int __devinit snd_miro_probe(struct snd_card *card) { - static long possible_ports[] = {0x530, 0xe80, 0xf40, 0x604, -1}; - static long possible_mpu_ports[] = {0x330, 0x300, 0x310, 0x320, -1}; - static int possible_irqs[] = {11, 9, 10, 7, -1}; - static int possible_mpu_irqs[] = {10, 5, 9, 7, -1}; - static int possible_dma1s[] = {3, 1, 0, -1}; - static int possible_dma2s[][2] = {{1,-1}, {0,-1}, {-1,-1}, {0,-1}}; - int error; - struct snd_miro *miro; + struct snd_miro *miro = card->private_data; struct snd_wss *codec; struct snd_timer *timer; - struct snd_card *card; struct snd_pcm *pcm; struct snd_rawmidi *rmidi; - error = snd_card_create(index, id, THIS_MODULE, - sizeof(struct snd_miro), &card); - if (error < 0) - return error; - - card->private_free = snd_card_miro_free; - miro = card->private_data; - miro->card = card; - - if ((error = snd_card_miro_aci_detect(card, miro)) < 0) { - snd_card_free(card); - snd_printk(KERN_ERR "unable to detect aci chip\n"); - return -ENODEV; + if (!miro->res_mc_base) { + miro->res_mc_base = request_region(miro->mc_base, + miro->mc_base_size, + "miro (OPTi9xx MC)"); + if (miro->res_mc_base == NULL) { + snd_printk(KERN_ERR "request for OPTI9xx MC failed\n"); + return -ENOMEM; + } } - /* init proc interface */ - snd_miro_proc_init(miro); - - if ((error = snd_card_miro_detect(card, miro)) < 0) { + error = snd_card_miro_aci_detect(card, miro); + if (error < 0) { snd_card_free(card); - snd_printk(KERN_ERR "unable to detect OPTi9xx chip\n"); + snd_printk(KERN_ERR "unable to detect aci chip\n"); return -ENODEV; } - if (! miro->res_mc_base && - (miro->res_mc_base = request_region(miro->mc_base, miro->mc_base_size, - "miro (OPTi9xx MC)")) == NULL) { - snd_card_free(card); - snd_printk(KERN_ERR "request for OPTI9xx MC failed\n"); - return -ENOMEM; - } - miro->wss_base = port; - miro->fm_port = fm_port; miro->mpu_port = mpu_port; miro->irq = irq; miro->mpu_irq = mpu_irq; miro->dma1 = dma1; miro->dma2 = dma2; - if (miro->wss_base == SNDRV_AUTO_PORT) { - if ((miro->wss_base = snd_legacy_find_free_ioport(possible_ports, 4)) < 0) { - snd_card_free(card); - snd_printk(KERN_ERR "unable to find a free WSS port\n"); - return -EBUSY; - } - } - - if (miro->mpu_port == SNDRV_AUTO_PORT) { - if ((miro->mpu_port = snd_legacy_find_free_ioport(possible_mpu_ports, 2)) < 0) { - snd_card_free(card); - snd_printk(KERN_ERR "unable to find a free MPU401 port\n"); - return -EBUSY; - } - } - if (miro->irq == SNDRV_AUTO_IRQ) { - if ((miro->irq = snd_legacy_find_free_irq(possible_irqs)) < 0) { - snd_card_free(card); - snd_printk(KERN_ERR "unable to find a free IRQ\n"); - return -EBUSY; - } - } - if (miro->mpu_irq == SNDRV_AUTO_IRQ) { - if ((miro->mpu_irq = snd_legacy_find_free_irq(possible_mpu_irqs)) < 0) { - snd_card_free(card); - snd_printk(KERN_ERR "unable to find a free MPU401 IRQ\n"); - return -EBUSY; - } - } - if (miro->dma1 == SNDRV_AUTO_DMA) { - if ((miro->dma1 = snd_legacy_find_free_dma(possible_dma1s)) < 0) { - snd_card_free(card); - snd_printk(KERN_ERR "unable to find a free DMA1\n"); - return -EBUSY; - } - } - if (miro->dma2 == SNDRV_AUTO_DMA) { - if ((miro->dma2 = snd_legacy_find_free_dma(possible_dma2s[miro->dma1 % 4])) < 0) { - snd_card_free(card); - snd_printk(KERN_ERR "unable to find a free DMA2\n"); - return -EBUSY; - } - } + /* init proc interface */ + snd_miro_proc_init(card, miro); error = snd_miro_configure(miro); - if (error) { - snd_card_free(card); + if (error) return error; - } error = snd_wss_create(card, miro->wss_base + 4, -1, - miro->irq, miro->dma1, miro->dma2, - WSS_HW_AD1845, 0, &codec); - if (error < 0) { - snd_card_free(card); + miro->irq, miro->dma1, miro->dma2, + WSS_HW_DETECT, 0, &codec); + if (error < 0) return error; - } error = snd_wss_pcm(codec, 0, &pcm); - if (error < 0) { - snd_card_free(card); + if (error < 0) return error; - } + error = snd_wss_mixer(codec); - if (error < 0) { - snd_card_free(card); + if (error < 0) return error; - } + error = snd_wss_timer(codec, 0, &timer); - if (error < 0) { - snd_card_free(card); + if (error < 0) return error; - } miro->pcm = pcm; - if ((error = snd_miro_mixer(miro)) < 0) { - snd_card_free(card); + error = snd_miro_mixer(card, miro); + if (error < 0) return error; - } - if (miro->aci_vendor == 'm') { + if (miro->aci->aci_vendor == 'm') { /* It looks like a miro sound card. */ - switch (miro->aci_product) { + switch (miro->aci->aci_product) { case 'A': sprintf(card->shortname, "miroSOUND PCM1 pro / PCM12"); @@ -1380,30 +1374,131 @@ static int __devinit snd_miro_probe(struct device *devptr, unsigned int n) card->shortname, miro->name, pcm->name, miro->wss_base + 4, miro->irq, miro->dma1, miro->dma2); - if (miro->mpu_port <= 0 || miro->mpu_port == SNDRV_AUTO_PORT) + if (mpu_port <= 0 || mpu_port == SNDRV_AUTO_PORT) rmidi = NULL; - else - if ((error = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, - miro->mpu_port, 0, miro->mpu_irq, IRQF_DISABLED, - &rmidi))) - snd_printk(KERN_WARNING "no MPU-401 device at 0x%lx?\n", miro->mpu_port); + else { + error = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, + mpu_port, 0, miro->mpu_irq, IRQF_DISABLED, + &rmidi); + if (error < 0) + snd_printk(KERN_WARNING "no MPU-401 device at 0x%lx?\n", + mpu_port); + } - if (miro->fm_port > 0 && miro->fm_port != SNDRV_AUTO_PORT) { + if (fm_port > 0 && fm_port != SNDRV_AUTO_PORT) { struct snd_opl3 *opl3 = NULL; struct snd_opl4 *opl4; - if (snd_opl4_create(card, miro->fm_port, miro->fm_port - 8, + + if (snd_opl4_create(card, fm_port, fm_port - 8, 2, &opl3, &opl4) < 0) - snd_printk(KERN_WARNING "no OPL4 device at 0x%lx\n", miro->fm_port); + snd_printk(KERN_WARNING "no OPL4 device at 0x%lx\n", + fm_port); } - if ((error = snd_set_aci_init_values(miro)) < 0) { - snd_card_free(card); + error = snd_set_aci_init_values(miro); + if (error < 0) return error; + + return snd_card_register(card); +} + +static int __devinit snd_miro_isa_match(struct device *devptr, unsigned int n) +{ +#ifdef CONFIG_PNP + if (snd_miro_pnp_is_probed) + return 0; + if (isapnp) + return 0; +#endif + return 1; +} + +static int __devinit snd_miro_isa_probe(struct device *devptr, unsigned int n) +{ + static long possible_ports[] = {0x530, 0xe80, 0xf40, 0x604, -1}; + static long possible_mpu_ports[] = {0x330, 0x300, 0x310, 0x320, -1}; + static int possible_irqs[] = {11, 9, 10, 7, -1}; + static int possible_mpu_irqs[] = {10, 5, 9, 7, -1}; + static int possible_dma1s[] = {3, 1, 0, -1}; + static int possible_dma2s[][2] = { {1, -1}, {0, -1}, {-1, -1}, + {0, -1} }; + + int error; + struct snd_miro *miro; + struct snd_card *card; + + error = snd_card_create(index, id, THIS_MODULE, + sizeof(struct snd_miro), &card); + if (error < 0) + return error; + + card->private_free = snd_card_miro_free; + miro = card->private_data; + + error = snd_card_miro_detect(card, miro); + if (error < 0) { + snd_card_free(card); + snd_printk(KERN_ERR "unable to detect OPTi9xx chip\n"); + return -ENODEV; + } + + if (port == SNDRV_AUTO_PORT) { + port = snd_legacy_find_free_ioport(possible_ports, 4); + if (port < 0) { + snd_card_free(card); + snd_printk(KERN_ERR "unable to find a free WSS port\n"); + return -EBUSY; + } + } + + if (mpu_port == SNDRV_AUTO_PORT) { + mpu_port = snd_legacy_find_free_ioport(possible_mpu_ports, 2); + if (mpu_port < 0) { + snd_card_free(card); + snd_printk(KERN_ERR + "unable to find a free MPU401 port\n"); + return -EBUSY; + } + } + + if (irq == SNDRV_AUTO_IRQ) { + irq = snd_legacy_find_free_irq(possible_irqs); + if (irq < 0) { + snd_card_free(card); + snd_printk(KERN_ERR "unable to find a free IRQ\n"); + return -EBUSY; + } + } + if (mpu_irq == SNDRV_AUTO_IRQ) { + mpu_irq = snd_legacy_find_free_irq(possible_mpu_irqs); + if (mpu_irq < 0) { + snd_card_free(card); + snd_printk(KERN_ERR + "unable to find a free MPU401 IRQ\n"); + return -EBUSY; + } + } + if (dma1 == SNDRV_AUTO_DMA) { + dma1 = snd_legacy_find_free_dma(possible_dma1s); + if (dma1 < 0) { + snd_card_free(card); + snd_printk(KERN_ERR "unable to find a free DMA1\n"); + return -EBUSY; + } + } + if (dma2 == SNDRV_AUTO_DMA) { + dma2 = snd_legacy_find_free_dma(possible_dma2s[dma1 % 4]); + if (dma2 < 0) { + snd_card_free(card); + snd_printk(KERN_ERR "unable to find a free DMA2\n"); + return -EBUSY; + } } snd_card_set_dev(card, devptr); - if ((error = snd_card_register(card))) { + error = snd_miro_probe(card); + if (error < 0) { snd_card_free(card); return error; } @@ -1412,7 +1507,8 @@ static int __devinit snd_miro_probe(struct device *devptr, unsigned int n) return 0; } -static int __devexit snd_miro_remove(struct device *devptr, unsigned int dev) +static int __devexit snd_miro_isa_remove(struct device *devptr, + unsigned int dev) { snd_card_free(dev_get_drvdata(devptr)); dev_set_drvdata(devptr, NULL); @@ -1422,23 +1518,164 @@ static int __devexit snd_miro_remove(struct device *devptr, unsigned int dev) #define DEV_NAME "miro" static struct isa_driver snd_miro_driver = { - .match = snd_miro_match, - .probe = snd_miro_probe, - .remove = __devexit_p(snd_miro_remove), + .match = snd_miro_isa_match, + .probe = snd_miro_isa_probe, + .remove = __devexit_p(snd_miro_isa_remove), /* FIXME: suspend/resume */ .driver = { .name = DEV_NAME }, }; +#ifdef CONFIG_PNP + +static int __devinit snd_card_miro_pnp(struct snd_miro *chip, + struct pnp_card_link *card, + const struct pnp_card_device_id *pid) +{ + struct pnp_dev *pdev; + int err; + struct pnp_dev *devmpu; + struct pnp_dev *devmc; + + pdev = pnp_request_card_device(card, pid->devs[0].id, NULL); + if (pdev == NULL) + return -EBUSY; + + devmpu = pnp_request_card_device(card, pid->devs[1].id, NULL); + if (devmpu == NULL) + return -EBUSY; + + devmc = pnp_request_card_device(card, pid->devs[2].id, NULL); + if (devmc == NULL) + return -EBUSY; + + err = pnp_activate_dev(pdev); + if (err < 0) { + snd_printk(KERN_ERR "AUDIO pnp configure failure: %d\n", err); + return err; + } + + err = pnp_activate_dev(devmc); + if (err < 0) { + snd_printk(KERN_ERR "OPL syntg pnp configure failure: %d\n", + err); + return err; + } + + port = pnp_port_start(pdev, 1); + fm_port = pnp_port_start(pdev, 2) + 8; + + /* + * The MC(0) is never accessed and the miroSOUND PCM20 card does not + * include it in the PnP resource range. OPTI93x include it. + */ + chip->mc_base = pnp_port_start(devmc, 0) - 1; + chip->mc_base_size = pnp_port_len(devmc, 0) + 1; + + irq = pnp_irq(pdev, 0); + dma1 = pnp_dma(pdev, 0); + dma2 = pnp_dma(pdev, 1); + + if (mpu_port > 0) { + err = pnp_activate_dev(devmpu); + if (err < 0) { + snd_printk(KERN_ERR "MPU401 pnp configure failure\n"); + mpu_port = -1; + return err; + } + mpu_port = pnp_port_start(devmpu, 0); + mpu_irq = pnp_irq(devmpu, 0); + } + return 0; +} + +static int __devinit snd_miro_pnp_probe(struct pnp_card_link *pcard, + const struct pnp_card_device_id *pid) +{ + struct snd_card *card; + int err; + struct snd_miro *miro; + + if (snd_miro_pnp_is_probed) + return -EBUSY; + if (!isapnp) + return -ENODEV; + err = snd_card_create(index, id, THIS_MODULE, + sizeof(struct snd_miro), &card); + if (err < 0) + return err; + + card->private_free = snd_card_miro_free; + miro = card->private_data; + + err = snd_card_miro_pnp(miro, pcard, pid); + if (err) { + snd_card_free(card); + return err; + } + + /* only miroSOUND PCM20 and PCM12 == OPTi924 */ + err = snd_miro_init(miro, OPTi9XX_HW_82C924); + if (err) { + snd_card_free(card); + return err; + } + + err = snd_miro_opti_check(miro); + if (err) { + snd_printk(KERN_ERR "OPTI chip not found\n"); + snd_card_free(card); + return err; + } + + snd_card_set_dev(card, &pcard->card->dev); + err = snd_miro_probe(card); + if (err < 0) { + snd_card_free(card); + return err; + } + pnp_set_card_drvdata(pcard, card); + snd_miro_pnp_is_probed = 1; + return 0; +} + +static void __devexit snd_miro_pnp_remove(struct pnp_card_link * pcard) +{ + snd_card_free(pnp_get_card_drvdata(pcard)); + pnp_set_card_drvdata(pcard, NULL); + snd_miro_pnp_is_probed = 0; +} + +static struct pnp_card_driver miro_pnpc_driver = { + .flags = PNP_DRIVER_RES_DISABLE, + .name = "miro", + .id_table = snd_miro_pnpids, + .probe = snd_miro_pnp_probe, + .remove = __devexit_p(snd_miro_pnp_remove), +}; +#endif + static int __init alsa_card_miro_init(void) { +#ifdef CONFIG_PNP + pnp_register_card_driver(&miro_pnpc_driver); + if (snd_miro_pnp_is_probed) + return 0; + pnp_unregister_card_driver(&miro_pnpc_driver); +#endif return isa_register_driver(&snd_miro_driver, 1); } static void __exit alsa_card_miro_exit(void) { - isa_unregister_driver(&snd_miro_driver); + if (!snd_miro_pnp_is_probed) { + isa_unregister_driver(&snd_miro_driver); + return; + } +#ifdef CONFIG_PNP + pnp_unregister_card_driver(&miro_pnpc_driver); +#endif } module_init(alsa_card_miro_init) diff --git a/sound/isa/opti9xx/miro.h b/sound/isa/opti9xx/miro.h deleted file mode 100644 index 6e1385b8e07e..000000000000 --- a/sound/isa/opti9xx/miro.h +++ /dev/null @@ -1,73 +0,0 @@ -#ifndef _MIRO_H_ -#define _MIRO_H_ - -#define ACI_REG_COMMAND 0 /* write register offset */ -#define ACI_REG_STATUS 1 /* read register offset */ -#define ACI_REG_BUSY 2 /* busy register offset */ -#define ACI_REG_RDS 2 /* PCM20: RDS register offset */ -#define ACI_MINTIME 500 /* ACI time out limit */ - -#define ACI_SET_MUTE 0x0d -#define ACI_SET_POWERAMP 0x0f -#define ACI_SET_TUNERMUTE 0xa3 -#define ACI_SET_TUNERMONO 0xa4 -#define ACI_SET_IDE 0xd0 -#define ACI_SET_WSS 0xd1 -#define ACI_SET_SOLOMODE 0xd2 -#define ACI_SET_PREAMP 0x03 -#define ACI_GET_PREAMP 0x21 -#define ACI_WRITE_TUNE 0xa7 -#define ACI_READ_TUNERSTEREO 0xa8 -#define ACI_READ_TUNERSTATION 0xa9 -#define ACI_READ_VERSION 0xf1 -#define ACI_READ_IDCODE 0xf2 -#define ACI_INIT 0xff -#define ACI_STATUS 0xf0 -#define ACI_S_GENERAL 0x00 -#define ACI_ERROR_OP 0xdf - -/* ACI Mixer */ - -/* These are the values for the right channel GET registers. - Add an offset of 0x01 for the left channel register. - (left=right+0x01) */ - -#define ACI_GET_MASTER 0x03 -#define ACI_GET_MIC 0x05 -#define ACI_GET_LINE 0x07 -#define ACI_GET_CD 0x09 -#define ACI_GET_SYNTH 0x0b -#define ACI_GET_PCM 0x0d -#define ACI_GET_LINE1 0x10 /* Radio on PCM20 */ -#define ACI_GET_LINE2 0x12 - -#define ACI_GET_EQ1 0x22 /* from Bass ... */ -#define ACI_GET_EQ2 0x24 -#define ACI_GET_EQ3 0x26 -#define ACI_GET_EQ4 0x28 -#define ACI_GET_EQ5 0x2a -#define ACI_GET_EQ6 0x2c -#define ACI_GET_EQ7 0x2e /* ... to Treble */ - -/* And these are the values for the right channel SET registers. - For left channel access you have to add an offset of 0x08. - MASTER is an exception, which needs an offset of 0x01 */ - -#define ACI_SET_MASTER 0x00 -#define ACI_SET_MIC 0x30 -#define ACI_SET_LINE 0x31 -#define ACI_SET_CD 0x34 -#define ACI_SET_SYNTH 0x33 -#define ACI_SET_PCM 0x32 -#define ACI_SET_LINE1 0x35 /* Radio on PCM20 */ -#define ACI_SET_LINE2 0x36 - -#define ACI_SET_EQ1 0x40 /* from Bass ... */ -#define ACI_SET_EQ2 0x41 -#define ACI_SET_EQ3 0x42 -#define ACI_SET_EQ4 0x43 -#define ACI_SET_EQ5 0x44 -#define ACI_SET_EQ6 0x45 -#define ACI_SET_EQ7 0x46 /* ... to Treble */ - -#endif /* _MIRO_H_ */ diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c index 5cd555325b9d..d08c38906449 100644 --- a/sound/isa/opti9xx/opti92x-ad1848.c +++ b/sound/isa/opti9xx/opti92x-ad1848.c @@ -141,15 +141,7 @@ struct snd_opti9xx { spinlock_t lock; - long wss_base; int irq; - int dma1; - int dma2; - - long fm_port; - - long mpu_port; - int mpu_irq; #ifdef CONFIG_PNP struct pnp_dev *dev; @@ -216,13 +208,7 @@ static int __devinit snd_opti9xx_init(struct snd_opti9xx *chip, spin_lock_init(&chip->lock); - chip->wss_base = -1; chip->irq = -1; - chip->dma1 = -1; - chip->dma2 = -1; - chip->fm_port = -1; - chip->mpu_port = -1; - chip->mpu_irq = -1; switch (hardware) { #ifndef OPTi93X @@ -348,7 +334,10 @@ static void snd_opti9xx_write(struct snd_opti9xx *chip, unsigned char reg, (snd_opti9xx_read(chip, reg) & ~(mask)) | ((value) & (mask))) -static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip) +static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip, + long wss_base, + int irq, int dma1, int dma2, + long mpu_port, int mpu_irq) { unsigned char wss_base_bits; unsigned char irq_bits; @@ -416,7 +405,7 @@ static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip) return -EINVAL; } - switch (chip->wss_base) { + switch (wss_base) { case 0x530: wss_base_bits = 0x00; break; @@ -430,14 +419,13 @@ static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip) wss_base_bits = 0x02; break; default: - snd_printk(KERN_WARNING "WSS port 0x%lx not valid\n", - chip->wss_base); + snd_printk(KERN_WARNING "WSS port 0x%lx not valid\n", wss_base); goto __skip_base; } snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(1), wss_base_bits << 4, 0x30); __skip_base: - switch (chip->irq) { + switch (irq) { //#ifdef OPTi93X case 5: irq_bits = 0x05; @@ -456,11 +444,11 @@ __skip_base: irq_bits = 0x04; break; default: - snd_printk(KERN_WARNING "WSS irq # %d not valid\n", chip->irq); + snd_printk(KERN_WARNING "WSS irq # %d not valid\n", irq); goto __skip_resources; } - switch (chip->dma1) { + switch (dma1) { case 0: dma_bits = 0x01; break; @@ -471,38 +459,36 @@ __skip_base: dma_bits = 0x03; break; default: - snd_printk(KERN_WARNING "WSS dma1 # %d not valid\n", - chip->dma1); + snd_printk(KERN_WARNING "WSS dma1 # %d not valid\n", dma1); goto __skip_resources; } #if defined(CS4231) || defined(OPTi93X) - if (chip->dma1 == chip->dma2) { + if (dma1 == dma2) { snd_printk(KERN_ERR "don't want to share dmas\n"); return -EBUSY; } - switch (chip->dma2) { + switch (dma2) { case 0: case 1: break; default: - snd_printk(KERN_WARNING "WSS dma2 # %d not valid\n", - chip->dma2); + snd_printk(KERN_WARNING "WSS dma2 # %d not valid\n", dma2); goto __skip_resources; } dma_bits |= 0x04; #endif /* CS4231 || OPTi93X */ #ifndef OPTi93X - outb(irq_bits << 3 | dma_bits, chip->wss_base); + outb(irq_bits << 3 | dma_bits, wss_base); #else /* OPTi93X */ snd_opti9xx_write(chip, OPTi9XX_MC_REG(3), (irq_bits << 3 | dma_bits)); #endif /* OPTi93X */ __skip_resources: if (chip->hardware > OPTi9XX_HW_82C928) { - switch (chip->mpu_port) { + switch (mpu_port) { case 0: case -1: break; @@ -520,12 +506,11 @@ __skip_resources: break; default: snd_printk(KERN_WARNING - "MPU-401 port 0x%lx not valid\n", - chip->mpu_port); + "MPU-401 port 0x%lx not valid\n", mpu_port); goto __skip_mpu; } - switch (chip->mpu_irq) { + switch (mpu_irq) { case 5: mpu_irq_bits = 0x02; break; @@ -540,12 +525,12 @@ __skip_resources: break; default: snd_printk(KERN_WARNING "MPU-401 irq # %d not valid\n", - chip->mpu_irq); + mpu_irq); goto __skip_mpu; } snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(6), - (chip->mpu_port <= 0) ? 0x00 : + (mpu_port <= 0) ? 0x00 : 0x80 | mpu_port_bits << 5 | mpu_irq_bits << 3, 0xf8); } @@ -701,6 +686,7 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card) { static long possible_ports[] = {0x530, 0xe80, 0xf40, 0x604, -1}; int error; + int xdma2; struct snd_opti9xx *chip = card->private_data; struct snd_wss *codec; #ifdef CS4231 @@ -715,31 +701,25 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card) "OPTi9xx MC")) == NULL) return -ENOMEM; - chip->wss_base = port; - chip->fm_port = fm_port; - chip->mpu_port = mpu_port; - chip->irq = irq; - chip->mpu_irq = mpu_irq; - chip->dma1 = dma1; #if defined(CS4231) || defined(OPTi93X) - chip->dma2 = dma2; + xdma2 = dma2; #else - chip->dma2 = -1; + xdma2 = -1; #endif - if (chip->wss_base == SNDRV_AUTO_PORT) { - chip->wss_base = snd_legacy_find_free_ioport(possible_ports, 4); - if (chip->wss_base < 0) { + if (port == SNDRV_AUTO_PORT) { + port = snd_legacy_find_free_ioport(possible_ports, 4); + if (port < 0) { snd_printk(KERN_ERR "unable to find a free WSS port\n"); return -EBUSY; } } - error = snd_opti9xx_configure(chip); + error = snd_opti9xx_configure(chip, port, irq, dma1, xdma2, + mpu_port, mpu_irq); if (error) return error; - error = snd_wss_create(card, chip->wss_base + 4, -1, - chip->irq, chip->dma1, chip->dma2, + error = snd_wss_create(card, port + 4, -1, irq, dma1, xdma2, #ifdef OPTi93X WSS_HW_OPTI93X, WSS_HWSHARE_IRQ, #else @@ -763,35 +743,35 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card) return error; #endif #ifdef OPTi93X - error = request_irq(chip->irq, snd_opti93x_interrupt, + error = request_irq(irq, snd_opti93x_interrupt, IRQF_DISABLED, DEV_NAME" - WSS", codec); if (error < 0) { snd_printk(KERN_ERR "opti9xx: can't grab IRQ %d\n", chip->irq); return error; } #endif + chip->irq = irq; strcpy(card->driver, chip->name); sprintf(card->shortname, "OPTi %s", card->driver); #if defined(CS4231) || defined(OPTi93X) sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d&%d", - card->shortname, pcm->name, chip->wss_base + 4, - chip->irq, chip->dma1, chip->dma2); + card->shortname, pcm->name, port + 4, irq, dma1, xdma2); #else sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d", - card->shortname, pcm->name, chip->wss_base + 4, - chip->irq, chip->dma1); + card->shortname, pcm->name, port + 4, irq, dma1); #endif /* CS4231 || OPTi93X */ - if (chip->mpu_port <= 0 || chip->mpu_port == SNDRV_AUTO_PORT) + if (mpu_port <= 0 || mpu_port == SNDRV_AUTO_PORT) rmidi = NULL; - else - if ((error = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, - chip->mpu_port, 0, chip->mpu_irq, IRQF_DISABLED, - &rmidi))) + else { + error = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, + mpu_port, 0, mpu_irq, IRQF_DISABLED, &rmidi); + if (error) snd_printk(KERN_WARNING "no MPU-401 device at 0x%lx?\n", - chip->mpu_port); + mpu_port); + } - if (chip->fm_port > 0 && chip->fm_port != SNDRV_AUTO_PORT) { + if (fm_port > 0 && fm_port != SNDRV_AUTO_PORT) { struct snd_opl3 *opl3 = NULL; #ifndef OPTi93X if (chip->hardware == OPTi9XX_HW_82C928 || @@ -801,9 +781,7 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card) /* assume we have an OPL4 */ snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(2), 0x20, 0x20); - if (snd_opl4_create(card, - chip->fm_port, - chip->fm_port - 8, + if (snd_opl4_create(card, fm_port, fm_port - 8, 2, &opl3, &opl4) < 0) { /* no luck, use OPL3 instead */ snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(2), @@ -811,12 +789,10 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card) } } #endif /* !OPTi93X */ - if (!opl3 && snd_opl3_create(card, - chip->fm_port, - chip->fm_port + 2, + if (!opl3 && snd_opl3_create(card, fm_port, fm_port + 2, OPL3_HW_AUTO, 0, &opl3) < 0) { snd_printk(KERN_WARNING "no OPL device at 0x%lx-0x%lx\n", - chip->fm_port, chip->fm_port + 4 - 1); + fm_port, fm_port + 4 - 1); } if (opl3) { error = snd_opl3_hwdep_new(opl3, 0, 1, &synth); diff --git a/sound/isa/sb/sb_mixer.c b/sound/isa/sb/sb_mixer.c index 475220bbcc96..318ff0c823e7 100644 --- a/sound/isa/sb/sb_mixer.c +++ b/sound/isa/sb/sb_mixer.c @@ -631,7 +631,7 @@ static struct sbmix_elem snd_sb16_ctl_mic_play_switch = static struct sbmix_elem snd_sb16_ctl_mic_play_vol = SB_SINGLE("Mic Playback Volume", SB_DSP4_MIC_DEV, 3, 31); static struct sbmix_elem snd_sb16_ctl_pc_speaker_vol = - SB_SINGLE("PC Speaker Volume", SB_DSP4_SPEAKER_DEV, 6, 3); + SB_SINGLE("Beep Volume", SB_DSP4_SPEAKER_DEV, 6, 3); static struct sbmix_elem snd_sb16_ctl_capture_vol = SB_DOUBLE("Capture Volume", SB_DSP4_IGAIN_DEV, (SB_DSP4_IGAIN_DEV + 1), 6, 6, 3); static struct sbmix_elem snd_sb16_ctl_play_vol = @@ -689,7 +689,7 @@ static struct sbmix_elem snd_dt019x_ctl_cd_play_vol = static struct sbmix_elem snd_dt019x_ctl_mic_play_vol = SB_SINGLE("Mic Playback Volume", SB_DT019X_MIC_DEV, 4, 7); static struct sbmix_elem snd_dt019x_ctl_pc_speaker_vol = - SB_SINGLE("PC Speaker Volume", SB_DT019X_SPKR_DEV, 0, 7); + SB_SINGLE("Beep Volume", SB_DT019X_SPKR_DEV, 0, 7); static struct sbmix_elem snd_dt019x_ctl_line_play_vol = SB_DOUBLE("Line Playback Volume", SB_DT019X_LINE_DEV, SB_DT019X_LINE_DEV, 4,0, 15); static struct sbmix_elem snd_dt019x_ctl_pcm_play_switch = diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c index 66187122377c..e2d5d2d3ed96 100644 --- a/sound/isa/sscape.c +++ b/sound/isa/sscape.c @@ -1,5 +1,5 @@ /* - * Low-level ALSA driver for the ENSONIQ SoundScape PnP + * Low-level ALSA driver for the ENSONIQ SoundScape * Copyright (c) by Chris Rankin * * This driver was written in part using information obtained from @@ -25,31 +25,36 @@ #include <linux/err.h> #include <linux/isa.h> #include <linux/delay.h> +#include <linux/firmware.h> #include <linux/pnp.h> #include <linux/spinlock.h> #include <linux/moduleparam.h> #include <asm/dma.h> #include <sound/core.h> -#include <sound/hwdep.h> #include <sound/wss.h> #include <sound/mpu401.h> #include <sound/initval.h> -#include <sound/sscape_ioctl.h> - MODULE_AUTHOR("Chris Rankin"); -MODULE_DESCRIPTION("ENSONIQ SoundScape PnP driver"); +MODULE_DESCRIPTION("ENSONIQ SoundScape driver"); 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 = 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_FIRMWARE("sndscape.co0"); +MODULE_FIRMWARE("sndscape.co1"); +MODULE_FIRMWARE("sndscape.co2"); +MODULE_FIRMWARE("sndscape.co3"); +MODULE_FIRMWARE("sndscape.co4"); +MODULE_FIRMWARE("scope.cod"); + +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; +static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; +static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; +static long wss_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; +static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; +static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; +static int dma[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; +static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; +static bool joystick[SNDRV_CARDS]; module_param_array(index, int, NULL, 0444); MODULE_PARM_DESC(index, "Index number for SoundScape soundcard"); @@ -75,6 +80,9 @@ MODULE_PARM_DESC(dma, "DMA # for SoundScape driver."); module_param_array(dma2, int, NULL, 0444); MODULE_PARM_DESC(dma2, "DMA2 # for SoundScape driver."); +module_param_array(joystick, bool, NULL, 0444); +MODULE_PARM_DESC(joystick, "Enable gameport."); + #ifdef CONFIG_PNP static int isa_registered; static int pnp_registered; @@ -101,14 +109,14 @@ MODULE_DEVICE_TABLE(pnp_card, sscape_pnpids); #define RX_READY 0x01 #define TX_READY 0x02 -#define CMD_ACK 0x80 -#define CMD_SET_MIDI_VOL 0x84 -#define CMD_GET_MIDI_VOL 0x85 -#define CMD_XXX_MIDI_VOL 0x86 -#define CMD_SET_EXTMIDI 0x8a -#define CMD_GET_EXTMIDI 0x8b -#define CMD_SET_MT32 0x8c -#define CMD_GET_MT32 0x8d +#define CMD_ACK 0x80 +#define CMD_SET_MIDI_VOL 0x84 +#define CMD_GET_MIDI_VOL 0x85 +#define CMD_XXX_MIDI_VOL 0x86 +#define CMD_SET_EXTMIDI 0x8a +#define CMD_GET_EXTMIDI 0x8b +#define CMD_SET_MT32 0x8c +#define CMD_GET_MT32 0x8d enum GA_REG { GA_INTSTAT_REG = 0, @@ -127,7 +135,8 @@ enum GA_REG { enum card_type { - SSCAPE, + MEDIA_FX, /* Sequoia S-1000 */ + SSCAPE, /* Sequoia S-2000 */ SSCAPE_PNP, SSCAPE_VIVO, }; @@ -140,16 +149,7 @@ struct soundscape { struct resource *io_res; struct resource *wss_res; struct snd_wss *chip; - struct snd_mpu401 *mpu; - struct snd_hwdep *hw; - /* - * The MIDI device won't work until we've loaded - * its firmware via a hardware-dependent device IOCTL - */ - spinlock_t fwlock; - int hw_in_use; - unsigned long midi_usage; unsigned char midi_vol; }; @@ -161,28 +161,21 @@ static inline struct soundscape *get_card_soundscape(struct snd_card *c) return (struct soundscape *) (c->private_data); } -static inline struct soundscape *get_mpu401_soundscape(struct snd_mpu401 * mpu) -{ - return (struct soundscape *) (mpu->private_data); -} - -static inline struct soundscape *get_hwdep_soundscape(struct snd_hwdep * hw) -{ - return (struct soundscape *) (hw->private_data); -} - - /* * Allocates some kernel memory that we can use for DMA. * I think this means that the memory has to map to * contiguous pages of physical memory. */ -static struct snd_dma_buffer *get_dmabuf(struct snd_dma_buffer *buf, unsigned long size) +static struct snd_dma_buffer *get_dmabuf(struct snd_dma_buffer *buf, + unsigned long size) { if (buf) { - if (snd_dma_alloc_pages_fallback(SNDRV_DMA_TYPE_DEV, snd_dma_isa_data(), + if (snd_dma_alloc_pages_fallback(SNDRV_DMA_TYPE_DEV, + snd_dma_isa_data(), size, buf) < 0) { - snd_printk(KERN_ERR "sscape: Failed to allocate %lu bytes for DMA\n", size); + snd_printk(KERN_ERR "sscape: Failed to allocate " + "%lu bytes for DMA\n", + size); return NULL; } } @@ -199,13 +192,13 @@ static void free_dmabuf(struct snd_dma_buffer *buf) snd_dma_free_pages(buf); } - /* * This function writes to the SoundScape's control registers, * but doesn't do any locking. It's up to the caller to do that. * This is why this function is "unsafe" ... */ -static inline void sscape_write_unsafe(unsigned io_base, enum GA_REG reg, unsigned char val) +static inline void sscape_write_unsafe(unsigned io_base, enum GA_REG reg, + unsigned char val) { outb(reg, ODIE_ADDR_IO(io_base)); outb(val, ODIE_DATA_IO(io_base)); @@ -215,7 +208,8 @@ static inline void sscape_write_unsafe(unsigned io_base, enum GA_REG reg, unsign * Write to the SoundScape's control registers, and do the * necessary locking ... */ -static void sscape_write(struct soundscape *s, enum GA_REG reg, unsigned char val) +static void sscape_write(struct soundscape *s, enum GA_REG reg, + unsigned char val) { unsigned long flags; @@ -228,7 +222,8 @@ static void sscape_write(struct soundscape *s, enum GA_REG reg, unsigned char va * Read from the SoundScape's control registers, but leave any * locking to the caller. This is why the function is "unsafe" ... */ -static inline unsigned char sscape_read_unsafe(unsigned io_base, enum GA_REG reg) +static inline unsigned char sscape_read_unsafe(unsigned io_base, + enum GA_REG reg) { outb(reg, ODIE_ADDR_IO(io_base)); return inb(ODIE_DATA_IO(io_base)); @@ -257,9 +252,8 @@ static inline void set_midi_mode_unsafe(unsigned io_base) static inline int host_read_unsafe(unsigned io_base) { int data = -1; - if ((inb(HOST_CTRL_IO(io_base)) & RX_READY) != 0) { + if ((inb(HOST_CTRL_IO(io_base)) & RX_READY) != 0) data = inb(HOST_DATA_IO(io_base)); - } return data; } @@ -301,7 +295,7 @@ static inline int host_write_unsafe(unsigned io_base, unsigned char data) * Also leaves all locking-issues to the caller ... */ static int host_write_ctrl_unsafe(unsigned io_base, unsigned char data, - unsigned timeout) + unsigned timeout) { int err; @@ -320,7 +314,7 @@ static int host_write_ctrl_unsafe(unsigned io_base, unsigned char data, * * NOTE: This check is based upon observation, not documentation. */ -static inline int verify_mpu401(const struct snd_mpu401 * mpu) +static inline int verify_mpu401(const struct snd_mpu401 *mpu) { return ((inb(MPU401C(mpu)) & 0xc0) == 0x80); } @@ -328,7 +322,7 @@ static inline int verify_mpu401(const struct snd_mpu401 * mpu) /* * This is apparently the standard way to initailise an MPU-401 */ -static inline void initialise_mpu401(const struct snd_mpu401 * mpu) +static inline void initialise_mpu401(const struct snd_mpu401 *mpu) { outb(0, MPU401D(mpu)); } @@ -338,9 +332,10 @@ static inline void initialise_mpu401(const struct snd_mpu401 * mpu) * The AD1845 detection fails if we *don't* do this, so I * think that this is a good idea ... */ -static inline void activate_ad1845_unsafe(unsigned io_base) +static void activate_ad1845_unsafe(unsigned io_base) { - sscape_write_unsafe(io_base, GA_HMCTL_REG, (sscape_read_unsafe(io_base, GA_HMCTL_REG) & 0xcf) | 0x10); + unsigned char val = sscape_read_unsafe(io_base, GA_HMCTL_REG); + sscape_write_unsafe(io_base, GA_HMCTL_REG, (val & 0xcf) | 0x10); sscape_write_unsafe(io_base, GA_CDCFG_REG, 0x80); } @@ -359,24 +354,27 @@ static void soundscape_free(struct snd_card *c) * Tell the SoundScape to begin a DMA tranfer using the given channel. * All locking issues are left to the caller. */ -static inline void sscape_start_dma_unsafe(unsigned io_base, enum GA_REG reg) +static void sscape_start_dma_unsafe(unsigned io_base, enum GA_REG reg) { - sscape_write_unsafe(io_base, reg, sscape_read_unsafe(io_base, reg) | 0x01); - sscape_write_unsafe(io_base, reg, sscape_read_unsafe(io_base, reg) & 0xfe); + sscape_write_unsafe(io_base, reg, + sscape_read_unsafe(io_base, reg) | 0x01); + sscape_write_unsafe(io_base, reg, + sscape_read_unsafe(io_base, reg) & 0xfe); } /* * Wait for a DMA transfer to complete. This is a "limited busy-wait", * and all locking issues are left to the caller. */ -static int sscape_wait_dma_unsafe(unsigned io_base, enum GA_REG reg, unsigned timeout) +static int sscape_wait_dma_unsafe(unsigned io_base, enum GA_REG reg, + unsigned timeout) { while (!(sscape_read_unsafe(io_base, reg) & 0x01) && (timeout != 0)) { udelay(100); --timeout; } /* while */ - return (sscape_read_unsafe(io_base, reg) & 0x01); + return sscape_read_unsafe(io_base, reg) & 0x01; } /* @@ -392,12 +390,12 @@ static int obp_startup_ack(struct soundscape *s, unsigned timeout) do { unsigned long flags; - unsigned char x; + int x; spin_lock_irqsave(&s->lock, flags); - x = inb(HOST_DATA_IO(s->io_base)); + x = host_read_unsafe(s->io_base); spin_unlock_irqrestore(&s->lock, flags); - if ((x & 0xfe) == 0xfe) + if (x == 0xfe || x == 0xff) return 1; msleep(10); @@ -419,10 +417,10 @@ static int host_startup_ack(struct soundscape *s, unsigned timeout) do { unsigned long flags; - unsigned char x; + int x; spin_lock_irqsave(&s->lock, flags); - x = inb(HOST_DATA_IO(s->io_base)); + x = host_read_unsafe(s->io_base); spin_unlock_irqrestore(&s->lock, flags); if (x == 0xfe) return 1; @@ -436,15 +434,15 @@ static int host_startup_ack(struct soundscape *s, unsigned timeout) /* * Upload a byte-stream into the SoundScape using DMA channel A. */ -static int upload_dma_data(struct soundscape *s, - const unsigned char __user *data, - size_t size) +static int upload_dma_data(struct soundscape *s, const unsigned char *data, + size_t size) { unsigned long flags; struct snd_dma_buffer dma; int ret; + unsigned char val; - if (!get_dmabuf(&dma, PAGE_ALIGN(size))) + if (!get_dmabuf(&dma, PAGE_ALIGN(32 * 1024))) return -ENOMEM; spin_lock_irqsave(&s->lock, flags); @@ -452,70 +450,57 @@ static int upload_dma_data(struct soundscape *s, /* * Reset the board ... */ - sscape_write_unsafe(s->io_base, GA_HMCTL_REG, sscape_read_unsafe(s->io_base, GA_HMCTL_REG) & 0x3f); + val = sscape_read_unsafe(s->io_base, GA_HMCTL_REG); + sscape_write_unsafe(s->io_base, GA_HMCTL_REG, val & 0x3f); /* * Enable the DMA channels and configure them ... */ - sscape_write_unsafe(s->io_base, GA_DMACFG_REG, 0x50); - sscape_write_unsafe(s->io_base, GA_DMAA_REG, (s->chip->dma1 << 4) | DMA_8BIT); + val = (s->chip->dma1 << 4) | DMA_8BIT; + sscape_write_unsafe(s->io_base, GA_DMAA_REG, val); sscape_write_unsafe(s->io_base, GA_DMAB_REG, 0x20); /* * Take the board out of reset ... */ - sscape_write_unsafe(s->io_base, GA_HMCTL_REG, sscape_read_unsafe(s->io_base, GA_HMCTL_REG) | 0x80); + val = sscape_read_unsafe(s->io_base, GA_HMCTL_REG); + sscape_write_unsafe(s->io_base, GA_HMCTL_REG, val | 0x80); /* - * Upload the user's data (firmware?) to the SoundScape + * Upload the firmware to the SoundScape * board through the DMA channel ... */ while (size != 0) { unsigned long len; - /* - * Apparently, copying to/from userspace can sleep. - * We are therefore forbidden from holding any - * spinlocks while we copy ... - */ - spin_unlock_irqrestore(&s->lock, flags); - - /* - * Remember that the data that we want to DMA - * comes from USERSPACE. We have already verified - * the userspace pointer ... - */ len = min(size, dma.bytes); - len -= __copy_from_user(dma.area, data, len); + memcpy(dma.area, data, len); data += len; size -= len; - /* - * Grab that spinlock again, now that we've - * finished copying! - */ - spin_lock_irqsave(&s->lock, flags); - snd_dma_program(s->chip->dma1, dma.addr, len, DMA_MODE_WRITE); sscape_start_dma_unsafe(s->io_base, GA_DMAA_REG); if (!sscape_wait_dma_unsafe(s->io_base, GA_DMAA_REG, 5000)) { /* - * Don't forget to release this spinlock we're holding ... + * Don't forget to release this spinlock we're holding */ spin_unlock_irqrestore(&s->lock, flags); - snd_printk(KERN_ERR "sscape: DMA upload has timed out\n"); + snd_printk(KERN_ERR + "sscape: DMA upload has timed out\n"); ret = -EAGAIN; goto _release_dma; } } /* while */ set_host_mode_unsafe(s->io_base); + outb(0x0, s->io_base); /* * Boot the board ... (I think) */ - sscape_write_unsafe(s->io_base, GA_HMCTL_REG, sscape_read_unsafe(s->io_base, GA_HMCTL_REG) | 0x40); + val = sscape_read_unsafe(s->io_base, GA_HMCTL_REG); + sscape_write_unsafe(s->io_base, GA_HMCTL_REG, val | 0x40); spin_unlock_irqrestore(&s->lock, flags); /* @@ -525,10 +510,12 @@ static int upload_dma_data(struct soundscape *s, */ ret = 0; if (!obp_startup_ack(s, 5000)) { - snd_printk(KERN_ERR "sscape: No response from on-board processor after upload\n"); + snd_printk(KERN_ERR "sscape: No response " + "from on-board processor after upload\n"); ret = -EAGAIN; } else if (!host_startup_ack(s, 5000)) { - snd_printk(KERN_ERR "sscape: SoundScape failed to initialise\n"); + snd_printk(KERN_ERR + "sscape: SoundScape failed to initialise\n"); ret = -EAGAIN; } @@ -536,7 +523,7 @@ _release_dma: /* * NOTE!!! We are NOT holding any spinlocks at this point !!! */ - sscape_write(s, GA_DMAA_REG, (s->ic_type == IC_ODIE ? 0x70 : 0x40)); + sscape_write(s, GA_DMAA_REG, (s->ic_type == IC_OPUS ? 0x40 : 0x70)); free_dmabuf(&dma); return ret; @@ -546,167 +533,76 @@ _release_dma: * Upload the bootblock(?) into the SoundScape. The only * purpose of this block of code seems to be to tell * us which version of the microcode we should be using. - * - * NOTE: The boot-block data resides in USER-SPACE!!! - * However, we have already verified its memory - * addresses by the time we get here. */ -static int sscape_upload_bootblock(struct soundscape *sscape, struct sscape_bootblock __user *bb) +static int sscape_upload_bootblock(struct snd_card *card) { + struct soundscape *sscape = get_card_soundscape(card); unsigned long flags; + const struct firmware *init_fw = NULL; int data = 0; int ret; - ret = upload_dma_data(sscape, bb->code, sizeof(bb->code)); - - spin_lock_irqsave(&sscape->lock, flags); - if (ret == 0) { - data = host_read_ctrl_unsafe(sscape->io_base, 100); - } - set_midi_mode_unsafe(sscape->io_base); - spin_unlock_irqrestore(&sscape->lock, flags); - - if (ret == 0) { - if (data < 0) { - snd_printk(KERN_ERR "sscape: timeout reading firmware version\n"); - ret = -EAGAIN; - } - else if (__copy_to_user(&bb->version, &data, sizeof(bb->version))) { - ret = -EFAULT; - } + ret = request_firmware(&init_fw, "scope.cod", card->dev); + if (ret < 0) { + snd_printk(KERN_ERR "sscape: Error loading scope.cod"); + return ret; } + ret = upload_dma_data(sscape, init_fw->data, init_fw->size); - return ret; -} - -/* - * Upload the microcode into the SoundScape. The - * microcode is 64K of data, and if we try to copy - * it into a local variable then we will SMASH THE - * KERNEL'S STACK! We therefore leave it in USER - * SPACE, and save ourselves from copying it at all. - */ -static int sscape_upload_microcode(struct soundscape *sscape, - const struct sscape_microcode __user *mc) -{ - unsigned long flags; - char __user *code; - int err; + release_firmware(init_fw); - /* - * We are going to have to copy this data into a special - * DMA-able buffer before we can upload it. We shall therefore - * just check that the data pointer is valid for now. - * - * NOTE: This buffer is 64K long! That's WAY too big to - * copy into a stack-temporary anyway. - */ - if ( get_user(code, &mc->code) || - !access_ok(VERIFY_READ, code, SSCAPE_MICROCODE_SIZE) ) - return -EFAULT; + spin_lock_irqsave(&sscape->lock, flags); + if (ret == 0) + data = host_read_ctrl_unsafe(sscape->io_base, 100); - if ((err = upload_dma_data(sscape, code, SSCAPE_MICROCODE_SIZE)) == 0) { - snd_printk(KERN_INFO "sscape: MIDI firmware loaded\n"); - } + if (data & 0x10) + sscape_write_unsafe(sscape->io_base, GA_SMCFGA_REG, 0x2f); - spin_lock_irqsave(&sscape->lock, flags); - set_midi_mode_unsafe(sscape->io_base); spin_unlock_irqrestore(&sscape->lock, flags); - initialise_mpu401(sscape->mpu); + data &= 0xf; + if (ret == 0 && data > 7) { + snd_printk(KERN_ERR + "sscape: timeout reading firmware version\n"); + ret = -EAGAIN; + } - return err; + return (ret == 0) ? data : ret; } /* - * Hardware-specific device functions, to implement special - * IOCTLs for the SoundScape card. This is how we upload - * the microcode into the card, for example, and so we - * must ensure that no two processes can open this device - * simultaneously, and that we can't open it at all if - * someone is using the MIDI device. + * Upload the microcode into the SoundScape. */ -static int sscape_hw_open(struct snd_hwdep * hw, struct file *file) +static int sscape_upload_microcode(struct snd_card *card, int version) { - register struct soundscape *sscape = get_hwdep_soundscape(hw); - unsigned long flags; + struct soundscape *sscape = get_card_soundscape(card); + const struct firmware *init_fw = NULL; + char name[14]; int err; - spin_lock_irqsave(&sscape->fwlock, flags); + snprintf(name, sizeof(name), "sndscape.co%d", version); - if ((sscape->midi_usage != 0) || sscape->hw_in_use) { - err = -EBUSY; - } else { - sscape->hw_in_use = 1; - err = 0; + err = request_firmware(&init_fw, name, card->dev); + if (err < 0) { + snd_printk(KERN_ERR "sscape: Error loading sndscape.co%d", + version); + return err; } + err = upload_dma_data(sscape, init_fw->data, init_fw->size); + if (err == 0) + snd_printk(KERN_INFO "sscape: MIDI firmware loaded %d KBs\n", + init_fw->size >> 10); - spin_unlock_irqrestore(&sscape->fwlock, flags); - return err; -} - -static int sscape_hw_release(struct snd_hwdep * hw, struct file *file) -{ - register struct soundscape *sscape = get_hwdep_soundscape(hw); - unsigned long flags; - - spin_lock_irqsave(&sscape->fwlock, flags); - sscape->hw_in_use = 0; - spin_unlock_irqrestore(&sscape->fwlock, flags); - return 0; -} - -static int sscape_hw_ioctl(struct snd_hwdep * hw, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct soundscape *sscape = get_hwdep_soundscape(hw); - int err = -EBUSY; - - switch (cmd) { - case SND_SSCAPE_LOAD_BOOTB: - { - register struct sscape_bootblock __user *bb = (struct sscape_bootblock __user *) arg; - - /* - * We are going to have to copy this data into a special - * DMA-able buffer before we can upload it. We shall therefore - * just check that the data pointer is valid for now ... - */ - if ( !access_ok(VERIFY_READ, bb->code, sizeof(bb->code)) ) - return -EFAULT; - - /* - * Now check that we can write the firmware version number too... - */ - if ( !access_ok(VERIFY_WRITE, &bb->version, sizeof(bb->version)) ) - return -EFAULT; - - err = sscape_upload_bootblock(sscape, bb); - } - break; - - case SND_SSCAPE_LOAD_MCODE: - { - register const struct sscape_microcode __user *mc = (const struct sscape_microcode __user *) arg; - - err = sscape_upload_microcode(sscape, mc); - } - break; - - default: - err = -EINVAL; - break; - } /* switch */ + release_firmware(init_fw); return err; } - /* * Mixer control for the SoundScape's MIDI device. */ static int sscape_midi_info(struct snd_kcontrol *ctl, - struct snd_ctl_elem_info *uinfo) + struct snd_ctl_elem_info *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 1; @@ -716,7 +612,7 @@ static int sscape_midi_info(struct snd_kcontrol *ctl, } static int sscape_midi_get(struct snd_kcontrol *kctl, - struct snd_ctl_elem_value *uctl) + struct snd_ctl_elem_value *uctl) { struct snd_wss *chip = snd_kcontrol_chip(kctl); struct snd_card *card = chip->card; @@ -730,16 +626,18 @@ static int sscape_midi_get(struct snd_kcontrol *kctl, } static int sscape_midi_put(struct snd_kcontrol *kctl, - struct snd_ctl_elem_value *uctl) + struct snd_ctl_elem_value *uctl) { struct snd_wss *chip = snd_kcontrol_chip(kctl); struct snd_card *card = chip->card; - register struct soundscape *s = get_card_soundscape(card); + struct soundscape *s = get_card_soundscape(card); unsigned long flags; int change; + unsigned char new_val; spin_lock_irqsave(&s->lock, flags); + new_val = uctl->value.integer.value[0] & 127; /* * We need to put the board into HOST mode before we * can send any volume-changing HOST commands ... @@ -752,15 +650,16 @@ static int sscape_midi_put(struct snd_kcontrol *kctl, * and then perform another volume-related command. Perhaps the * first command is an "open" and the second command is a "close"? */ - if (s->midi_vol == ((unsigned char) uctl->value.integer. value[0] & 127)) { + if (s->midi_vol == new_val) { change = 0; goto __skip_change; } - change = (host_write_ctrl_unsafe(s->io_base, CMD_SET_MIDI_VOL, 100) - && host_write_ctrl_unsafe(s->io_base, ((unsigned char) uctl->value.integer. value[0]) & 127, 100) - && host_write_ctrl_unsafe(s->io_base, CMD_XXX_MIDI_VOL, 100)); - s->midi_vol = (unsigned char) uctl->value.integer.value[0] & 127; - __skip_change: + change = host_write_ctrl_unsafe(s->io_base, CMD_SET_MIDI_VOL, 100) + && host_write_ctrl_unsafe(s->io_base, new_val, 100) + && host_write_ctrl_unsafe(s->io_base, CMD_XXX_MIDI_VOL, 100) + && host_write_ctrl_unsafe(s->io_base, new_val, 100); + s->midi_vol = new_val; +__skip_change: /* * Take the board out of HOST mode and back into MIDI mode ... @@ -784,20 +683,25 @@ static struct snd_kcontrol_new midi_mixer_ctl = { * These IRQs are encoded as bit patterns so that they can be * written to the control registers. */ -static unsigned __devinit get_irq_config(int irq) +static unsigned __devinit get_irq_config(int sscape_type, int irq) { static const int valid_irq[] = { 9, 5, 7, 10 }; + static const int old_irq[] = { 9, 7, 5, 15 }; unsigned cfg; - for (cfg = 0; cfg < ARRAY_SIZE(valid_irq); ++cfg) { - if (irq == valid_irq[cfg]) - return cfg; - } /* for */ + if (sscape_type == MEDIA_FX) { + for (cfg = 0; cfg < ARRAY_SIZE(old_irq); ++cfg) + if (irq == old_irq[cfg]) + return cfg; + } else { + for (cfg = 0; cfg < ARRAY_SIZE(valid_irq); ++cfg) + if (irq == valid_irq[cfg]) + return cfg; + } return INVALID_IRQ; } - /* * Perform certain arcane port-checks to see whether there * is a SoundScape board lurking behind the given ports. @@ -842,11 +746,38 @@ static int __devinit detect_sscape(struct soundscape *s, long wss_io) 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->ic_type == IC_OPUS) + activate_ad1845_unsafe(s->io_base); if (s->type == SSCAPE_VIVO) wss_io += 4; + + d = sscape_read_unsafe(s->io_base, GA_HMCTL_REG); + sscape_write_unsafe(s->io_base, GA_HMCTL_REG, d | 0xc0); + + /* wait for WSS codec */ + for (d = 0; d < 500; d++) { + if ((inb(wss_io) & 0x80) == 0) + break; + spin_unlock_irqrestore(&s->lock, flags); + msleep(1); + spin_lock_irqsave(&s->lock, flags); + } + + if ((inb(wss_io) & 0x80) != 0) + goto _done; + + if (inb(wss_io + 2) == 0xff) + goto _done; + + d = sscape_read_unsafe(s->io_base, GA_HMCTL_REG) & 0x3f; + sscape_write_unsafe(s->io_base, GA_HMCTL_REG, d); + + if ((inb(wss_io) & 0x80) != 0) + s->type = MEDIA_FX; + + d = sscape_read_unsafe(s->io_base, GA_HMCTL_REG); + sscape_write_unsafe(s->io_base, GA_HMCTL_REG, d | 0xc0); /* wait for WSS codec */ for (d = 0; d < 500; d++) { if ((inb(wss_io) & 0x80) == 0) @@ -855,14 +786,13 @@ static int __devinit detect_sscape(struct soundscape *s, long wss_io) msleep(1); spin_lock_irqsave(&s->lock, flags); } - snd_printd(KERN_INFO "init delay = %d ms\n", d); /* * SoundScape successfully detected! */ retval = 1; - _done: +_done: spin_unlock_irqrestore(&s->lock, flags); return retval; } @@ -873,63 +803,35 @@ static int __devinit detect_sscape(struct soundscape *s, long wss_io) * to crash the machine. Also check that someone isn't using the hardware * IOCTL device. */ -static int mpu401_open(struct snd_mpu401 * mpu) +static int mpu401_open(struct snd_mpu401 *mpu) { - int err; - if (!verify_mpu401(mpu)) { - snd_printk(KERN_ERR "sscape: MIDI disabled, please load firmware\n"); - err = -ENODEV; - } else { - register struct soundscape *sscape = get_mpu401_soundscape(mpu); - unsigned long flags; - - spin_lock_irqsave(&sscape->fwlock, flags); - - if (sscape->hw_in_use || (sscape->midi_usage == ULONG_MAX)) { - err = -EBUSY; - } else { - ++(sscape->midi_usage); - err = 0; - } - - spin_unlock_irqrestore(&sscape->fwlock, flags); + snd_printk(KERN_ERR "sscape: MIDI disabled, " + "please load firmware\n"); + return -ENODEV; } - return err; -} - -static void mpu401_close(struct snd_mpu401 * mpu) -{ - register struct soundscape *sscape = get_mpu401_soundscape(mpu); - unsigned long flags; - - spin_lock_irqsave(&sscape->fwlock, flags); - --(sscape->midi_usage); - spin_unlock_irqrestore(&sscape->fwlock, flags); + return 0; } /* * Initialse an MPU-401 subdevice for MIDI support on the SoundScape. */ -static int __devinit create_mpu401(struct snd_card *card, int devnum, unsigned long port, int irq) +static int __devinit create_mpu401(struct snd_card *card, int devnum, + unsigned long port, int irq) { struct soundscape *sscape = get_card_soundscape(card); struct snd_rawmidi *rawmidi; int err; - if ((err = snd_mpu401_uart_new(card, devnum, - MPU401_HW_MPU401, - port, MPU401_INFO_INTEGRATED, - irq, IRQF_DISABLED, - &rawmidi)) == 0) { - struct snd_mpu401 *mpu = (struct snd_mpu401 *) rawmidi->private_data; + err = snd_mpu401_uart_new(card, devnum, MPU401_HW_MPU401, port, + MPU401_INFO_INTEGRATED, irq, IRQF_DISABLED, + &rawmidi); + if (err == 0) { + struct snd_mpu401 *mpu = rawmidi->private_data; mpu->open_input = mpu401_open; mpu->open_output = mpu401_open; - mpu->close_input = mpu401_close; - mpu->close_output = mpu401_close; mpu->private_data = sscape; - sscape->mpu = mpu; initialise_mpu401(mpu); } @@ -950,32 +852,34 @@ static int __devinit create_ad1845(struct snd_card *card, unsigned port, register struct soundscape *sscape = get_card_soundscape(card); struct snd_wss *chip; int err; + int codec_type = WSS_HW_DETECT; - if (sscape->type == SSCAPE_VIVO) - port += 4; + switch (sscape->type) { + case MEDIA_FX: + case SSCAPE: + /* + * There are some freak examples of early Soundscape cards + * with CS4231 instead of AD1848/CS4248. Unfortunately, the + * CS4231 works only in CS4248 compatibility mode on + * these cards so force it. + */ + if (sscape->ic_type != IC_OPUS) + codec_type = WSS_HW_AD1848; + break; - if (dma1 == dma2) - dma2 = -1; + case SSCAPE_VIVO: + port += 4; + break; + default: + break; + } err = snd_wss_create(card, port, -1, irq, dma1, dma2, - WSS_HW_DETECT, WSS_HWSHARE_DMA1, &chip); + codec_type, WSS_HWSHARE_DMA1, &chip); if (!err) { unsigned long flags; struct snd_pcm *pcm; -/* - * It turns out that the PLAYBACK_ENABLE bit is set - * by the lowlevel driver ... - * -#define AD1845_IFACE_CONFIG \ - (CS4231_AUTOCALIB | CS4231_RECORD_ENABLE | CS4231_PLAYBACK_ENABLE) - snd_wss_mce_up(chip); - spin_lock_irqsave(&chip->reg_lock, flags); - snd_wss_out(chip, CS4231_IFACE_CTRL, AD1845_IFACE_CONFIG); - spin_unlock_irqrestore(&chip->reg_lock, flags); - snd_wss_mce_down(chip); - */ - if (sscape->type != SSCAPE_VIVO) { /* * The input clock frequency on the SoundScape must @@ -1022,17 +926,10 @@ static int __devinit create_ad1845(struct snd_card *card, unsigned port, } } - strcpy(card->driver, "SoundScape"); - strcpy(card->shortname, pcm->name); - snprintf(card->longname, sizeof(card->longname), - "%s at 0x%lx, IRQ %d, DMA1 %d, DMA2 %d\n", - pcm->name, chip->port, chip->irq, - chip->dma1, chip->dma2); - sscape->chip = chip; } - _error: +_error: return err; } @@ -1051,21 +948,8 @@ static int __devinit create_sscape(int dev, struct snd_card *card) struct resource *wss_res; unsigned long flags; int err; - - /* - * Check that the user didn't pass us garbage data ... - */ - irq_cfg = get_irq_config(irq[dev]); - if (irq_cfg == INVALID_IRQ) { - snd_printk(KERN_ERR "sscape: Invalid IRQ %d\n", irq[dev]); - return -ENXIO; - } - - mpu_irq_cfg = get_irq_config(mpu_irq[dev]); - if (mpu_irq_cfg == INVALID_IRQ) { - printk(KERN_ERR "sscape: Invalid IRQ %d\n", mpu_irq[dev]); - return -ENXIO; - } + int val; + const char *name; /* * Grab IO ports that we will need to probe so that we @@ -1098,41 +982,51 @@ static int __devinit create_sscape(int dev, struct snd_card *card) } spin_lock_init(&sscape->lock); - spin_lock_init(&sscape->fwlock); sscape->io_res = io_res; sscape->wss_res = wss_res; sscape->io_base = port[dev]; if (!detect_sscape(sscape, wss_port[dev])) { - printk(KERN_ERR "sscape: hardware not detected at 0x%x\n", sscape->io_base); + printk(KERN_ERR "sscape: hardware not detected at 0x%x\n", + sscape->io_base); err = -ENODEV; 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]); + switch (sscape->type) { + case MEDIA_FX: + name = "MediaFX/SoundFX"; + break; + case SSCAPE: + name = "Soundscape"; + break; + case SSCAPE_PNP: + name = "Soundscape PnP"; + break; + case SSCAPE_VIVO: + name = "Soundscape VIVO"; + break; + default: + name = "unknown Soundscape"; + break; + } - 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; + printk(KERN_INFO "sscape: %s card detected at 0x%x, using IRQ %d, DMA %d\n", + name, sscape->io_base, irq[dev], dma[dev]); + + /* + * Check that the user didn't pass us garbage data ... + */ + irq_cfg = get_irq_config(sscape->type, irq[dev]); + if (irq_cfg == INVALID_IRQ) { + snd_printk(KERN_ERR "sscape: Invalid IRQ %d\n", irq[dev]); + return -ENXIO; + } + + mpu_irq_cfg = get_irq_config(sscape->type, mpu_irq[dev]); + if (mpu_irq_cfg == INVALID_IRQ) { + snd_printk(KERN_ERR "sscape: Invalid IRQ %d\n", mpu_irq[dev]); + return -ENXIO; } /* @@ -1141,9 +1035,6 @@ static int __devinit create_sscape(int dev, struct snd_card *card) */ spin_lock_irqsave(&sscape->lock, flags); - activate_ad1845_unsafe(sscape->io_base); - - sscape_write_unsafe(sscape->io_base, GA_INTENA_REG, 0x00); /* disable */ sscape_write_unsafe(sscape->io_base, GA_SMCFGA_REG, 0x2e); sscape_write_unsafe(sscape->io_base, GA_SMCFGB_REG, 0x00); @@ -1151,15 +1042,23 @@ static int __devinit create_sscape(int dev, struct snd_card *card) * Enable and configure the DMA channels ... */ sscape_write_unsafe(sscape->io_base, GA_DMACFG_REG, 0x50); - dma_cfg = (sscape->ic_type == IC_ODIE ? 0x70 : 0x40); + dma_cfg = (sscape->ic_type == IC_OPUS ? 0x40 : 0x70); sscape_write_unsafe(sscape->io_base, GA_DMAA_REG, dma_cfg); sscape_write_unsafe(sscape->io_base, GA_DMAB_REG, 0x20); - sscape_write_unsafe(sscape->io_base, - GA_INTCFG_REG, 0xf0 | (mpu_irq_cfg << 2) | mpu_irq_cfg); + mpu_irq_cfg |= mpu_irq_cfg << 2; + val = sscape_read_unsafe(sscape->io_base, GA_HMCTL_REG) & 0xF7; + if (joystick[dev]) + val |= 8; + sscape_write_unsafe(sscape->io_base, GA_HMCTL_REG, val | 0x10); + sscape_write_unsafe(sscape->io_base, GA_INTCFG_REG, 0xf0 | mpu_irq_cfg); sscape_write_unsafe(sscape->io_base, GA_CDCFG_REG, 0x09 | DMA_8BIT | (dma[dev] << 4) | (irq_cfg << 1)); + /* + * Enable the master IRQ ... + */ + sscape_write_unsafe(sscape->io_base, GA_INTENA_REG, 0x80); spin_unlock_irqrestore(&sscape->lock, flags); @@ -1170,32 +1069,56 @@ static int __devinit create_sscape(int dev, struct snd_card *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]); + snd_printk(KERN_ERR + "sscape: No AD1845 device at 0x%lx, IRQ %d\n", + wss_port[dev], irq[dev]); goto _release_dma; } + strcpy(card->driver, "SoundScape"); + strcpy(card->shortname, name); + snprintf(card->longname, sizeof(card->longname), + "%s at 0x%lx, IRQ %d, DMA1 %d, DMA2 %d\n", + name, sscape->chip->port, sscape->chip->irq, + sscape->chip->dma1, sscape->chip->dma2); + #define MIDI_DEVNUM 0 if (sscape->type != SSCAPE_VIVO) { - err = create_mpu401(card, MIDI_DEVNUM, port[dev], mpu_irq[dev]); - if (err < 0) { - printk(KERN_ERR "sscape: Failed to create " - "MPU-401 device at 0x%lx\n", - port[dev]); - goto _release_dma; - } + err = sscape_upload_bootblock(card); + if (err >= 0) + err = sscape_upload_microcode(card, err); - /* - * Enable the master IRQ ... - */ - sscape_write(sscape, GA_INTENA_REG, 0x80); + if (err == 0) { + err = create_mpu401(card, MIDI_DEVNUM, port[dev], + mpu_irq[dev]); + if (err < 0) { + snd_printk(KERN_ERR "sscape: Failed to create " + "MPU-401 device at 0x%lx\n", + port[dev]); + goto _release_dma; + } - /* - * 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 + */ + spin_lock_irqsave(&sscape->lock, flags); + sscape->midi_vol = 0; + host_write_ctrl_unsafe(sscape->io_base, + CMD_SET_MIDI_VOL, 100); + host_write_ctrl_unsafe(sscape->io_base, + sscape->midi_vol, 100); + host_write_ctrl_unsafe(sscape->io_base, + CMD_XXX_MIDI_VOL, 100); + host_write_ctrl_unsafe(sscape->io_base, + sscape->midi_vol, 100); + host_write_ctrl_unsafe(sscape->io_base, + CMD_SET_EXTMIDI, 100); + host_write_ctrl_unsafe(sscape->io_base, + 0, 100); + host_write_ctrl_unsafe(sscape->io_base, CMD_ACK, 100); + + set_midi_mode_unsafe(sscape->io_base); + spin_unlock_irqrestore(&sscape->lock, flags); + } } /* @@ -1231,7 +1154,8 @@ static int __devinit snd_sscape_match(struct device *pdev, unsigned int i) mpu_irq[i] == SNDRV_AUTO_IRQ || dma[i] == SNDRV_AUTO_DMA) { printk(KERN_INFO - "sscape: insufficient parameters, need IO, IRQ, MPU-IRQ and DMA\n"); + "sscape: insufficient parameters, " + "need IO, IRQ, MPU-IRQ and DMA\n"); return 0; } @@ -1253,13 +1177,15 @@ static int __devinit snd_sscape_probe(struct device *pdev, unsigned int dev) sscape->type = SSCAPE; dma[dev] &= 0x03; + snd_card_set_dev(card, pdev); + ret = create_sscape(dev, card); if (ret < 0) 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"); + ret = snd_card_register(card); + if (ret < 0) { + snd_printk(KERN_ERR "sscape: Failed to register sound card\n"); goto _release_card; } dev_set_drvdata(pdev, card); @@ -1311,36 +1237,20 @@ static int __devinit sscape_pnp_detect(struct pnp_card_link *pcard, * Allow this function to fail *quietly* if all the ISA PnP * devices were configured using module parameters instead. */ - if ((idx = get_next_autoindex(idx)) >= SNDRV_CARDS) + idx = get_next_autoindex(idx); + if (idx >= SNDRV_CARDS) return -ENOSPC; /* - * We have found a candidate ISA PnP card. Now we - * have to check that it has the devices that we - * expect it to have. - * - * We will NOT try and autoconfigure all of the resources - * needed and then activate the card as we are assuming that - * has already been done at boot-time using /proc/isapnp. - * We shall simply try to give each active card the resources - * that it wants. This is a sensible strategy for a modular - * system where unused modules are unloaded regularly. - * - * This strategy is utterly useless if we compile the driver - * into the kernel, of course. - */ - // printk(KERN_INFO "sscape: %s\n", card->name); - - /* * Check that we still have room for another sound card ... */ dev = pnp_request_card_device(pcard, pid->devs[0].id, NULL); - if (! dev) + if (!dev) return -ENODEV; if (!pnp_is_active(dev)) { if (pnp_activate_dev(dev) < 0) { - printk(KERN_INFO "sscape: device is inactive\n"); + snd_printk(KERN_INFO "sscape: device is inactive\n"); return -EBUSY; } } @@ -1378,14 +1288,15 @@ static int __devinit sscape_pnp_detect(struct pnp_card_link *pcard, wss_port[idx] = pnp_port_start(dev, 1); dma2[idx] = pnp_dma(dev, 1); } + snd_card_set_dev(card, &pcard->card->dev); ret = create_sscape(idx, card); if (ret < 0) 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"); + ret = snd_card_register(card); + if (ret < 0) { + snd_printk(KERN_ERR "sscape: Failed to register sound card\n"); goto _release_card; } diff --git a/sound/isa/wss/wss_lib.c b/sound/isa/wss/wss_lib.c index 5d2ba1b749ab..5b9d6c18bc45 100644 --- a/sound/isa/wss/wss_lib.c +++ b/sound/isa/wss/wss_lib.c @@ -1682,7 +1682,7 @@ static void snd_wss_resume(struct snd_wss *chip) } #endif /* CONFIG_PM */ -int snd_wss_free(struct snd_wss *chip) +static int snd_wss_free(struct snd_wss *chip) { release_and_free_resource(chip->res_port); release_and_free_resource(chip->res_cport); @@ -1705,7 +1705,6 @@ int snd_wss_free(struct snd_wss *chip) kfree(chip); return 0; } -EXPORT_SYMBOL(snd_wss_free); static int snd_wss_dev_free(struct snd_device *device) { @@ -2198,84 +2197,61 @@ EXPORT_SYMBOL(snd_wss_put_double); static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0); static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0); static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0); -static struct snd_kcontrol_new snd_ad1848_controls[] = { -WSS_DOUBLE("PCM Playback Switch", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, - 7, 7, 1, 1), +static struct snd_kcontrol_new snd_wss_controls[] = { +WSS_DOUBLE("PCM Playback Switch", 0, + CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1), WSS_DOUBLE_TLV("PCM Playback Volume", 0, - CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1, - db_scale_6bit), + CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1, + db_scale_6bit), WSS_DOUBLE("Aux Playback Switch", 0, - CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1), + CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1), WSS_DOUBLE_TLV("Aux Playback Volume", 0, - CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1, - db_scale_5bit_12db_max), + CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1, + db_scale_5bit_12db_max), WSS_DOUBLE("Aux Playback Switch", 1, - CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1), + CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1), WSS_DOUBLE_TLV("Aux Playback Volume", 1, - CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1, - db_scale_5bit_12db_max), + CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1, + db_scale_5bit_12db_max), WSS_DOUBLE_TLV("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0, db_scale_rec_gain), { - .name = "Capture Source", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Source", .info = snd_wss_info_mux, .get = snd_wss_get_mux, .put = snd_wss_put_mux, }, -WSS_SINGLE("Loopback Capture Switch", 0, CS4231_LOOPBACK, 0, 1, 0), -WSS_SINGLE_TLV("Loopback Capture Volume", 0, CS4231_LOOPBACK, 1, 63, 0, - db_scale_6bit), -}; - -static struct snd_kcontrol_new snd_wss_controls[] = { -WSS_DOUBLE("PCM Playback Switch", 0, - CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1), -WSS_DOUBLE("PCM Playback Volume", 0, - CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1), +WSS_DOUBLE("Mic Boost (+20dB)", 0, + CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 5, 5, 1, 0), +WSS_SINGLE("Loopback Capture Switch", 0, + CS4231_LOOPBACK, 0, 1, 0), +WSS_SINGLE_TLV("Loopback Capture Volume", 0, CS4231_LOOPBACK, 2, 63, 1, + db_scale_6bit), WSS_DOUBLE("Line Playback Switch", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1), -WSS_DOUBLE("Line Playback Volume", 0, - CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1), -WSS_DOUBLE("Aux Playback Switch", 0, - CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1), -WSS_DOUBLE("Aux Playback Volume", 0, - CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1), -WSS_DOUBLE("Aux Playback Switch", 1, - CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1), -WSS_DOUBLE("Aux Playback Volume", 1, - CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1), -WSS_SINGLE("Mono Playback Switch", 0, +WSS_DOUBLE_TLV("Line Playback Volume", 0, + CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1, + db_scale_5bit_12db_max), +WSS_SINGLE("Beep Playback Switch", 0, CS4231_MONO_CTRL, 7, 1, 1), -WSS_SINGLE("Mono Playback Volume", 0, - CS4231_MONO_CTRL, 0, 15, 1), +WSS_SINGLE_TLV("Beep Playback Volume", 0, + CS4231_MONO_CTRL, 0, 15, 1, + db_scale_4bit), WSS_SINGLE("Mono Output Playback Switch", 0, CS4231_MONO_CTRL, 6, 1, 1), -WSS_SINGLE("Mono Output Playback Bypass", 0, +WSS_SINGLE("Beep Bypass Playback Switch", 0, CS4231_MONO_CTRL, 5, 1, 0), -WSS_DOUBLE("Capture Volume", 0, - CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0), -{ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .info = snd_wss_info_mux, - .get = snd_wss_get_mux, - .put = snd_wss_put_mux, -}, -WSS_DOUBLE("Mic Boost", 0, - CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 5, 5, 1, 0), -WSS_SINGLE("Loopback Capture Switch", 0, - CS4231_LOOPBACK, 0, 1, 0), -WSS_SINGLE("Loopback Capture Volume", 0, - CS4231_LOOPBACK, 2, 63, 1) }; static struct snd_kcontrol_new snd_opti93x_controls[] = { WSS_DOUBLE("Master Playback Switch", 0, OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 7, 7, 1, 1), -WSS_DOUBLE("Master Playback Volume", 0, - OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 1, 1, 31, 1), +WSS_DOUBLE_TLV("Master Playback Volume", 0, + OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 1, 1, 31, 1, + db_scale_6bit), WSS_DOUBLE("PCM Playback Switch", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1), WSS_DOUBLE("PCM Playback Volume", 0, @@ -2334,22 +2310,21 @@ int snd_wss_mixer(struct snd_wss *chip) if (err < 0) return err; } - else if (chip->hardware & WSS_HW_AD1848_MASK) - for (idx = 0; idx < ARRAY_SIZE(snd_ad1848_controls); idx++) { - err = snd_ctl_add(card, - snd_ctl_new1(&snd_ad1848_controls[idx], - chip)); - if (err < 0) - return err; - } - else - for (idx = 0; idx < ARRAY_SIZE(snd_wss_controls); idx++) { + else { + int count = ARRAY_SIZE(snd_wss_controls); + + /* Use only the first 11 entries on AD1848 */ + if (chip->hardware & WSS_HW_AD1848_MASK) + count = 11; + + for (idx = 0; idx < count; idx++) { err = snd_ctl_add(card, snd_ctl_new1(&snd_wss_controls[idx], chip)); if (err < 0) return err; } + } return 0; } EXPORT_SYMBOL(snd_wss_mixer); diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig index bcf2a0698d54..135a2b77cc4a 100644 --- a/sound/oss/Kconfig +++ b/sound/oss/Kconfig @@ -287,18 +287,6 @@ config SOUND_DMAP Say Y unless you have 16MB or more RAM or a PCI sound card. -config SOUND_SSCAPE - tristate "Ensoniq SoundScape support" - help - Answer Y if you have a sound card based on the Ensoniq SoundScape - chipset. Such cards are being manufactured at least by Ensoniq, Spea - and Reveal (Reveal makes also other cards). - - If you compile the driver into the kernel, you have to add - "sscape=<io>,<irq>,<dma>,<mpuio>,<mpuirq>" to the kernel command - line. - - config SOUND_VMIDI tristate "Loopback MIDI device support" help diff --git a/sound/oss/Makefile b/sound/oss/Makefile index e0ae4d4d6a5c..567b8a74178a 100644 --- a/sound/oss/Makefile +++ b/sound/oss/Makefile @@ -13,7 +13,6 @@ obj-$(CONFIG_SOUND_SH_DAC_AUDIO) += sh_dac_audio.o obj-$(CONFIG_SOUND_AEDSP16) += aedsp16.o obj-$(CONFIG_SOUND_PSS) += pss.o ad1848.o mpu401.o obj-$(CONFIG_SOUND_TRIX) += trix.o ad1848.o sb_lib.o uart401.o -obj-$(CONFIG_SOUND_SSCAPE) += sscape.o ad1848.o mpu401.o obj-$(CONFIG_SOUND_MSS) += ad1848.o obj-$(CONFIG_SOUND_PAS) += pas2.o sb.o sb_lib.o uart401.o obj-$(CONFIG_SOUND_SB) += sb.o sb_lib.o uart401.o diff --git a/sound/oss/audio.c b/sound/oss/audio.c index b69c05b7ea7b..7df48a25c4ee 100644 --- a/sound/oss/audio.c +++ b/sound/oss/audio.c @@ -838,7 +838,7 @@ static int dma_ioctl(int dev, unsigned int cmd, void __user *arg) if ((err = audio_devs[dev]->d->prepare_for_input(dev, dmap_in->fragment_size, dmap_in->nbufs)) < 0) { spin_unlock_irqrestore(&dmap_in->lock,flags); - return -err; + return err; } dmap_in->dma_mode = DMODE_INPUT; audio_devs[dev]->enable_bits |= PCM_ENABLE_INPUT; diff --git a/sound/oss/dmasound/dmasound_core.c b/sound/oss/dmasound/dmasound_core.c index 793b7f478433..3f3c3f71db4b 100644 --- a/sound/oss/dmasound/dmasound_core.c +++ b/sound/oss/dmasound/dmasound_core.c @@ -219,7 +219,9 @@ static int shared_resources_initialised; * Mid level stuff */ -struct sound_settings dmasound = { .lock = SPIN_LOCK_UNLOCKED }; +struct sound_settings dmasound = { + .lock = __SPIN_LOCK_UNLOCKED(dmasound.lock) +}; static inline void sound_silence(void) { diff --git a/sound/oss/hex2hex.c b/sound/oss/hex2hex.c index 5460faae98c9..041ef5c52bc2 100644 --- a/sound/oss/hex2hex.c +++ b/sound/oss/hex2hex.c @@ -12,7 +12,7 @@ #define MAX_SIZE (256*1024) unsigned char buf[MAX_SIZE]; -int loadhex(FILE *inf, unsigned char *buf) +static int loadhex(FILE *inf, unsigned char *buf) { int l=0, c, i; diff --git a/sound/oss/midi_synth.c b/sound/oss/midi_synth.c index 9e450988ed36..3bc7104c5379 100644 --- a/sound/oss/midi_synth.c +++ b/sound/oss/midi_synth.c @@ -426,7 +426,7 @@ midi_synth_open(int dev, int mode) int err; struct midi_input_info *inc; - if (orig_dev < 0 || orig_dev > num_midis || midi_devs[orig_dev] == NULL) + if (orig_dev < 0 || orig_dev >= num_midis || midi_devs[orig_dev] == NULL) return -ENXIO; midi2synth[orig_dev] = dev; diff --git a/sound/oss/mpu401.c b/sound/oss/mpu401.c index 734b8f9e2f78..0af9d24feb8f 100644 --- a/sound/oss/mpu401.c +++ b/sound/oss/mpu401.c @@ -770,7 +770,7 @@ static int mpu_synth_ioctl(int dev, unsigned int cmd, void __user *arg) midi_dev = synth_devs[dev]->midi_dev; - if (midi_dev < 0 || midi_dev > num_midis || midi_devs[midi_dev] == NULL) + if (midi_dev < 0 || midi_dev >= num_midis || midi_devs[midi_dev] == NULL) return -ENXIO; devc = &dev_conf[midi_dev]; diff --git a/sound/oss/sb_common.c b/sound/oss/sb_common.c index 77d0e5efda76..ce4db49291f7 100644 --- a/sound/oss/sb_common.c +++ b/sound/oss/sb_common.c @@ -157,7 +157,7 @@ static void sb_intr (sb_devc *devc) break; default: - /* printk(KERN_WARN "Sound Blaster: Unexpected interrupt\n"); */ + /* printk(KERN_WARNING "Sound Blaster: Unexpected interrupt\n"); */ ; } } @@ -177,7 +177,7 @@ static void sb_intr (sb_devc *devc) break; default: - /* printk(KERN_WARN "Sound Blaster: Unexpected interrupt\n"); */ + /* printk(KERN_WARNING "Sound Blaster: Unexpected interrupt\n"); */ ; } } diff --git a/sound/oss/sb_ess.c b/sound/oss/sb_ess.c index 180e95c87e3e..51a3d381a59e 100644 --- a/sound/oss/sb_ess.c +++ b/sound/oss/sb_ess.c @@ -782,7 +782,7 @@ printk(KERN_INFO "FKS: ess_handle_channel %s irq_mode=%d\n", channel, irq_mode); break; default:; - /* printk(KERN_WARN "ESS: Unexpected interrupt\n"); */ + /* printk(KERN_WARNING "ESS: Unexpected interrupt\n"); */ } } diff --git a/sound/oss/sh_dac_audio.c b/sound/oss/sh_dac_audio.c index b2ed8757542a..4153752507e3 100644 --- a/sound/oss/sh_dac_audio.c +++ b/sound/oss/sh_dac_audio.c @@ -164,9 +164,6 @@ static ssize_t dac_audio_write(struct file *file, const char *buf, size_t count, int free; int nbytes; - if (count < 0) - return -EINVAL; - if (!count) { dac_audio_sync(); return 0; diff --git a/sound/oss/sscape.c b/sound/oss/sscape.c deleted file mode 100644 index 30c36d1f35d7..000000000000 --- a/sound/oss/sscape.c +++ /dev/null @@ -1,1480 +0,0 @@ -/* - * sound/oss/sscape.c - * - * Low level driver for Ensoniq SoundScape - * - * - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - * - * - * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) - * Sergey Smitienko : ensoniq p'n'p support - * Christoph Hellwig : adapted to module_init/module_exit - * Bartlomiej Zolnierkiewicz : added __init to attach_sscape() - * Chris Rankin : Specify that this module owns the coprocessor - * Arnaldo C. de Melo : added missing restore_flags in sscape_pnp_upload_file - */ - -#include <linux/init.h> -#include <linux/module.h> - -#include "sound_config.h" -#include "sound_firmware.h" - -#include <linux/types.h> -#include <linux/errno.h> -#include <linux/signal.h> -#include <linux/fcntl.h> -#include <linux/ctype.h> -#include <linux/stddef.h> -#include <linux/kmod.h> -#include <asm/dma.h> -#include <asm/io.h> -#include <linux/wait.h> -#include <linux/slab.h> -#include <linux/ioport.h> -#include <linux/delay.h> -#include <linux/proc_fs.h> -#include <linux/mm.h> -#include <linux/spinlock.h> - -#include "coproc.h" - -#include "ad1848.h" -#include "mpu401.h" - -/* - * I/O ports - */ -#define MIDI_DATA 0 -#define MIDI_CTRL 1 -#define HOST_CTRL 2 -#define TX_READY 0x02 -#define RX_READY 0x01 -#define HOST_DATA 3 -#define ODIE_ADDR 4 -#define ODIE_DATA 5 - -/* - * Indirect registers - */ - -#define GA_INTSTAT_REG 0 -#define GA_INTENA_REG 1 -#define GA_DMAA_REG 2 -#define GA_DMAB_REG 3 -#define GA_INTCFG_REG 4 -#define GA_DMACFG_REG 5 -#define GA_CDCFG_REG 6 -#define GA_SMCFGA_REG 7 -#define GA_SMCFGB_REG 8 -#define GA_HMCTL_REG 9 - -/* - * DMA channel identifiers (A and B) - */ - -#define SSCAPE_DMA_A 0 -#define SSCAPE_DMA_B 1 - -#define PORT(name) (devc->base+name) - -/* - * Host commands recognized by the OBP microcode - */ - -#define CMD_GEN_HOST_ACK 0x80 -#define CMD_GEN_MPU_ACK 0x81 -#define CMD_GET_BOARD_TYPE 0x82 -#define CMD_SET_CONTROL 0x88 /* Old firmware only */ -#define CMD_GET_CONTROL 0x89 /* Old firmware only */ -#define CTL_MASTER_VOL 0 -#define CTL_MIC_MODE 2 -#define CTL_SYNTH_VOL 4 -#define CTL_WAVE_VOL 7 -#define CMD_SET_EXTMIDI 0x8a -#define CMD_GET_EXTMIDI 0x8b -#define CMD_SET_MT32 0x8c -#define CMD_GET_MT32 0x8d - -#define CMD_ACK 0x80 - -#define IC_ODIE 1 -#define IC_OPUS 2 - -typedef struct sscape_info -{ - int base, irq, dma; - - int codec, codec_irq; /* required to setup pnp cards*/ - int codec_type; - int ic_type; - char* raw_buf; - unsigned long raw_buf_phys; - int buffsize; /* -------------------------- */ - spinlock_t lock; - int ok; /* Properly detected */ - int failed; - int dma_allocated; - int codec_audiodev; - int opened; - int *osp; - int my_audiodev; -} sscape_info; - -static struct sscape_info adev_info = { - 0 -}; - -static struct sscape_info *devc = &adev_info; -static int sscape_mididev = -1; - -/* Some older cards have assigned interrupt bits differently than new ones */ -static char valid_interrupts_old[] = { - 9, 7, 5, 15 -}; - -static char valid_interrupts_new[] = { - 9, 5, 7, 10 -}; - -static char *valid_interrupts = valid_interrupts_new; - -/* - * See the bottom of the driver. This can be set by spea =0/1. - */ - -#ifdef REVEAL_SPEA -static char old_hardware = 1; -#else -static char old_hardware; -#endif - -static void sleep(unsigned howlong) -{ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(howlong); -} - -static unsigned char sscape_read(struct sscape_info *devc, int reg) -{ - unsigned long flags; - unsigned char val; - - spin_lock_irqsave(&devc->lock,flags); - outb(reg, PORT(ODIE_ADDR)); - val = inb(PORT(ODIE_DATA)); - spin_unlock_irqrestore(&devc->lock,flags); - return val; -} - -static void __sscape_write(int reg, int data) -{ - outb(reg, PORT(ODIE_ADDR)); - outb(data, PORT(ODIE_DATA)); -} - -static void sscape_write(struct sscape_info *devc, int reg, int data) -{ - unsigned long flags; - - spin_lock_irqsave(&devc->lock,flags); - __sscape_write(reg, data); - spin_unlock_irqrestore(&devc->lock,flags); -} - -static unsigned char sscape_pnp_read_codec(sscape_info* devc, unsigned char reg) -{ - unsigned char res; - unsigned long flags; - - spin_lock_irqsave(&devc->lock,flags); - outb( reg, devc -> codec); - res = inb (devc -> codec + 1); - spin_unlock_irqrestore(&devc->lock,flags); - return res; - -} - -static void sscape_pnp_write_codec(sscape_info* devc, unsigned char reg, unsigned char data) -{ - unsigned long flags; - - spin_lock_irqsave(&devc->lock,flags); - outb( reg, devc -> codec); - outb( data, devc -> codec + 1); - spin_unlock_irqrestore(&devc->lock,flags); -} - -static void host_open(struct sscape_info *devc) -{ - outb((0x00), PORT(HOST_CTRL)); /* Put the board to the host mode */ -} - -static void host_close(struct sscape_info *devc) -{ - outb((0x03), PORT(HOST_CTRL)); /* Put the board to the MIDI mode */ -} - -static int host_write(struct sscape_info *devc, unsigned char *data, int count) -{ - unsigned long flags; - int i, timeout_val; - - spin_lock_irqsave(&devc->lock,flags); - /* - * Send the command and data bytes - */ - - for (i = 0; i < count; i++) - { - for (timeout_val = 10000; timeout_val > 0; timeout_val--) - if (inb(PORT(HOST_CTRL)) & TX_READY) - break; - - if (timeout_val <= 0) - { - spin_unlock_irqrestore(&devc->lock,flags); - return 0; - } - outb(data[i], PORT(HOST_DATA)); - } - spin_unlock_irqrestore(&devc->lock,flags); - return 1; -} - -static int host_read(struct sscape_info *devc) -{ - unsigned long flags; - int timeout_val; - unsigned char data; - - spin_lock_irqsave(&devc->lock,flags); - /* - * Read a byte - */ - - for (timeout_val = 10000; timeout_val > 0; timeout_val--) - if (inb(PORT(HOST_CTRL)) & RX_READY) - break; - - if (timeout_val <= 0) - { - spin_unlock_irqrestore(&devc->lock,flags); - return -1; - } - data = inb(PORT(HOST_DATA)); - spin_unlock_irqrestore(&devc->lock,flags); - return data; -} - -#if 0 /* unused */ -static int host_command1(struct sscape_info *devc, int cmd) -{ - unsigned char buf[10]; - buf[0] = (unsigned char) (cmd & 0xff); - return host_write(devc, buf, 1); -} -#endif /* unused */ - - -static int host_command2(struct sscape_info *devc, int cmd, int parm1) -{ - unsigned char buf[10]; - - buf[0] = (unsigned char) (cmd & 0xff); - buf[1] = (unsigned char) (parm1 & 0xff); - - return host_write(devc, buf, 2); -} - -static int host_command3(struct sscape_info *devc, int cmd, int parm1, int parm2) -{ - unsigned char buf[10]; - - buf[0] = (unsigned char) (cmd & 0xff); - buf[1] = (unsigned char) (parm1 & 0xff); - buf[2] = (unsigned char) (parm2 & 0xff); - return host_write(devc, buf, 3); -} - -static void set_mt32(struct sscape_info *devc, int value) -{ - host_open(devc); - host_command2(devc, CMD_SET_MT32, value ? 1 : 0); - if (host_read(devc) != CMD_ACK) - { - /* printk( "SNDSCAPE: Setting MT32 mode failed\n"); */ - } - host_close(devc); -} - -static void set_control(struct sscape_info *devc, int ctrl, int value) -{ - host_open(devc); - host_command3(devc, CMD_SET_CONTROL, ctrl, value); - if (host_read(devc) != CMD_ACK) - { - /* printk( "SNDSCAPE: Setting control (%d) failed\n", ctrl); */ - } - host_close(devc); -} - -static void do_dma(struct sscape_info *devc, int dma_chan, unsigned long buf, int blk_size, int mode) -{ - unsigned char temp; - - if (dma_chan != SSCAPE_DMA_A) - { - printk(KERN_WARNING "soundscape: Tried to use DMA channel != A. Why?\n"); - return; - } - audio_devs[devc->codec_audiodev]->flags &= ~DMA_AUTOMODE; - DMAbuf_start_dma(devc->codec_audiodev, buf, blk_size, mode); - audio_devs[devc->codec_audiodev]->flags |= DMA_AUTOMODE; - - temp = devc->dma << 4; /* Setup DMA channel select bits */ - if (devc->dma <= 3) - temp |= 0x80; /* 8 bit DMA channel */ - - temp |= 1; /* Trigger DMA */ - sscape_write(devc, GA_DMAA_REG, temp); - temp &= 0xfe; /* Clear DMA trigger */ - sscape_write(devc, GA_DMAA_REG, temp); -} - -static int verify_mpu(struct sscape_info *devc) -{ - /* - * The SoundScape board could be in three modes (MPU, 8250 and host). - * If the card is not in the MPU mode, enabling the MPU driver will - * cause infinite loop (the driver believes that there is always some - * received data in the buffer. - * - * Detect this by looking if there are more than 10 received MIDI bytes - * (0x00) in the buffer. - */ - - int i; - - for (i = 0; i < 10; i++) - { - if (inb(devc->base + HOST_CTRL) & 0x80) - return 1; - - if (inb(devc->base) != 0x00) - return 1; - } - printk(KERN_WARNING "SoundScape: The device is not in the MPU-401 mode\n"); - return 0; -} - -static int sscape_coproc_open(void *dev_info, int sub_device) -{ - if (sub_device == COPR_MIDI) - { - set_mt32(devc, 0); - if (!verify_mpu(devc)) - return -EIO; - } - return 0; -} - -static void sscape_coproc_close(void *dev_info, int sub_device) -{ - struct sscape_info *devc = dev_info; - unsigned long flags; - - spin_lock_irqsave(&devc->lock,flags); - if (devc->dma_allocated) - { - __sscape_write(GA_DMAA_REG, 0x20); /* DMA channel disabled */ - devc->dma_allocated = 0; - } - spin_unlock_irqrestore(&devc->lock,flags); - return; -} - -static void sscape_coproc_reset(void *dev_info) -{ -} - -static int sscape_download_boot(struct sscape_info *devc, unsigned char *block, int size, int flag) -{ - unsigned long flags; - unsigned char temp; - volatile int done, timeout_val; - static unsigned char codec_dma_bits; - - if (flag & CPF_FIRST) - { - /* - * First block. Have to allocate DMA and to reset the board - * before continuing. - */ - - spin_lock_irqsave(&devc->lock,flags); - codec_dma_bits = sscape_read(devc, GA_CDCFG_REG); - - if (devc->dma_allocated == 0) - devc->dma_allocated = 1; - - spin_unlock_irqrestore(&devc->lock,flags); - - sscape_write(devc, GA_HMCTL_REG, - (temp = sscape_read(devc, GA_HMCTL_REG)) & 0x3f); /*Reset */ - - for (timeout_val = 10000; timeout_val > 0; timeout_val--) - sscape_read(devc, GA_HMCTL_REG); /* Delay */ - - /* Take board out of reset */ - sscape_write(devc, GA_HMCTL_REG, - (temp = sscape_read(devc, GA_HMCTL_REG)) | 0x80); - } - /* - * Transfer one code block using DMA - */ - if (audio_devs[devc->codec_audiodev]->dmap_out->raw_buf == NULL) - { - printk(KERN_WARNING "soundscape: DMA buffer not available\n"); - return 0; - } - memcpy(audio_devs[devc->codec_audiodev]->dmap_out->raw_buf, block, size); - - spin_lock_irqsave(&devc->lock,flags); - - /******** INTERRUPTS DISABLED NOW ********/ - - do_dma(devc, SSCAPE_DMA_A, - audio_devs[devc->codec_audiodev]->dmap_out->raw_buf_phys, - size, DMA_MODE_WRITE); - - /* - * Wait until transfer completes. - */ - - done = 0; - timeout_val = 30; - while (!done && timeout_val-- > 0) - { - int resid; - - if (HZ / 50) - sleep(HZ / 50); - clear_dma_ff(devc->dma); - if ((resid = get_dma_residue(devc->dma)) == 0) - done = 1; - } - - spin_unlock_irqrestore(&devc->lock,flags); - if (!done) - return 0; - - if (flag & CPF_LAST) - { - /* - * Take the board out of reset - */ - outb((0x00), PORT(HOST_CTRL)); - outb((0x00), PORT(MIDI_CTRL)); - - temp = sscape_read(devc, GA_HMCTL_REG); - temp |= 0x40; - sscape_write(devc, GA_HMCTL_REG, temp); /* Kickstart the board */ - - /* - * Wait until the ODB wakes up - */ - spin_lock_irqsave(&devc->lock,flags); - done = 0; - timeout_val = 5 * HZ; - while (!done && timeout_val-- > 0) - { - unsigned char x; - - sleep(1); - x = inb(PORT(HOST_DATA)); - if (x == 0xff || x == 0xfe) /* OBP startup acknowledge */ - { - DDB(printk("Soundscape: Acknowledge = %x\n", x)); - done = 1; - } - } - sscape_write(devc, GA_CDCFG_REG, codec_dma_bits); - - spin_unlock_irqrestore(&devc->lock,flags); - if (!done) - { - printk(KERN_ERR "soundscape: The OBP didn't respond after code download\n"); - return 0; - } - spin_lock_irqsave(&devc->lock,flags); - done = 0; - timeout_val = 5 * HZ; - while (!done && timeout_val-- > 0) - { - sleep(1); - if (inb(PORT(HOST_DATA)) == 0xfe) /* Host startup acknowledge */ - done = 1; - } - spin_unlock_irqrestore(&devc->lock,flags); - if (!done) - { - printk(KERN_ERR "soundscape: OBP Initialization failed.\n"); - return 0; - } - printk(KERN_INFO "SoundScape board initialized OK\n"); - set_control(devc, CTL_MASTER_VOL, 100); - set_control(devc, CTL_SYNTH_VOL, 100); - -#ifdef SSCAPE_DEBUG3 - /* - * Temporary debugging aid. Print contents of the registers after - * downloading the code. - */ - { - int i; - - for (i = 0; i < 13; i++) - printk("I%d = %02x (new value)\n", i, sscape_read(devc, i)); - } -#endif - - } - return 1; -} - -static int download_boot_block(void *dev_info, copr_buffer * buf) -{ - if (buf->len <= 0 || buf->len > sizeof(buf->data)) - return -EINVAL; - - if (!sscape_download_boot(devc, buf->data, buf->len, buf->flags)) - { - printk(KERN_ERR "soundscape: Unable to load microcode block to the OBP.\n"); - return -EIO; - } - return 0; -} - -static int sscape_coproc_ioctl(void *dev_info, unsigned int cmd, void __user *arg, int local) -{ - copr_buffer *buf; - int err; - - switch (cmd) - { - case SNDCTL_COPR_RESET: - sscape_coproc_reset(dev_info); - return 0; - - case SNDCTL_COPR_LOAD: - buf = (copr_buffer *) vmalloc(sizeof(copr_buffer)); - if (buf == NULL) - return -ENOSPC; - if (copy_from_user(buf, arg, sizeof(copr_buffer))) - { - vfree(buf); - return -EFAULT; - } - err = download_boot_block(dev_info, buf); - vfree(buf); - return err; - - default: - return -EINVAL; - } -} - -static coproc_operations sscape_coproc_operations = -{ - "SoundScape M68K", - THIS_MODULE, - sscape_coproc_open, - sscape_coproc_close, - sscape_coproc_ioctl, - sscape_coproc_reset, - &adev_info -}; - -static struct resource *sscape_ports; -static int sscape_is_pnp; - -static void __init attach_sscape(struct address_info *hw_config) -{ -#ifndef SSCAPE_REGS - /* - * Config register values for Spea/V7 Media FX and Ensoniq S-2000. - * These values are card - * dependent. If you have another SoundScape based card, you have to - * find the correct values. Do the following: - * - Compile this driver with SSCAPE_DEBUG1 defined. - * - Shut down and power off your machine. - * - Boot with DOS so that the SSINIT.EXE program is run. - * - Warm boot to {Linux|SYSV|BSD} and write down the lines displayed - * when detecting the SoundScape. - * - Modify the following list to use the values printed during boot. - * Undefine the SSCAPE_DEBUG1 - */ -#define SSCAPE_REGS { \ -/* I0 */ 0x00, \ -/* I1 */ 0xf0, /* Note! Ignored. Set always to 0xf0 */ \ -/* I2 */ 0x20, /* Note! Ignored. Set always to 0x20 */ \ -/* I3 */ 0x20, /* Note! Ignored. Set always to 0x20 */ \ -/* I4 */ 0xf5, /* Ignored */ \ -/* I5 */ 0x10, \ -/* I6 */ 0x00, \ -/* I7 */ 0x2e, /* I7 MEM config A. Likely to vary between models */ \ -/* I8 */ 0x00, /* I8 MEM config B. Likely to vary between models */ \ -/* I9 */ 0x40 /* Ignored */ \ - } -#endif - - unsigned long flags; - static unsigned char regs[10] = SSCAPE_REGS; - - int i, irq_bits = 0xff; - - if (old_hardware) - { - valid_interrupts = valid_interrupts_old; - conf_printf("Ensoniq SoundScape (old)", hw_config); - } - else - conf_printf("Ensoniq SoundScape", hw_config); - - for (i = 0; i < 4; i++) - { - if (hw_config->irq == valid_interrupts[i]) - { - irq_bits = i; - break; - } - } - if (hw_config->irq > 15 || (regs[4] = irq_bits == 0xff)) - { - printk(KERN_ERR "Invalid IRQ%d\n", hw_config->irq); - release_region(devc->base, 2); - release_region(devc->base + 2, 6); - if (sscape_is_pnp) - release_region(devc->codec, 2); - return; - } - - if (!sscape_is_pnp) { - - spin_lock_irqsave(&devc->lock,flags); - /* Host interrupt enable */ - sscape_write(devc, 1, 0xf0); /* All interrupts enabled */ - /* DMA A status/trigger register */ - sscape_write(devc, 2, 0x20); /* DMA channel disabled */ - /* DMA B status/trigger register */ - sscape_write(devc, 3, 0x20); /* DMA channel disabled */ - /* Host interrupt config reg */ - sscape_write(devc, 4, 0xf0 | (irq_bits << 2) | irq_bits); - /* Don't destroy CD-ROM DMA config bits (0xc0) */ - sscape_write(devc, 5, (regs[5] & 0x3f) | (sscape_read(devc, 5) & 0xc0)); - /* CD-ROM config (WSS codec actually) */ - sscape_write(devc, 6, regs[6]); - sscape_write(devc, 7, regs[7]); - sscape_write(devc, 8, regs[8]); - /* Master control reg. Don't modify CR-ROM bits. Disable SB emul */ - sscape_write(devc, 9, (sscape_read(devc, 9) & 0xf0) | 0x08); - spin_unlock_irqrestore(&devc->lock,flags); - } -#ifdef SSCAPE_DEBUG2 - /* - * Temporary debugging aid. Print contents of the registers after - * changing them. - */ - { - int i; - - for (i = 0; i < 13; i++) - printk("I%d = %02x (new value)\n", i, sscape_read(devc, i)); - } -#endif - - if (probe_mpu401(hw_config, sscape_ports)) - hw_config->always_detect = 1; - hw_config->name = "SoundScape"; - - hw_config->irq *= -1; /* Negative value signals IRQ sharing */ - attach_mpu401(hw_config, THIS_MODULE); - hw_config->irq *= -1; /* Restore it */ - - if (hw_config->slots[1] != -1) /* The MPU driver installed itself */ - { - sscape_mididev = hw_config->slots[1]; - midi_devs[hw_config->slots[1]]->coproc = &sscape_coproc_operations; - } - sscape_write(devc, GA_INTENA_REG, 0x80); /* Master IRQ enable */ - devc->ok = 1; - devc->failed = 0; -} - -static int detect_ga(sscape_info * devc) -{ - unsigned char save; - - DDB(printk("Entered Soundscape detect_ga(%x)\n", devc->base)); - - /* - * First check that the address register of "ODIE" is - * there and that it has exactly 4 writable bits. - * First 4 bits - */ - - if ((save = inb(PORT(ODIE_ADDR))) & 0xf0) - { - DDB(printk("soundscape: Detect error A\n")); - return 0; - } - outb((0x00), PORT(ODIE_ADDR)); - if (inb(PORT(ODIE_ADDR)) != 0x00) - { - DDB(printk("soundscape: Detect error B\n")); - return 0; - } - outb((0xff), PORT(ODIE_ADDR)); - if (inb(PORT(ODIE_ADDR)) != 0x0f) - { - DDB(printk("soundscape: Detect error C\n")); - return 0; - } - outb((save), PORT(ODIE_ADDR)); - - /* - * Now verify that some indirect registers return zero on some bits. - * This may break the driver with some future revisions of "ODIE" but... - */ - - if (sscape_read(devc, 0) & 0x0c) - { - DDB(printk("soundscape: Detect error D (%x)\n", sscape_read(devc, 0))); - return 0; - } - if (sscape_read(devc, 1) & 0x0f) - { - DDB(printk("soundscape: Detect error E\n")); - return 0; - } - if (sscape_read(devc, 5) & 0x0f) - { - DDB(printk("soundscape: Detect error F\n")); - return 0; - } - return 1; -} - -static int sscape_read_host_ctrl(sscape_info* devc) -{ - return host_read(devc); -} - -static void sscape_write_host_ctrl2(sscape_info *devc, int a, int b) -{ - host_command2(devc, a, b); -} - -static int sscape_alloc_dma(sscape_info *devc) -{ - char *start_addr, *end_addr; - int dma_pagesize; - int sz, size; - struct page *page; - - if (devc->raw_buf != NULL) return 0; /* Already done */ - dma_pagesize = (devc->dma < 4) ? (64 * 1024) : (128 * 1024); - devc->raw_buf = NULL; - devc->buffsize = 8192*4; - if (devc->buffsize > dma_pagesize) devc->buffsize = dma_pagesize; - start_addr = NULL; - /* - * Now loop until we get a free buffer. Try to get smaller buffer if - * it fails. Don't accept smaller than 8k buffer for performance - * reasons. - */ - while (start_addr == NULL && devc->buffsize > PAGE_SIZE) { - for (sz = 0, size = PAGE_SIZE; size < devc->buffsize; sz++, size <<= 1); - devc->buffsize = PAGE_SIZE * (1 << sz); - start_addr = (char *) __get_free_pages(GFP_ATOMIC|GFP_DMA, sz); - if (start_addr == NULL) devc->buffsize /= 2; - } - - if (start_addr == NULL) { - printk(KERN_ERR "sscape pnp init error: Couldn't allocate DMA buffer\n"); - return 0; - } else { - /* make some checks */ - end_addr = start_addr + devc->buffsize - 1; - /* now check if it fits into the same dma-pagesize */ - - if (((long) start_addr & ~(dma_pagesize - 1)) != ((long) end_addr & ~(dma_pagesize - 1)) - || end_addr >= (char *) (MAX_DMA_ADDRESS)) { - printk(KERN_ERR "sscape pnp: Got invalid address 0x%lx for %db DMA-buffer\n", (long) start_addr, devc->buffsize); - return 0; - } - } - devc->raw_buf = start_addr; - devc->raw_buf_phys = virt_to_bus(start_addr); - - for (page = virt_to_page(start_addr); page <= virt_to_page(end_addr); page++) - SetPageReserved(page); - return 1; -} - -static void sscape_free_dma(sscape_info *devc) -{ - int sz, size; - unsigned long start_addr, end_addr; - struct page *page; - - if (devc->raw_buf == NULL) return; - for (sz = 0, size = PAGE_SIZE; size < devc->buffsize; sz++, size <<= 1); - start_addr = (unsigned long) devc->raw_buf; - end_addr = start_addr + devc->buffsize; - - for (page = virt_to_page(start_addr); page <= virt_to_page(end_addr); page++) - ClearPageReserved(page); - - free_pages((unsigned long) devc->raw_buf, sz); - devc->raw_buf = NULL; -} - -/* Intel version !!!!!!!!! */ - -static int sscape_start_dma(int chan, unsigned long physaddr, int count, int dma_mode) -{ - unsigned long flags; - - flags = claim_dma_lock(); - disable_dma(chan); - clear_dma_ff(chan); - set_dma_mode(chan, dma_mode); - set_dma_addr(chan, physaddr); - set_dma_count(chan, count); - enable_dma(chan); - release_dma_lock(flags); - return 0; -} - -static void sscape_pnp_start_dma(sscape_info* devc, int arg ) -{ - int reg; - if (arg == 0) reg = 2; - else reg = 3; - - sscape_write(devc, reg, sscape_read( devc, reg) | 0x01); - sscape_write(devc, reg, sscape_read( devc, reg) & 0xFE); -} - -static int sscape_pnp_wait_dma (sscape_info* devc, int arg ) -{ - int reg; - unsigned long i; - unsigned char d; - - if (arg == 0) reg = 2; - else reg = 3; - - sleep ( 1 ); - i = 0; - do { - d = sscape_read(devc, reg) & 1; - if ( d == 1) break; - i++; - } while (i < 500000); - d = sscape_read(devc, reg) & 1; - return d; -} - -static int sscape_pnp_alloc_dma(sscape_info* devc) -{ - /* printk(KERN_INFO "sscape: requesting dma\n"); */ - if (request_dma(devc -> dma, "sscape")) return 0; - /* printk(KERN_INFO "sscape: dma channel allocated\n"); */ - if (!sscape_alloc_dma(devc)) { - free_dma(devc -> dma); - return 0; - }; - return 1; -} - -static void sscape_pnp_free_dma(sscape_info* devc) -{ - sscape_free_dma( devc); - free_dma(devc -> dma ); - /* printk(KERN_INFO "sscape: dma released\n"); */ -} - -static int sscape_pnp_upload_file(sscape_info* devc, char* fn) -{ - int done = 0; - int timeout_val; - char* data,*dt; - int len,l; - unsigned long flags; - - sscape_write( devc, 9, sscape_read(devc, 9 ) & 0x3F ); - sscape_write( devc, 2, (devc -> dma << 4) | 0x80 ); - sscape_write( devc, 3, 0x20 ); - sscape_write( devc, 9, sscape_read( devc, 9 ) | 0x80 ); - - len = mod_firmware_load(fn, &data); - if (len == 0) { - printk(KERN_ERR "sscape: file not found: %s\n", fn); - return 0; - } - dt = data; - spin_lock_irqsave(&devc->lock,flags); - while ( len > 0 ) { - if (len > devc -> buffsize) l = devc->buffsize; - else l = len; - len -= l; - memcpy(devc->raw_buf, dt, l); dt += l; - sscape_start_dma(devc->dma, devc->raw_buf_phys, l, 0x48); - sscape_pnp_start_dma ( devc, 0 ); - if (sscape_pnp_wait_dma ( devc, 0 ) == 0) { - spin_unlock_irqrestore(&devc->lock,flags); - return 0; - } - } - - spin_unlock_irqrestore(&devc->lock,flags); - vfree(data); - - outb(0, devc -> base + 2); - outb(0, devc -> base); - - sscape_write ( devc, 9, sscape_read( devc, 9 ) | 0x40); - - timeout_val = 5 * HZ; - while (!done && timeout_val-- > 0) - { - unsigned char x; - sleep(1); - x = inb( devc -> base + 3); - if (x == 0xff || x == 0xfe) /* OBP startup acknowledge */ - { - //printk(KERN_ERR "Soundscape: Acknowledge = %x\n", x); - done = 1; - } - } - timeout_val = 5 * HZ; - done = 0; - while (!done && timeout_val-- > 0) - { - unsigned char x; - sleep(1); - x = inb( devc -> base + 3); - if (x == 0xfe) /* OBP startup acknowledge */ - { - //printk(KERN_ERR "Soundscape: Acknowledge = %x\n", x); - done = 1; - } - } - - if ( !done ) printk(KERN_ERR "soundscape: OBP Initialization failed.\n"); - - sscape_write( devc, 2, devc->ic_type == IC_ODIE ? 0x70 : 0x40); - sscape_write( devc, 3, (devc -> dma << 4) + 0x80); - return 1; -} - -static void __init sscape_pnp_init_hw(sscape_info* devc) -{ - unsigned char midi_irq = 0, sb_irq = 0; - unsigned i; - static char code_file_name[23] = "/sndscape/sndscape.cox"; - - int sscape_joystic_enable = 0x7f; - int sscape_mic_enable = 0; - int sscape_ext_midi = 0; - - if ( !sscape_pnp_alloc_dma(devc) ) { - printk(KERN_ERR "sscape: faild to allocate dma\n"); - return; - } - - for (i = 0; i < 4; i++) { - if ( devc -> irq == valid_interrupts[i] ) - midi_irq = i; - if ( devc -> codec_irq == valid_interrupts[i] ) - sb_irq = i; - } - - sscape_write( devc, 5, 0x50); - sscape_write( devc, 7, 0x2e); - sscape_write( devc, 8, 0x00); - - sscape_write( devc, 2, devc->ic_type == IC_ODIE ? 0x70 : 0x40); - sscape_write( devc, 3, ( devc -> dma << 4) | 0x80); - - sscape_write (devc, 4, 0xF0 | (midi_irq<<2) | midi_irq); - - i = 0x10; //sscape_read(devc, 9) & (devc->ic_type == IC_ODIE ? 0xf0 : 0xc0); - if (sscape_joystic_enable) i |= 8; - - sscape_write (devc, 9, i); - sscape_write (devc, 6, 0x80); - sscape_write (devc, 1, 0x80); - - if (devc -> codec_type == 2) { - sscape_pnp_write_codec( devc, 0x0C, 0x50); - sscape_pnp_write_codec( devc, 0x10, sscape_pnp_read_codec( devc, 0x10) & 0x3F); - sscape_pnp_write_codec( devc, 0x11, sscape_pnp_read_codec( devc, 0x11) | 0xC0); - sscape_pnp_write_codec( devc, 29, 0x20); - } - - if (sscape_pnp_upload_file(devc, "/sndscape/scope.cod") == 0 ) { - printk(KERN_ERR "sscape: faild to upload file /sndscape/scope.cod\n"); - sscape_pnp_free_dma(devc); - return; - } - - i = sscape_read_host_ctrl( devc ); - - if ( (i & 0x0F) > 7 ) { - printk(KERN_ERR "sscape: scope.cod faild\n"); - sscape_pnp_free_dma(devc); - return; - } - if ( i & 0x10 ) sscape_write( devc, 7, 0x2F); - code_file_name[21] = (char) ( i & 0x0F) + 0x30; - if (sscape_pnp_upload_file( devc, code_file_name) == 0) { - printk(KERN_ERR "sscape: faild to upload file %s\n", code_file_name); - sscape_pnp_free_dma(devc); - return; - } - - if (devc->ic_type != IC_ODIE) { - sscape_pnp_write_codec( devc, 10, (sscape_pnp_read_codec(devc, 10) & 0x7f) | - ( sscape_mic_enable == 0 ? 0x00 : 0x80) ); - } - sscape_write_host_ctrl2( devc, 0x84, 0x64 ); /* MIDI volume */ - sscape_write_host_ctrl2( devc, 0x86, 0x64 ); /* MIDI volume?? */ - sscape_write_host_ctrl2( devc, 0x8A, sscape_ext_midi); - - sscape_pnp_write_codec ( devc, 6, 0x3f ); //WAV_VOL - sscape_pnp_write_codec ( devc, 7, 0x3f ); //WAV_VOL - sscape_pnp_write_codec ( devc, 2, 0x1F ); //WD_CDXVOLL - sscape_pnp_write_codec ( devc, 3, 0x1F ); //WD_CDXVOLR - - if (devc -> codec_type == 1) { - sscape_pnp_write_codec ( devc, 4, 0x1F ); - sscape_pnp_write_codec ( devc, 5, 0x1F ); - sscape_write_host_ctrl2( devc, 0x88, sscape_mic_enable); - } else { - int t; - sscape_pnp_write_codec ( devc, 0x10, 0x1F << 1); - sscape_pnp_write_codec ( devc, 0x11, 0xC0 | (0x1F << 1)); - - t = sscape_pnp_read_codec( devc, 0x00) & 0xDF; - if ( (sscape_mic_enable == 0)) t |= 0; - else t |= 0x20; - sscape_pnp_write_codec ( devc, 0x00, t); - t = sscape_pnp_read_codec( devc, 0x01) & 0xDF; - if ( (sscape_mic_enable == 0) ) t |= 0; - else t |= 0x20; - sscape_pnp_write_codec ( devc, 0x01, t); - sscape_pnp_write_codec ( devc, 0x40 | 29 , 0x20); - outb(0, devc -> codec); - } - if (devc -> ic_type == IC_OPUS ) { - int i = sscape_read( devc, 9 ); - sscape_write( devc, 9, i | 3 ); - sscape_write( devc, 3, 0x40); - - if (request_region(0x228, 1, "sscape setup junk")) { - outb(0, 0x228); - release_region(0x228,1); - } - sscape_write( devc, 3, (devc -> dma << 4) | 0x80); - sscape_write( devc, 9, i ); - } - - host_close ( devc ); - sscape_pnp_free_dma(devc); -} - -static int __init detect_sscape_pnp(sscape_info* devc) -{ - long i, irq_bits = 0xff; - unsigned int d; - - DDB(printk("Entered detect_sscape_pnp(%x)\n", devc->base)); - - if (!request_region(devc->codec, 2, "sscape codec")) { - printk(KERN_ERR "detect_sscape_pnp: port %x is not free\n", devc->codec); - return 0; - } - - if ((inb(devc->base + 2) & 0x78) != 0) - goto fail; - - d = inb ( devc -> base + 4) & 0xF0; - if (d & 0x80) - goto fail; - - if (d == 0) { - devc->codec_type = 1; - devc->ic_type = IC_ODIE; - } else if ( (d & 0x60) != 0) { - devc->codec_type = 2; - devc->ic_type = IC_OPUS; - } else if ( (d & 0x40) != 0) { /* WTF? */ - devc->codec_type = 2; - devc->ic_type = IC_ODIE; - } else - goto fail; - - sscape_is_pnp = 1; - - outb(0xFA, devc -> base+4); - if ((inb( devc -> base+4) & 0x9F) != 0x0A) - goto fail; - outb(0xFE, devc -> base+4); - if ( (inb(devc -> base+4) & 0x9F) != 0x0E) - goto fail; - if ( (inb(devc -> base+5) & 0x9F) != 0x0E) - goto fail; - - if (devc->codec_type == 2) { - if (devc->codec != devc->base + 8) { - printk("soundscape warning: incorrect codec port specified\n"); - goto fail; - } - d = 0x10 | (sscape_read(devc, 9) & 0xCF); - sscape_write(devc, 9, d); - sscape_write(devc, 6, 0x80); - } else { - //todo: check codec is not base + 8 - } - - d = (sscape_read(devc, 9) & 0x3F) | 0xC0; - sscape_write(devc, 9, d); - - for (i = 0; i < 550000; i++) - if ( !(inb(devc -> codec) & 0x80) ) break; - - d = inb(devc -> codec); - if (d & 0x80) - goto fail; - if ( inb(devc -> codec + 2) == 0xFF) - goto fail; - - sscape_write(devc, 9, sscape_read(devc, 9) & 0x3F ); - - d = inb(devc -> codec) & 0x80; - if ( d == 0) { - printk(KERN_INFO "soundscape: hardware detected\n"); - valid_interrupts = valid_interrupts_new; - } else { - printk(KERN_INFO "soundscape: board looks like media fx\n"); - valid_interrupts = valid_interrupts_old; - old_hardware = 1; - } - - sscape_write( devc, 9, 0xC0 | (sscape_read(devc, 9) & 0x3F) ); - - for (i = 0; i < 550000; i++) - if ( !(inb(devc -> codec) & 0x80)) - break; - - sscape_pnp_init_hw(devc); - - for (i = 0; i < 4; i++) - { - if (devc->codec_irq == valid_interrupts[i]) { - irq_bits = i; - break; - } - } - sscape_write(devc, GA_INTENA_REG, 0x00); - sscape_write(devc, GA_DMACFG_REG, 0x50); - sscape_write(devc, GA_DMAA_REG, 0x70); - sscape_write(devc, GA_DMAB_REG, 0x20); - sscape_write(devc, GA_INTCFG_REG, 0xf0); - sscape_write(devc, GA_CDCFG_REG, 0x89 | (devc->dma << 4) | (irq_bits << 1)); - - sscape_pnp_write_codec( devc, 0, sscape_pnp_read_codec( devc, 0) | 0x20); - sscape_pnp_write_codec( devc, 0, sscape_pnp_read_codec( devc, 1) | 0x20); - - return 1; -fail: - release_region(devc->codec, 2); - return 0; -} - -static int __init probe_sscape(struct address_info *hw_config) -{ - devc->base = hw_config->io_base; - devc->irq = hw_config->irq; - devc->dma = hw_config->dma; - devc->osp = hw_config->osp; - -#ifdef SSCAPE_DEBUG1 - /* - * Temporary debugging aid. Print contents of the registers before - * changing them. - */ - { - int i; - - for (i = 0; i < 13; i++) - printk("I%d = %02x (old value)\n", i, sscape_read(devc, i)); - } -#endif - devc->failed = 1; - - sscape_ports = request_region(devc->base, 2, "mpu401"); - if (!sscape_ports) - return 0; - - if (!request_region(devc->base + 2, 6, "SoundScape")) { - release_region(devc->base, 2); - return 0; - } - - if (!detect_ga(devc)) { - if (detect_sscape_pnp(devc)) - return 1; - release_region(devc->base, 2); - release_region(devc->base + 2, 6); - return 0; - } - - if (old_hardware) /* Check that it's really an old Spea/Reveal card. */ - { - unsigned char tmp; - int cc; - - if (!((tmp = sscape_read(devc, GA_HMCTL_REG)) & 0xc0)) - { - sscape_write(devc, GA_HMCTL_REG, tmp | 0x80); - for (cc = 0; cc < 200000; ++cc) - inb(devc->base + ODIE_ADDR); - } - } - return 1; -} - -static int __init init_ss_ms_sound(struct address_info *hw_config) -{ - int i, irq_bits = 0xff; - int ad_flags = 0; - struct resource *ports; - - if (devc->failed) - { - printk(KERN_ERR "soundscape: Card not detected\n"); - return 0; - } - if (devc->ok == 0) - { - printk(KERN_ERR "soundscape: Invalid initialization order.\n"); - return 0; - } - for (i = 0; i < 4; i++) - { - if (hw_config->irq == valid_interrupts[i]) - { - irq_bits = i; - break; - } - } - if (irq_bits == 0xff) { - printk(KERN_ERR "soundscape: Invalid MSS IRQ%d\n", hw_config->irq); - return 0; - } - - if (old_hardware) - ad_flags = 0x12345677; /* Tell that we may have a CS4248 chip (Spea-V7 Media FX) */ - else if (sscape_is_pnp) - ad_flags = 0x87654321; /* Tell that we have a soundscape pnp with 1845 chip */ - - ports = request_region(hw_config->io_base, 4, "ad1848"); - if (!ports) { - printk(KERN_ERR "soundscape: ports busy\n"); - return 0; - } - - if (!ad1848_detect(ports, &ad_flags, hw_config->osp)) { - release_region(hw_config->io_base, 4); - return 0; - } - - if (!sscape_is_pnp) /*pnp is already setup*/ - { - /* - * Setup the DMA polarity. - */ - sscape_write(devc, GA_DMACFG_REG, 0x50); - - /* - * Take the gate-array off of the DMA channel. - */ - sscape_write(devc, GA_DMAB_REG, 0x20); - - /* - * Init the AD1848 (CD-ROM) config reg. - */ - sscape_write(devc, GA_CDCFG_REG, 0x89 | (hw_config->dma << 4) | (irq_bits << 1)); - } - - if (hw_config->irq == devc->irq) - printk(KERN_WARNING "soundscape: Warning! The WSS mode can't share IRQ with MIDI\n"); - - hw_config->slots[0] = ad1848_init( - sscape_is_pnp ? "SoundScape" : "SoundScape PNP", - ports, - hw_config->irq, - hw_config->dma, - hw_config->dma, - 0, - devc->osp, - THIS_MODULE); - - - if (hw_config->slots[0] != -1) /* The AD1848 driver installed itself */ - { - audio_devs[hw_config->slots[0]]->coproc = &sscape_coproc_operations; - devc->codec_audiodev = hw_config->slots[0]; - devc->my_audiodev = hw_config->slots[0]; - - /* Set proper routings here (what are they) */ - AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_LINE); - } - -#ifdef SSCAPE_DEBUG5 - /* - * Temporary debugging aid. Print contents of the registers - * after the AD1848 device has been initialized. - */ - { - int i; - - for (i = 0; i < 13; i++) - printk("I%d = %02x\n", i, sscape_read(devc, i)); - } -#endif - return 1; -} - -static void __exit unload_sscape(struct address_info *hw_config) -{ - release_region(devc->base + 2, 6); - unload_mpu401(hw_config); - if (sscape_is_pnp) - release_region(devc->codec, 2); -} - -static void __exit unload_ss_ms_sound(struct address_info *hw_config) -{ - ad1848_unload(hw_config->io_base, - hw_config->irq, - devc->dma, - devc->dma, - 0); - sound_unload_audiodev(hw_config->slots[0]); -} - -static struct address_info cfg; -static struct address_info cfg_mpu; - -static int __initdata spea = -1; -static int mss = 0; -static int __initdata dma = -1; -static int __initdata irq = -1; -static int __initdata io = -1; -static int __initdata mpu_irq = -1; -static int __initdata mpu_io = -1; - -module_param(dma, int, 0); -module_param(irq, int, 0); -module_param(io, int, 0); -module_param(spea, int, 0); /* spea=0/1 set the old_hardware */ -module_param(mpu_irq, int, 0); -module_param(mpu_io, int, 0); -module_param(mss, int, 0); - -static int __init init_sscape(void) -{ - printk(KERN_INFO "Soundscape driver Copyright (C) by Hannu Savolainen 1993-1996\n"); - - cfg.irq = irq; - cfg.dma = dma; - cfg.io_base = io; - - cfg_mpu.irq = mpu_irq; - cfg_mpu.io_base = mpu_io; - /* WEH - Try to get right dma channel */ - cfg_mpu.dma = dma; - - devc->codec = cfg.io_base; - devc->codec_irq = cfg.irq; - devc->codec_type = 0; - devc->ic_type = 0; - devc->raw_buf = NULL; - spin_lock_init(&devc->lock); - - if (cfg.dma == -1 || cfg.irq == -1 || cfg.io_base == -1) { - printk(KERN_ERR "DMA, IRQ, and IO port must be specified.\n"); - return -EINVAL; - } - - if (cfg_mpu.irq == -1 && cfg_mpu.io_base != -1) { - printk(KERN_ERR "MPU_IRQ must be specified if MPU_IO is set.\n"); - return -EINVAL; - } - - if(spea != -1) { - old_hardware = spea; - printk(KERN_INFO "Forcing %s hardware support.\n", - spea?"new":"old"); - } - if (probe_sscape(&cfg_mpu) == 0) - return -ENODEV; - - attach_sscape(&cfg_mpu); - - mss = init_ss_ms_sound(&cfg); - - return 0; -} - -static void __exit cleanup_sscape(void) -{ - if (mss) - unload_ss_ms_sound(&cfg); - unload_sscape(&cfg_mpu); -} - -module_init(init_sscape); -module_exit(cleanup_sscape); - -#ifndef MODULE -static int __init setup_sscape(char *str) -{ - /* io, irq, dma, mpu_io, mpu_irq */ - int ints[6]; - - str = get_options(str, ARRAY_SIZE(ints), ints); - - io = ints[1]; - irq = ints[2]; - dma = ints[3]; - mpu_io = ints[4]; - mpu_irq = ints[5]; - - return 1; -} - -__setup("sscape=", setup_sscape); -#endif -MODULE_LICENSE("GPL"); diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 75c602b5b132..351654cf7b09 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -570,6 +570,7 @@ config SND_ICE1712 tristate "ICEnsemble ICE1712 (Envy24)" select SND_MPU401_UART select SND_AC97_CODEC + select BITREVERSE help Say Y here to include support for soundcards based on the ICE1712 (Envy24) chip. diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 78288dbfc17a..20cb60afb200 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -603,8 +603,8 @@ AC97_SINGLE("Tone Control - Treble", AC97_MASTER_TONE, 0, 15, 1) }; static const struct snd_kcontrol_new snd_ac97_controls_pc_beep[2] = { -AC97_SINGLE("PC Speaker Playback Switch", AC97_PC_BEEP, 15, 1, 1), -AC97_SINGLE("PC Speaker Playback Volume", AC97_PC_BEEP, 1, 15, 1) +AC97_SINGLE("Beep Playback Switch", AC97_PC_BEEP, 15, 1, 1), +AC97_SINGLE("Beep Playback Volume", AC97_PC_BEEP, 1, 15, 1) }; static const struct snd_kcontrol_new snd_ac97_controls_mic_boost = @@ -1393,7 +1393,7 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) } } - /* build PC Speaker controls */ + /* build Beep controls */ if (!(ac97->flags & AC97_HAS_NO_PC_BEEP) && ((ac97->flags & AC97_HAS_PC_BEEP) || snd_ac97_try_volume_mix(ac97, AC97_PC_BEEP))) { diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 7337abdbe4e3..139cf3b2b9d7 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -800,12 +800,12 @@ AC97_SINGLE("Mono Switch", AC97_MASTER_TONE, 7, 1, 1), AC97_SINGLE("Mono ZC Switch", AC97_MASTER_TONE, 6, 1, 0), AC97_SINGLE("Mono Volume", AC97_MASTER_TONE, 0, 31, 1), -AC97_SINGLE("PC Beep to Headphone Switch", AC97_AUX, 15, 1, 1), -AC97_SINGLE("PC Beep to Headphone Volume", AC97_AUX, 12, 7, 1), -AC97_SINGLE("PC Beep to Master Switch", AC97_AUX, 11, 1, 1), -AC97_SINGLE("PC Beep to Master Volume", AC97_AUX, 8, 7, 1), -AC97_SINGLE("PC Beep to Mono Switch", AC97_AUX, 7, 1, 1), -AC97_SINGLE("PC Beep to Mono Volume", AC97_AUX, 4, 7, 1), +AC97_SINGLE("Beep to Headphone Switch", AC97_AUX, 15, 1, 1), +AC97_SINGLE("Beep to Headphone Volume", AC97_AUX, 12, 7, 1), +AC97_SINGLE("Beep to Master Switch", AC97_AUX, 11, 1, 1), +AC97_SINGLE("Beep to Master Volume", AC97_AUX, 8, 7, 1), +AC97_SINGLE("Beep to Mono Switch", AC97_AUX, 7, 1, 1), +AC97_SINGLE("Beep to Mono Volume", AC97_AUX, 4, 7, 1), AC97_SINGLE("Voice to Headphone Switch", AC97_PCM, 15, 1, 1), AC97_SINGLE("Voice to Headphone Volume", AC97_PCM, 12, 7, 1), diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index 8451a0169f32..69867ace7860 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c @@ -830,8 +830,8 @@ static struct snd_kcontrol_new snd_azf3328_mixer_controls[] __devinitdata = { AZF3328_MIXER_SWITCH("Mic Boost (+20dB)", IDX_MIXER_MIC, 6, 0), AZF3328_MIXER_SWITCH("Line Playback Switch", IDX_MIXER_LINEIN, 15, 1), AZF3328_MIXER_VOL_STEREO("Line Playback Volume", IDX_MIXER_LINEIN, 0x1f, 1), - AZF3328_MIXER_SWITCH("PC Speaker Playback Switch", IDX_MIXER_PCBEEP, 15, 1), - AZF3328_MIXER_VOL_SPECIAL("PC Speaker Playback Volume", IDX_MIXER_PCBEEP, 0x0f, 1, 1), + AZF3328_MIXER_SWITCH("Beep Playback Switch", IDX_MIXER_PCBEEP, 15, 1), + AZF3328_MIXER_VOL_SPECIAL("Beep Playback Volume", IDX_MIXER_PCBEEP, 0x0f, 1, 1), AZF3328_MIXER_SWITCH("Video Playback Switch", IDX_MIXER_VIDEO, 15, 1), AZF3328_MIXER_VOL_STEREO("Video Playback Volume", IDX_MIXER_VIDEO, 0x1f, 1), AZF3328_MIXER_SWITCH("Aux Playback Switch", IDX_MIXER_AUX, 15, 1), diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index c8c6f437f5b3..8f443a9d61ec 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c @@ -792,8 +792,8 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu) "Phone Playback Volume", "Video Playback Switch", "Video Playback Volume", - "PC Speaker Playback Switch", - "PC Speaker Playback Volume", + "Beep Playback Switch", + "Beep Playback Volume", "Mono Output Select", "Capture Source", "Capture Switch", diff --git a/sound/pci/ca0106/ca0106_proc.c b/sound/pci/ca0106/ca0106_proc.c index c62b7d10ec61..15523e60351c 100644 --- a/sound/pci/ca0106/ca0106_proc.c +++ b/sound/pci/ca0106/ca0106_proc.c @@ -304,7 +304,7 @@ static void snd_ca0106_proc_reg_write32(struct snd_info_entry *entry, while (!snd_info_get_line(buffer, line, sizeof(line))) { if (sscanf(line, "%x %x", ®, &val) != 2) continue; - if ((reg < 0x40) && (reg >=0) && (val <= 0xffffffff) ) { + if (reg < 0x40 && val <= 0xffffffff) { spin_lock_irqsave(&emu->emu_lock, flags); outl(val, emu->port + (reg & 0xfffffffc)); spin_unlock_irqrestore(&emu->emu_lock, flags); @@ -405,7 +405,7 @@ static void snd_ca0106_proc_reg_write(struct snd_info_entry *entry, while (!snd_info_get_line(buffer, line, sizeof(line))) { if (sscanf(line, "%x %x %x", ®, &channel_id, &val) != 3) continue; - if ((reg < 0x80) && (reg >=0) && (val <= 0xffffffff) && (channel_id >=0) && (channel_id <= 3) ) + if (reg < 0x80 && val <= 0xffffffff && channel_id <= 3) snd_ca0106_ptr_write(emu, reg, channel_id, val); } } diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index ddcd4a9fd7e6..a312bae08f52 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c @@ -2302,7 +2302,7 @@ static struct snd_kcontrol_new snd_cmipci_mixers[] __devinitdata = { CMIPCI_SB_VOL_MONO("Mic Playback Volume", SB_DSP4_MIC_DEV, 3, 31), CMIPCI_SB_SW_MONO("Mic Playback Switch", 0), CMIPCI_DOUBLE("Mic Capture Switch", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 0, 0, 1, 0, 0), - CMIPCI_SB_VOL_MONO("PC Speaker Playback Volume", SB_DSP4_SPEAKER_DEV, 6, 3), + CMIPCI_SB_VOL_MONO("Beep Playback Volume", SB_DSP4_SPEAKER_DEV, 6, 3), CMIPCI_MIXER_VOL_STEREO("Aux Playback Volume", CM_REG_AUX_VOL, 4, 0, 15), CMIPCI_MIXER_SW_STEREO("Aux Playback Switch", CM_REG_MIXER2, CM_VAUXLM_SHIFT, CM_VAUXRM_SHIFT, 0), CMIPCI_MIXER_SW_STEREO("Aux Capture Switch", CM_REG_MIXER2, CM_RAUXLEN_SHIFT, CM_RAUXREN_SHIFT, 0), @@ -2310,7 +2310,7 @@ static struct snd_kcontrol_new snd_cmipci_mixers[] __devinitdata = { CMIPCI_MIXER_VOL_MONO("Mic Capture Volume", CM_REG_MIXER2, CM_VADMIC_SHIFT, 7), CMIPCI_SB_VOL_MONO("Phone Playback Volume", CM_REG_EXTENT_IND, 5, 7), CMIPCI_DOUBLE("Phone Playback Switch", CM_REG_EXTENT_IND, CM_REG_EXTENT_IND, 4, 4, 1, 0, 0), - CMIPCI_DOUBLE("PC Speaker Playback Switch", CM_REG_EXTENT_IND, CM_REG_EXTENT_IND, 3, 3, 1, 0, 0), + CMIPCI_DOUBLE("Beep Playback Switch", CM_REG_EXTENT_IND, CM_REG_EXTENT_IND, 3, 3, 1, 0, 0), CMIPCI_DOUBLE("Mic Boost Capture Switch", CM_REG_EXTENT_IND, CM_REG_EXTENT_IND, 0, 0, 1, 0, 0), }; diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c index 75454648d50c..cb65bd0dd35b 100644 --- a/sound/pci/ctxfi/ctatc.c +++ b/sound/pci/ctxfi/ctatc.c @@ -240,7 +240,7 @@ static int select_rom(unsigned int pitch) } else if (pitch == 0x02000000) { /* pitch == 2 */ return 3; - } else if (pitch >= 0x0 && pitch <= 0x08000000) { + } else if (pitch <= 0x08000000) { /* 0 <= pitch <= 8 */ return 0; } else { diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index 36e08bd2b3cc..6b8ae7b5cd54 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c @@ -1040,8 +1040,7 @@ static void snd_emu10k1x_proc_reg_write(struct snd_info_entry *entry, if (sscanf(line, "%x %x %x", ®, &channel_id, &val) != 3) continue; - if ((reg < 0x49) && (reg >= 0) && (val <= 0xffffffff) - && (channel_id >= 0) && (channel_id <= 2) ) + if (reg < 0x49 && val <= 0xffffffff && channel_id <= 2) snd_emu10k1x_ptr_write(emu, reg, channel_id, val); } } diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index b0fb6c917c38..05afe06e353a 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -1818,8 +1818,8 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, "Master Playback Switch", "Master Capture Switch", "Master Playback Volume", "Master Capture Volume", "Wave Master Playback Volume", "Master Playback Volume", - "PC Speaker Playback Switch", "PC Speaker Capture Switch", - "PC Speaker Playback Volume", "PC Speaker Capture Volume", + "Beep Playback Switch", "Beep Capture Switch", + "Beep Playback Volume", "Beep Capture Volume", "Phone Playback Switch", "Phone Capture Switch", "Phone Playback Volume", "Phone Capture Volume", "Mic Playback Switch", "Mic Capture Switch", diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c index 216f9748aff5..baa7cd508cd8 100644 --- a/sound/pci/emu10k1/emuproc.c +++ b/sound/pci/emu10k1/emuproc.c @@ -451,7 +451,7 @@ static void snd_emu_proc_io_reg_write(struct snd_info_entry *entry, while (!snd_info_get_line(buffer, line, sizeof(line))) { if (sscanf(line, "%x %x", ®, &val) != 2) continue; - if ((reg < 0x40) && (reg >= 0) && (val <= 0xffffffff) ) { + if (reg < 0x40 && val <= 0xffffffff) { spin_lock_irqsave(&emu->emu_lock, flags); outl(val, emu->port + (reg & 0xfffffffc)); spin_unlock_irqrestore(&emu->emu_lock, flags); @@ -527,7 +527,7 @@ static void snd_emu_proc_ptr_reg_write(struct snd_info_entry *entry, while (!snd_info_get_line(buffer, line, sizeof(line))) { if (sscanf(line, "%x %x %x", ®, &channel_id, &val) != 3) continue; - if ((reg < 0xa0) && (reg >= 0) && (val <= 0xffffffff) && (channel_id >= 0) && (channel_id <= 3) ) + if (reg < 0xa0 && val <= 0xffffffff && channel_id <= 3) snd_ptr_write(emu, iobase, reg, channel_id, val); } } diff --git a/sound/pci/emu10k1/io.c b/sound/pci/emu10k1/io.c index c1a5aa15af8f..5ef7080e14d0 100644 --- a/sound/pci/emu10k1/io.c +++ b/sound/pci/emu10k1/io.c @@ -256,7 +256,7 @@ int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, u32 reg, u32 value) if (reg > 0x3f) return 1; reg += 0x40; /* 0x40 upwards are registers. */ - if (value < 0 || value > 0x3f) /* 0 to 0x3f are values */ + if (value > 0x3f) /* 0 to 0x3f are values */ return 1; spin_lock_irqsave(&emu->emu_lock, flags); outl(reg, emu->port + A_IOCFG); diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c index 820318ee62c1..fb83e1ffa5cb 100644 --- a/sound/pci/es1938.c +++ b/sound/pci/es1938.c @@ -1387,7 +1387,7 @@ ES1938_DOUBLE_TLV("Aux Playback Volume", 0, 0x3a, 0x3a, 4, 0, 15, 0, db_scale_line), ES1938_DOUBLE_TLV("Capture Volume", 0, 0xb4, 0xb4, 4, 0, 15, 0, db_scale_capture), -ES1938_SINGLE("PC Speaker Volume", 0, 0x3c, 0, 7, 0), +ES1938_SINGLE("Beep Volume", 0, 0x3c, 0, 7, 0), ES1938_SINGLE("Record Monitor", 0, 0xa8, 3, 1, 0), ES1938_SINGLE("Capture Switch", 0, 0x1c, 4, 1, 1), { diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index 60cdb9e0b68d..83508b3964fb 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -55,7 +55,7 @@ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card * * 1 = MediaForte 256-PCS * 2 = MediaForte 256-PCPR * 3 = MediaForte 64-PCR - * 16 = setup tuner only (this is additional bit), i.e. SF-64-PCR FM card + * 16 = setup tuner only (this is additional bit), i.e. SF64-PCR FM card * High 16-bits are video (radio) device number + 1 */ static int tea575x_tuner[SNDRV_CARDS]; @@ -67,7 +67,10 @@ MODULE_PARM_DESC(id, "ID string for the FM801 soundcard."); module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "Enable FM801 soundcard."); module_param_array(tea575x_tuner, int, NULL, 0444); -MODULE_PARM_DESC(tea575x_tuner, "Enable TEA575x tuner."); +MODULE_PARM_DESC(tea575x_tuner, "TEA575x tuner access method (1 = SF256-PCS, 2=SF256-PCPR, 3=SF64-PCR, +16=tuner-only)."); + +#define TUNER_ONLY (1<<4) +#define TUNER_TYPE_MASK (~TUNER_ONLY & 0xFFFF) /* * Direct registers @@ -160,7 +163,7 @@ struct fm801 { unsigned int multichannel: 1, /* multichannel support */ secondary: 1; /* secondary codec */ unsigned char secondary_addr; /* address of the secondary codec */ - unsigned int tea575x_tuner; /* tuner flags */ + unsigned int tea575x_tuner; /* tuner access method & flags */ unsigned short ply_ctrl; /* playback control */ unsigned short cap_ctrl; /* capture control */ @@ -1287,7 +1290,7 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume) { unsigned short cmdw; - if (chip->tea575x_tuner & 0x0010) + if (chip->tea575x_tuner & TUNER_ONLY) goto __ac97_ok; /* codec cold reset + AC'97 warm reset */ @@ -1296,11 +1299,13 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume) udelay(100); outw(0, FM801_REG(chip, CODEC_CTRL)); - if (wait_for_codec(chip, 0, AC97_RESET, msecs_to_jiffies(750)) < 0) { - snd_printk(KERN_ERR "Primary AC'97 codec not found\n"); - if (! resume) - return -EIO; - } + if (wait_for_codec(chip, 0, AC97_RESET, msecs_to_jiffies(750)) < 0) + if (!resume) { + snd_printk(KERN_INFO "Primary AC'97 codec not found, " + "assume SF64-PCR (tuner-only)\n"); + chip->tea575x_tuner = 3 | TUNER_ONLY; + goto __ac97_ok; + } if (chip->multichannel) { if (chip->secondary_addr) { @@ -1414,7 +1419,7 @@ static int __devinit snd_fm801_create(struct snd_card *card, return err; } chip->port = pci_resource_start(pci, 0); - if ((tea575x_tuner & 0x0010) == 0) { + if ((tea575x_tuner & TUNER_ONLY) == 0) { if (request_irq(pci->irq, snd_fm801_interrupt, IRQF_SHARED, "FM801", chip)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", chip->irq); @@ -1429,6 +1434,14 @@ static int __devinit snd_fm801_create(struct snd_card *card, chip->multichannel = 1; snd_fm801_chip_init(chip, 0); + /* init might set tuner access method */ + tea575x_tuner = chip->tea575x_tuner; + + if (chip->irq >= 0 && (tea575x_tuner & TUNER_ONLY)) { + pci_clear_master(pci); + free_irq(chip->irq, chip); + chip->irq = -1; + } if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { snd_fm801_free(chip); @@ -1438,12 +1451,13 @@ static int __devinit snd_fm801_create(struct snd_card *card, snd_card_set_dev(card, &pci->dev); #ifdef TEA575X_RADIO - if (tea575x_tuner > 0 && (tea575x_tuner & 0x000f) < 4) { + if ((tea575x_tuner & TUNER_TYPE_MASK) > 0 && + (tea575x_tuner & TUNER_TYPE_MASK) < 4) { chip->tea.dev_nr = tea575x_tuner >> 16; chip->tea.card = card; chip->tea.freq_fixup = 10700; chip->tea.private_data = chip; - chip->tea.ops = &snd_fm801_tea_ops[(tea575x_tuner & 0x000f) - 1]; + chip->tea.ops = &snd_fm801_tea_ops[(tea575x_tuner & TUNER_TYPE_MASK) - 1]; snd_tea575x_init(&chip->tea); } #endif @@ -1483,7 +1497,7 @@ static int __devinit snd_card_fm801_probe(struct pci_dev *pci, sprintf(card->longname, "%s at 0x%lx, irq %i", card->shortname, chip->port, chip->irq); - if (tea575x_tuner[dev] & 0x0010) + if (chip->tea575x_tuner & TUNER_ONLY) goto __fm801_tuner_only; if ((err = snd_fm801_pcm(chip, 0, NULL)) < 0) { diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index e340792f6cb3..6517f589d01d 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -722,9 +722,10 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus, chip->last_cmd[addr]); chip->single_cmd = 1; bus->response_reset = 0; - /* re-initialize CORB/RIRB */ + /* release CORB/RIRB */ azx_free_cmd_io(chip); - azx_init_cmd_io(chip); + /* disable unsolicited responses */ + azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~ICH6_GCTL_UNSOL); return -1; } @@ -865,7 +866,9 @@ static int azx_reset(struct azx *chip) } /* Accept unsolicited responses */ - azx_writel(chip, GCTL, azx_readl(chip, GCTL) | ICH6_GCTL_UNSOL); + if (!chip->single_cmd) + azx_writel(chip, GCTL, azx_readl(chip, GCTL) | + ICH6_GCTL_UNSOL); /* detect codecs */ if (!chip->codec_mask) { @@ -980,7 +983,8 @@ static void azx_init_chip(struct azx *chip) azx_int_enable(chip); /* initialize the codec command I/O */ - azx_init_cmd_io(chip); + if (!chip->single_cmd) + azx_init_cmd_io(chip); /* program the position buffer */ azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr); diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index 780e1a72114a..85c81feb10cf 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c @@ -197,8 +197,8 @@ static struct snd_kcontrol_new cmi9880_basic_mixer[] = { HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x08, 0, HDA_INPUT), HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0, HDA_INPUT), - HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x23, 0, HDA_OUTPUT), - HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x23, 0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Beep Playback Volume", 0x23, 0, HDA_OUTPUT), + HDA_CODEC_MUTE("Beep Playback Switch", 0x23, 0, HDA_OUTPUT), { } /* end */ }; diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 3fbbc8c01e70..905859d4f4df 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -110,6 +110,7 @@ struct conexant_spec { unsigned int dell_automute; unsigned int port_d_mode; + unsigned char ext_mic_bias; }; static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo, @@ -1927,6 +1928,11 @@ static hda_nid_t cxt5066_adc_nids[3] = { 0x14, 0x15, 0x16 }; static hda_nid_t cxt5066_capsrc_nids[1] = { 0x17 }; #define CXT5066_SPDIF_OUT 0x21 +/* OLPC's microphone port is DC coupled for use with external sensors, + * therefore we use a 50% mic bias in order to center the input signal with + * the DC input range of the codec. */ +#define CXT5066_OLPC_EXT_MIC_BIAS PIN_VREF50 + static struct hda_channel_mode cxt5066_modes[1] = { { 2, NULL }, }; @@ -1980,9 +1986,10 @@ static int cxt5066_hp_master_sw_put(struct snd_kcontrol *kcontrol, /* toggle input of built-in and mic jack appropriately */ static void cxt5066_automic(struct hda_codec *codec) { - static struct hda_verb ext_mic_present[] = { + struct conexant_spec *spec = codec->spec; + struct hda_verb ext_mic_present[] = { /* enable external mic, port B */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, spec->ext_mic_bias}, /* switch to external mic input */ {0x17, AC_VERB_SET_CONNECT_SEL, 0}, @@ -2235,7 +2242,7 @@ static struct hda_verb cxt5066_init_verbs_olpc[] = { {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ /* Port B: external microphone */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, CXT5066_OLPC_EXT_MIC_BIAS}, /* Port C: internal microphone */ {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, @@ -2325,6 +2332,7 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = { CXT5066_LAPTOP), SND_PCI_QUIRK(0x1028, 0x02f5, "Dell", CXT5066_DELL_LAPTOP), + SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5), {} }; @@ -2352,6 +2360,7 @@ static int patch_cxt5066(struct hda_codec *codec) spec->input_mux = &cxt5066_capture_source; spec->port_d_mode = PIN_HP; + spec->ext_mic_bias = PIN_VREF80; spec->num_init_verbs = 1; spec->init_verbs[0] = cxt5066_init_verbs; @@ -2383,6 +2392,7 @@ static int patch_cxt5066(struct hda_codec *codec) spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc; spec->mixers[spec->num_mixers++] = cxt5066_mixers; spec->port_d_mode = 0; + spec->ext_mic_bias = CXT5066_OLPC_EXT_MIC_BIAS; /* no S/PDIF out */ spec->multiout.dig_out_nid = 0; diff --git a/sound/pci/hda/patch_nvhdmi.c b/sound/pci/hda/patch_nvhdmi.c index 9fb60276f5c9..6afdab09bab7 100644 --- a/sound/pci/hda/patch_nvhdmi.c +++ b/sound/pci/hda/patch_nvhdmi.c @@ -397,6 +397,7 @@ static int patch_nvhdmi_2ch(struct hda_codec *codec) static struct hda_codec_preset snd_hda_preset_nvhdmi[] = { { .id = 0x10de0002, .name = "MCP78 HDMI", .patch = patch_nvhdmi_8ch }, { .id = 0x10de0003, .name = "MCP78 HDMI", .patch = patch_nvhdmi_8ch }, + { .id = 0x10de0005, .name = "MCP78 HDMI", .patch = patch_nvhdmi_8ch }, { .id = 0x10de0006, .name = "MCP78 HDMI", .patch = patch_nvhdmi_8ch }, { .id = 0x10de0007, .name = "MCP7A HDMI", .patch = patch_nvhdmi_8ch }, { .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi_2ch }, @@ -406,6 +407,7 @@ static struct hda_codec_preset snd_hda_preset_nvhdmi[] = { MODULE_ALIAS("snd-hda-codec-id:10de0002"); MODULE_ALIAS("snd-hda-codec-id:10de0003"); +MODULE_ALIAS("snd-hda-codec-id:10de0005"); MODULE_ALIAS("snd-hda-codec-id:10de0006"); MODULE_ALIAS("snd-hda-codec-id:10de0007"); MODULE_ALIAS("snd-hda-codec-id:10de0067"); diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index ff20048504b6..24b07c9b6a8e 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4684,9 +4684,9 @@ static int alc880_parse_auto_config(struct hda_codec *codec) spec->multiout.dig_out_nid = dig_nid; else { spec->multiout.slave_dig_outs = spec->slave_dig_outs; - spec->slave_dig_outs[i - 1] = dig_nid; - if (i == ARRAY_SIZE(spec->slave_dig_outs) - 1) + if (i >= ARRAY_SIZE(spec->slave_dig_outs) - 1) break; + spec->slave_dig_outs[i - 1] = dig_nid; } } if (spec->autocfg.dig_in_pin) @@ -6249,7 +6249,7 @@ static struct snd_pci_quirk alc260_cfg_tbl[] = { SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER), SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FAVORIT100), SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013), - SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_HP_3013), + SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_AUTO), /* no quirk */ SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013), SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP_3013), SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_DC7600), @@ -7336,8 +7336,8 @@ static struct snd_kcontrol_new alc882_macpro_mixer[] = { HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT), HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT), /* FIXME: this looks suspicious... - HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x02, HDA_INPUT), */ { } /* end */ }; @@ -8911,10 +8911,11 @@ static struct snd_pci_quirk alc882_ssid_cfg_tbl[] = { SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3), SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_IMAC24), SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC885_MB5), - /* FIXME: HP jack sense seems not working for MBP 5,1, so apparently - * no perfect solution yet + /* FIXME: HP jack sense seems not working for MBP 5,1 or 5,2, + * so apparently no perfect solution yet */ SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC885_MB5), + SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC885_MB5), {} /* terminator */ }; @@ -9813,9 +9814,9 @@ static int alc882_parse_auto_config(struct hda_codec *codec) spec->multiout.dig_out_nid = dig_nid; else { spec->multiout.slave_dig_outs = spec->slave_dig_outs; - spec->slave_dig_outs[i - 1] = dig_nid; - if (i == ARRAY_SIZE(spec->slave_dig_outs) - 1) + if (i >= ARRAY_SIZE(spec->slave_dig_outs) - 1) break; + spec->slave_dig_outs[i - 1] = dig_nid; } } if (spec->autocfg.dig_in_pin) @@ -11460,6 +11461,8 @@ static struct snd_pci_quirk alc262_cfg_tbl[] = { SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD), SND_PCI_QUIRK(0x104d, 0x9016, "Sony VAIO", ALC262_AUTO), /* dig-only */ SND_PCI_QUIRK(0x104d, 0x9025, "Sony VAIO Z21MN", ALC262_TOSHIBA_S06), + SND_PCI_QUIRK(0x104d, 0x9035, "Sony VAIO VGN-FW170J", ALC262_AUTO), + SND_PCI_QUIRK(0x104d, 0x9047, "Sony VAIO Type G", ALC262_AUTO), SND_PCI_QUIRK_MASK(0x104d, 0xff00, 0x9000, "Sony VAIO", ALC262_SONY_ASSAMD), SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1", diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 66c0876bf734..ec25262e59e7 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -28,6 +28,7 @@ #include <linux/delay.h> #include <linux/slab.h> #include <linux/pci.h> +#include <linux/dmi.h> #include <sound/core.h> #include <sound/asoundef.h> #include <sound/jack.h> @@ -1589,6 +1590,8 @@ static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = { "Dell Studio 17", STAC_DELL_M6_DMIC), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02be, "Dell Studio 1555", STAC_DELL_M6_DMIC), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02bd, + "Dell Studio 1557", STAC_DELL_M6_DMIC), {} /* terminator */ }; @@ -1693,6 +1696,8 @@ static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = { "DFI LanParty", STAC_92HD71BXX_REF), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30fb, "HP dv4-1222nr", STAC_HP_DV4_1222NR), + SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x1720, + "HP", STAC_HP_DV5), SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x3080, "HP", STAC_HP_DV5), SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x30f0, @@ -3221,7 +3226,7 @@ static int stac92xx_auto_create_beep_ctls(struct hda_codec *codec, /* check for mute support for the the amp */ if ((caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT) { err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, - "PC Beep Playback Switch", + "Beep Playback Switch", HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT)); if (err < 0) return err; @@ -3230,7 +3235,7 @@ static int stac92xx_auto_create_beep_ctls(struct hda_codec *codec, /* check to see if there is volume support for the amp */ if ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) { err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, - "PC Beep Playback Volume", + "Beep Playback Volume", HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT)); if (err < 0) return err; @@ -3271,7 +3276,7 @@ static struct snd_kcontrol_new stac92xx_dig_beep_ctrl = { static int stac92xx_beep_switch_ctl(struct hda_codec *codec) { return stac92xx_add_control_temp(codec->spec, &stac92xx_dig_beep_ctrl, - 0, "PC Beep Playback Switch", 0); + 0, "Beep Playback Switch", 0); } #endif @@ -4665,6 +4670,26 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) } } +static int hp_bseries_system(u32 subsystem_id) +{ + switch (subsystem_id) { + case 0x103c307e: + case 0x103c307f: + case 0x103c3080: + case 0x103c3081: + case 0x103c1722: + case 0x103c1723: + case 0x103c1724: + case 0x103c1725: + case 0x103c1726: + case 0x103c1727: + case 0x103c1728: + case 0x103c1729: + return 1; + } + return 0; +} + #ifdef CONFIG_PROC_FS static void stac92hd_proc_hook(struct snd_info_buffer *buffer, struct hda_codec *codec, hda_nid_t nid) @@ -4754,6 +4779,11 @@ static int stac92xx_hp_check_power_status(struct hda_codec *codec, else spec->gpio_data |= spec->gpio_led; /* white */ + if (hp_bseries_system(codec->subsystem_id)) { + /* LED state is inverted on these systems */ + spec->gpio_data ^= spec->gpio_led; + } + stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data); @@ -5243,6 +5273,7 @@ static int patch_stac92hd71bxx(struct hda_codec *codec) { struct sigmatel_spec *spec; struct hda_verb *unmute_init = stac92hd71bxx_unmute_core_init; + unsigned int pin_cfg; int err = 0; spec = kzalloc(sizeof(*spec), GFP_KERNEL); @@ -5426,6 +5457,45 @@ again: break; } + if (hp_bseries_system(codec->subsystem_id)) { + pin_cfg = snd_hda_codec_get_pincfg(codec, 0x0f); + if (get_defcfg_device(pin_cfg) == AC_JACK_LINE_OUT || + get_defcfg_device(pin_cfg) == AC_JACK_SPEAKER || + get_defcfg_device(pin_cfg) == AC_JACK_HP_OUT) { + /* It was changed in the BIOS to just satisfy MS DTM. + * Lets turn it back into slaved HP + */ + pin_cfg = (pin_cfg & (~AC_DEFCFG_DEVICE)) + | (AC_JACK_HP_OUT << + AC_DEFCFG_DEVICE_SHIFT); + pin_cfg = (pin_cfg & (~(AC_DEFCFG_DEF_ASSOC + | AC_DEFCFG_SEQUENCE))) + | 0x1f; + snd_hda_codec_set_pincfg(codec, 0x0f, pin_cfg); + } + } + + if ((codec->subsystem_id >> 16) == PCI_VENDOR_ID_HP) { + const struct dmi_device *dev = NULL; + while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, + NULL, dev))) { + if (strcmp(dev->name, "HP_Mute_LED_1")) { + switch (codec->vendor_id) { + case 0x111d7608: + spec->gpio_led = 0x01; + break; + case 0x111d7600: + case 0x111d7601: + case 0x111d7602: + case 0x111d7603: + spec->gpio_led = 0x08; + break; + } + break; + } + } + } + #ifdef CONFIG_SND_HDA_POWER_SAVE if (spec->gpio_led) { spec->gpio_mask |= spec->gpio_led; diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h index 9da2dae64c5b..d063149e7047 100644 --- a/sound/pci/ice1712/ice1712.h +++ b/sound/pci/ice1712/ice1712.h @@ -382,8 +382,8 @@ struct snd_ice1712 { #ifdef CONFIG_PM int (*pm_suspend)(struct snd_ice1712 *); int (*pm_resume)(struct snd_ice1712 *); - int pm_suspend_enabled:1; - int pm_saved_is_spdif_master:1; + unsigned int pm_suspend_enabled:1; + unsigned int pm_saved_is_spdif_master:1; unsigned int pm_saved_spdif_ctrl; unsigned char pm_saved_spdif_cfg; unsigned int pm_saved_route; diff --git a/sound/pci/ice1712/juli.c b/sound/pci/ice1712/juli.c index fd948bfd9aef..f5020ad99a10 100644 --- a/sound/pci/ice1712/juli.c +++ b/sound/pci/ice1712/juli.c @@ -504,6 +504,31 @@ static int __devinit juli_add_controls(struct snd_ice1712 *ice) } /* + * suspend/resume + * */ + +#ifdef CONFIG_PM +static int juli_resume(struct snd_ice1712 *ice) +{ + struct snd_akm4xxx *ak = ice->akm; + struct juli_spec *spec = ice->spec; + /* akm4358 un-reset, un-mute */ + snd_akm4xxx_reset(ak, 0); + /* reinit ak4114 */ + snd_ak4114_reinit(spec->ak4114); + return 0; +} + +static int juli_suspend(struct snd_ice1712 *ice) +{ + struct snd_akm4xxx *ak = ice->akm; + /* akm4358 reset and soft-mute */ + snd_akm4xxx_reset(ak, 1); + return 0; +} +#endif + +/* * initialize the chip */ @@ -646,6 +671,13 @@ static int __devinit juli_init(struct snd_ice1712 *ice) ice->set_spdif_clock = juli_set_spdif_clock; ice->spdif.ops.open = juli_spdif_in_open; + +#ifdef CONFIG_PM + ice->pm_resume = juli_resume; + ice->pm_suspend = juli_suspend; + ice->pm_suspend_enabled = 1; +#endif + return 0; } diff --git a/sound/pci/ice1712/prodigy_hifi.c b/sound/pci/ice1712/prodigy_hifi.c index c75515f5be6f..6a9fee3ee78f 100644 --- a/sound/pci/ice1712/prodigy_hifi.c +++ b/sound/pci/ice1712/prodigy_hifi.c @@ -1100,7 +1100,7 @@ static void ak4396_init(struct snd_ice1712 *ice) } #ifdef CONFIG_PM -static int __devinit prodigy_hd2_resume(struct snd_ice1712 *ice) +static int prodigy_hd2_resume(struct snd_ice1712 *ice) { /* initialize ak4396 codec and restore previous mixer volumes */ struct prodigy_hifi_spec *spec = ice->spec; diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 754867ed4785..b990143636f1 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -1950,6 +1950,12 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = { }, { .subvendor = 0x104d, + .subdevice = 0x8144, + .name = "Sony", + .type = AC97_TUNE_INV_EAPD + }, + { + .subvendor = 0x104d, .subdevice = 0x8197, .name = "Sony S1XP", .type = AC97_TUNE_INV_EAPD @@ -2057,6 +2063,12 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = { .type = AC97_TUNE_HP_ONLY }, { + .subvendor = 0x161f, + .subdevice = 0x203a, + .name = "Gateway 4525GZ", /* AD1981B */ + .type = AC97_TUNE_INV_EAPD + }, + { .subvendor = 0x1734, .subdevice = 0x0088, .name = "Fujitsu-Siemens D1522", /* AD1981 */ diff --git a/sound/ppc/awacs.c b/sound/ppc/awacs.c index 2cc0eda4f20e..2e156467b814 100644 --- a/sound/ppc/awacs.c +++ b/sound/ppc/awacs.c @@ -479,7 +479,7 @@ static int snd_pmac_awacs_put_master_amp(struct snd_kcontrol *kcontrol, static struct snd_kcontrol_new snd_pmac_awacs_amp_vol[] __devinitdata = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "PC Speaker Playback Volume", + .name = "Speaker Playback Volume", .info = snd_pmac_awacs_info_volume_amp, .get = snd_pmac_awacs_get_volume_amp, .put = snd_pmac_awacs_put_volume_amp, @@ -525,7 +525,7 @@ static struct snd_kcontrol_new snd_pmac_awacs_amp_hp_sw __devinitdata = { static struct snd_kcontrol_new snd_pmac_awacs_amp_spk_sw __devinitdata = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "PC Speaker Playback Switch", + .name = "Speaker Playback Switch", .info = snd_pmac_boolean_stereo_info, .get = snd_pmac_awacs_get_switch_amp, .put = snd_pmac_awacs_put_switch_amp, @@ -696,17 +696,17 @@ static struct snd_kcontrol_new snd_pmac_screamer_mic_boost_imac[] __devinitdata }; static struct snd_kcontrol_new snd_pmac_awacs_speaker_vol[] __devinitdata = { - AWACS_VOLUME("PC Speaker Playback Volume", 4, 6, 1), + AWACS_VOLUME("Speaker Playback Volume", 4, 6, 1), }; static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw __devinitdata = -AWACS_SWITCH("PC Speaker Playback Switch", 1, SHIFT_SPKMUTE, 1); +AWACS_SWITCH("Speaker Playback Switch", 1, SHIFT_SPKMUTE, 1); static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw_imac1 __devinitdata = -AWACS_SWITCH("PC Speaker Playback Switch", 1, SHIFT_PAROUT1, 1); +AWACS_SWITCH("Speaker Playback Switch", 1, SHIFT_PAROUT1, 1); static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw_imac2 __devinitdata = -AWACS_SWITCH("PC Speaker Playback Switch", 1, SHIFT_PAROUT1, 0); +AWACS_SWITCH("Speaker Playback Switch", 1, SHIFT_PAROUT1, 0); /* diff --git a/sound/ppc/burgundy.c b/sound/ppc/burgundy.c index 16ed240e423c..0accfe49735b 100644 --- a/sound/ppc/burgundy.c +++ b/sound/ppc/burgundy.c @@ -505,7 +505,7 @@ static struct snd_kcontrol_new snd_pmac_burgundy_mixers_imac[] __devinitdata = { MASK_ADDR_BURGUNDY_GAINLINE, 1, 0), BURGUNDY_VOLUME_B("Mic Gain Capture Volume", 0, MASK_ADDR_BURGUNDY_GAINMIC, 1, 0), - BURGUNDY_VOLUME_B("PC Speaker Playback Volume", 0, + BURGUNDY_VOLUME_B("Speaker Playback Volume", 0, MASK_ADDR_BURGUNDY_ATTENSPEAKER, 1, 1), BURGUNDY_VOLUME_B("Line out Playback Volume", 0, MASK_ADDR_BURGUNDY_ATTENLINEOUT, 1, 1), @@ -527,7 +527,7 @@ static struct snd_kcontrol_new snd_pmac_burgundy_mixers_pmac[] __devinitdata = { MASK_ADDR_BURGUNDY_VOLMIC, 16), BURGUNDY_VOLUME_B("Line in Gain Capture Volume", 0, MASK_ADDR_BURGUNDY_GAINMIC, 1, 0), - BURGUNDY_VOLUME_B("PC Speaker Playback Volume", 0, + BURGUNDY_VOLUME_B("Speaker Playback Volume", 0, MASK_ADDR_BURGUNDY_ATTENMONO, 0, 1), BURGUNDY_VOLUME_B("Line out Playback Volume", 0, MASK_ADDR_BURGUNDY_ATTENSPEAKER, 1, 1), @@ -549,11 +549,11 @@ BURGUNDY_SWITCH_B("Master Playback Switch", 0, BURGUNDY_OUTPUT_INTERN | BURGUNDY_OUTPUT_LEFT, BURGUNDY_OUTPUT_RIGHT, 1); static struct snd_kcontrol_new snd_pmac_burgundy_speaker_sw_imac __devinitdata = -BURGUNDY_SWITCH_B("PC Speaker Playback Switch", 0, +BURGUNDY_SWITCH_B("Speaker Playback Switch", 0, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, BURGUNDY_OUTPUT_LEFT, BURGUNDY_OUTPUT_RIGHT, 1); static struct snd_kcontrol_new snd_pmac_burgundy_speaker_sw_pmac __devinitdata = -BURGUNDY_SWITCH_B("PC Speaker Playback Switch", 0, +BURGUNDY_SWITCH_B("Speaker Playback Switch", 0, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, BURGUNDY_OUTPUT_INTERN, 0, 0); static struct snd_kcontrol_new snd_pmac_burgundy_line_sw_imac __devinitdata = diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c index 08e584d1453a..789f44f4ac78 100644 --- a/sound/ppc/tumbler.c +++ b/sound/ppc/tumbler.c @@ -905,7 +905,7 @@ static struct snd_kcontrol_new tumbler_hp_sw __devinitdata = { }; static struct snd_kcontrol_new tumbler_speaker_sw __devinitdata = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "PC Speaker Playback Switch", + .name = "Speaker Playback Switch", .info = snd_pmac_boolean_mono_info, .get = tumbler_get_mute_switch, .put = tumbler_put_mute_switch, diff --git a/sound/sh/Kconfig b/sound/sh/Kconfig index aed0f90c3919..61139f3c1614 100644 --- a/sound/sh/Kconfig +++ b/sound/sh/Kconfig @@ -19,5 +19,13 @@ config SND_AICA help ALSA Sound driver for the SEGA Dreamcast console. +config SND_SH_DAC_AUDIO + tristate "SuperH DAC audio support" + depends on SND + depends on CPU_SH3 && HIGH_RES_TIMERS + select SND_PCM + help + Say Y here to include support for the on-chip DAC. + endif # SND_SUPERH diff --git a/sound/sh/Makefile b/sound/sh/Makefile index 8fdcb6e26f00..7d09b5188cf7 100644 --- a/sound/sh/Makefile +++ b/sound/sh/Makefile @@ -3,6 +3,8 @@ # snd-aica-objs := aica.o +snd-sh_dac_audio-objs := sh_dac_audio.o # Toplevel Module Dependency obj-$(CONFIG_SND_AICA) += snd-aica.o +obj-$(CONFIG_SND_SH_DAC_AUDIO) += snd-sh_dac_audio.o diff --git a/sound/sh/aica.c b/sound/sh/aica.c index 583a3693df75..a0df401ebb9f 100644 --- a/sound/sh/aica.c +++ b/sound/sh/aica.c @@ -49,6 +49,7 @@ MODULE_AUTHOR("Adrian McMenamin <adrian@mcmen.demon.co.uk>"); MODULE_DESCRIPTION("Dreamcast AICA sound (pcm) driver"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Yamaha/SEGA, AICA}}"); +MODULE_FIRMWARE("aica_firmware.bin"); /* module parameters */ #define CARD_NAME "AICA" diff --git a/sound/sh/sh_dac_audio.c b/sound/sh/sh_dac_audio.c new file mode 100644 index 000000000000..76d9ad27d91c --- /dev/null +++ b/sound/sh/sh_dac_audio.c @@ -0,0 +1,453 @@ +/* + * sh_dac_audio.c - SuperH DAC audio driver for ALSA + * + * Copyright (c) 2009 by Rafael Ignacio Zurita <rizurita@yahoo.com> + * + * + * Based on sh_dac_audio.c (Copyright (C) 2004, 2005 by Andriy Skulysh) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <linux/hrtimer.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/platform_device.h> +#include <sound/core.h> +#include <sound/initval.h> +#include <sound/pcm.h> +#include <sound/sh_dac_audio.h> +#include <asm/clock.h> +#include <asm/hd64461.h> +#include <mach/hp6xx.h> +#include <cpu/dac.h> + +MODULE_AUTHOR("Rafael Ignacio Zurita <rizurita@yahoo.com>"); +MODULE_DESCRIPTION("SuperH DAC audio driver"); +MODULE_LICENSE("GPL"); +MODULE_SUPPORTED_DEVICE("{{SuperH DAC audio support}}"); + +/* Module Parameters */ +static int index = SNDRV_DEFAULT_IDX1; +static char *id = SNDRV_DEFAULT_STR1; +module_param(index, int, 0444); +MODULE_PARM_DESC(index, "Index value for SuperH DAC audio."); +module_param(id, charp, 0444); +MODULE_PARM_DESC(id, "ID string for SuperH DAC audio."); + +/* main struct */ +struct snd_sh_dac { + struct snd_card *card; + struct snd_pcm_substream *substream; + struct hrtimer hrtimer; + ktime_t wakeups_per_second; + + int rate; + int empty; + char *data_buffer, *buffer_begin, *buffer_end; + int processed; /* bytes proccesed, to compare with period_size */ + int buffer_size; + struct dac_audio_pdata *pdata; +}; + + +static void dac_audio_start_timer(struct snd_sh_dac *chip) +{ + hrtimer_start(&chip->hrtimer, chip->wakeups_per_second, + HRTIMER_MODE_REL); +} + +static void dac_audio_stop_timer(struct snd_sh_dac *chip) +{ + hrtimer_cancel(&chip->hrtimer); +} + +static void dac_audio_reset(struct snd_sh_dac *chip) +{ + dac_audio_stop_timer(chip); + chip->buffer_begin = chip->buffer_end = chip->data_buffer; + chip->processed = 0; + chip->empty = 1; +} + +static void dac_audio_set_rate(struct snd_sh_dac *chip) +{ + chip->wakeups_per_second = ktime_set(0, 1000000000 / chip->rate); +} + + +/* PCM INTERFACE */ + +static struct snd_pcm_hardware snd_sh_dac_pcm_hw = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_HALF_DUPLEX), + .formats = SNDRV_PCM_FMTBIT_U8, + .rates = SNDRV_PCM_RATE_8000, + .rate_min = 8000, + .rate_max = 8000, + .channels_min = 1, + .channels_max = 1, + .buffer_bytes_max = (48*1024), + .period_bytes_min = 1, + .period_bytes_max = (48*1024), + .periods_min = 1, + .periods_max = 1024, +}; + +static int snd_sh_dac_pcm_open(struct snd_pcm_substream *substream) +{ + struct snd_sh_dac *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + + runtime->hw = snd_sh_dac_pcm_hw; + + chip->substream = substream; + chip->buffer_begin = chip->buffer_end = chip->data_buffer; + chip->processed = 0; + chip->empty = 1; + + chip->pdata->start(chip->pdata); + + return 0; +} + +static int snd_sh_dac_pcm_close(struct snd_pcm_substream *substream) +{ + struct snd_sh_dac *chip = snd_pcm_substream_chip(substream); + + chip->substream = NULL; + + dac_audio_stop_timer(chip); + chip->pdata->stop(chip->pdata); + + return 0; +} + +static int snd_sh_dac_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_sh_dac_pcm_hw_free(struct snd_pcm_substream *substream) +{ + return snd_pcm_lib_free_pages(substream); +} + +static int snd_sh_dac_pcm_prepare(struct snd_pcm_substream *substream) +{ + struct snd_sh_dac *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = chip->substream->runtime; + + chip->buffer_size = runtime->buffer_size; + memset(chip->data_buffer, 0, chip->pdata->buffer_size); + + return 0; +} + +static int snd_sh_dac_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_sh_dac *chip = snd_pcm_substream_chip(substream); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + dac_audio_start_timer(chip); + break; + case SNDRV_PCM_TRIGGER_STOP: + chip->buffer_begin = chip->buffer_end = chip->data_buffer; + chip->processed = 0; + chip->empty = 1; + dac_audio_stop_timer(chip); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int snd_sh_dac_pcm_copy(struct snd_pcm_substream *substream, int channel, + snd_pcm_uframes_t pos, void __user *src, snd_pcm_uframes_t count) +{ + /* channel is not used (interleaved data) */ + struct snd_sh_dac *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + ssize_t b_count = frames_to_bytes(runtime , count); + ssize_t b_pos = frames_to_bytes(runtime , pos); + + if (count < 0) + return -EINVAL; + + if (!count) + return 0; + + memcpy_toio(chip->data_buffer + b_pos, src, b_count); + chip->buffer_end = chip->data_buffer + b_pos + b_count; + + if (chip->empty) { + chip->empty = 0; + dac_audio_start_timer(chip); + } + + return 0; +} + +static int snd_sh_dac_pcm_silence(struct snd_pcm_substream *substream, + int channel, snd_pcm_uframes_t pos, + snd_pcm_uframes_t count) +{ + /* channel is not used (interleaved data) */ + struct snd_sh_dac *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + ssize_t b_count = frames_to_bytes(runtime , count); + ssize_t b_pos = frames_to_bytes(runtime , pos); + + if (count < 0) + return -EINVAL; + + if (!count) + return 0; + + memset_io(chip->data_buffer + b_pos, 0, b_count); + chip->buffer_end = chip->data_buffer + b_pos + b_count; + + if (chip->empty) { + chip->empty = 0; + dac_audio_start_timer(chip); + } + + return 0; +} + +static +snd_pcm_uframes_t snd_sh_dac_pcm_pointer(struct snd_pcm_substream *substream) +{ + struct snd_sh_dac *chip = snd_pcm_substream_chip(substream); + int pointer = chip->buffer_begin - chip->data_buffer; + + return pointer; +} + +/* pcm ops */ +static struct snd_pcm_ops snd_sh_dac_pcm_ops = { + .open = snd_sh_dac_pcm_open, + .close = snd_sh_dac_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_sh_dac_pcm_hw_params, + .hw_free = snd_sh_dac_pcm_hw_free, + .prepare = snd_sh_dac_pcm_prepare, + .trigger = snd_sh_dac_pcm_trigger, + .pointer = snd_sh_dac_pcm_pointer, + .copy = snd_sh_dac_pcm_copy, + .silence = snd_sh_dac_pcm_silence, + .mmap = snd_pcm_lib_mmap_iomem, +}; + +static int __devinit snd_sh_dac_pcm(struct snd_sh_dac *chip, int device) +{ + int err; + struct snd_pcm *pcm; + + /* device should be always 0 for us */ + err = snd_pcm_new(chip->card, "SH_DAC PCM", device, 1, 0, &pcm); + if (err < 0) + return err; + + pcm->private_data = chip; + strcpy(pcm->name, "SH_DAC PCM"); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_sh_dac_pcm_ops); + + /* buffer size=48K */ + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, + snd_dma_continuous_data(GFP_KERNEL), + 48 * 1024, + 48 * 1024); + + return 0; +} +/* END OF PCM INTERFACE */ + + +/* driver .remove -- destructor */ +static int snd_sh_dac_remove(struct platform_device *devptr) +{ + snd_card_free(platform_get_drvdata(devptr)); + platform_set_drvdata(devptr, NULL); + + return 0; +} + +/* free -- it has been defined by create */ +static int snd_sh_dac_free(struct snd_sh_dac *chip) +{ + /* release the data */ + kfree(chip->data_buffer); + kfree(chip); + + return 0; +} + +static int snd_sh_dac_dev_free(struct snd_device *device) +{ + struct snd_sh_dac *chip = device->device_data; + + return snd_sh_dac_free(chip); +} + +static enum hrtimer_restart sh_dac_audio_timer(struct hrtimer *handle) +{ + struct snd_sh_dac *chip = container_of(handle, struct snd_sh_dac, + hrtimer); + struct snd_pcm_runtime *runtime = chip->substream->runtime; + ssize_t b_ps = frames_to_bytes(runtime, runtime->period_size); + + if (!chip->empty) { + sh_dac_output(*chip->buffer_begin, chip->pdata->channel); + chip->buffer_begin++; + + chip->processed++; + if (chip->processed >= b_ps) { + chip->processed -= b_ps; + snd_pcm_period_elapsed(chip->substream); + } + + if (chip->buffer_begin == (chip->data_buffer + + chip->buffer_size - 1)) + chip->buffer_begin = chip->data_buffer; + + if (chip->buffer_begin == chip->buffer_end) + chip->empty = 1; + + } + + if (!chip->empty) + hrtimer_start(&chip->hrtimer, chip->wakeups_per_second, + HRTIMER_MODE_REL); + + return HRTIMER_NORESTART; +} + +/* create -- chip-specific constructor for the cards components */ +static int __devinit snd_sh_dac_create(struct snd_card *card, + struct platform_device *devptr, + struct snd_sh_dac **rchip) +{ + struct snd_sh_dac *chip; + int err; + + static struct snd_device_ops ops = { + .dev_free = snd_sh_dac_dev_free, + }; + + *rchip = NULL; + + chip = kzalloc(sizeof(*chip), GFP_KERNEL); + if (chip == NULL) + return -ENOMEM; + + chip->card = card; + + hrtimer_init(&chip->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + chip->hrtimer.function = sh_dac_audio_timer; + + dac_audio_reset(chip); + chip->rate = 8000; + dac_audio_set_rate(chip); + + chip->pdata = devptr->dev.platform_data; + + chip->data_buffer = kmalloc(chip->pdata->buffer_size, GFP_KERNEL); + if (chip->data_buffer == NULL) { + kfree(chip); + return -ENOMEM; + } + + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); + if (err < 0) { + snd_sh_dac_free(chip); + return err; + } + + *rchip = chip; + + return 0; +} + +/* driver .probe -- constructor */ +static int __devinit snd_sh_dac_probe(struct platform_device *devptr) +{ + struct snd_sh_dac *chip; + struct snd_card *card; + int err; + + err = snd_card_create(index, id, THIS_MODULE, 0, &card); + if (err < 0) { + snd_printk(KERN_ERR "cannot allocate the card\n"); + return err; + } + + err = snd_sh_dac_create(card, devptr, &chip); + if (err < 0) + goto probe_error; + + err = snd_sh_dac_pcm(chip, 0); + if (err < 0) + goto probe_error; + + strcpy(card->driver, "snd_sh_dac"); + strcpy(card->shortname, "SuperH DAC audio driver"); + printk(KERN_INFO "%s %s", card->longname, card->shortname); + + err = snd_card_register(card); + if (err < 0) + goto probe_error; + + snd_printk("ALSA driver for SuperH DAC audio"); + + platform_set_drvdata(devptr, card); + return 0; + +probe_error: + snd_card_free(card); + return err; +} + +/* + * "driver" definition + */ +static struct platform_driver driver = { + .probe = snd_sh_dac_probe, + .remove = snd_sh_dac_remove, + .driver = { + .name = "dac_audio", + }, +}; + +static int __init sh_dac_init(void) +{ + return platform_driver_register(&driver); +} + +static void __exit sh_dac_exit(void) +{ + platform_driver_unregister(&driver); +} + +module_init(sh_dac_init); +module_exit(sh_dac_exit); diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index 09d1af85b6f1..a9dc5fb54774 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c @@ -85,7 +85,7 @@ static int tlv320aic23_write(struct snd_soc_codec *codec, unsigned int reg, * of data into val */ - if ((reg < 0 || reg > 9) && (reg != 15)) { + if (reg > 9 && reg != 15) { printk(KERN_WARNING "%s Invalid register R%u\n", __func__, reg); return -1; } diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 4d74ecb0e56b..c58aab375edb 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -165,9 +165,9 @@ SOC_SINGLE("Mono Playback Switch", AC97_MASTER_TONE, 7, 1, 1), SOC_SINGLE("Mono Playback ZC Switch", AC97_MASTER_TONE, 6, 1, 0), SOC_SINGLE("Mono Playback Volume", AC97_MASTER_TONE, 0, 31, 1), -SOC_SINGLE("PC Beep Playback Headphone Volume", AC97_AUX, 12, 7, 1), -SOC_SINGLE("PC Beep Playback Speaker Volume", AC97_AUX, 8, 7, 1), -SOC_SINGLE("PC Beep Playback Mono Volume", AC97_AUX, 4, 7, 1), +SOC_SINGLE("Beep Playback Headphone Volume", AC97_AUX, 12, 7, 1), +SOC_SINGLE("Beep Playback Speaker Volume", AC97_AUX, 8, 7, 1), +SOC_SINGLE("Beep Playback Mono Volume", AC97_AUX, 4, 7, 1), SOC_SINGLE("Voice Playback Headphone Volume", AC97_PCM, 12, 7, 1), SOC_SINGLE("Voice Playback Master Volume", AC97_PCM, 8, 7, 1), @@ -266,7 +266,7 @@ static int mixer_event(struct snd_soc_dapm_widget *w, /* Left Headphone Mixers */ static const struct snd_kcontrol_new wm9713_hpl_mixer_controls[] = { -SOC_DAPM_SINGLE("PC Beep Playback Switch", HPL_MIXER, 5, 1, 0), +SOC_DAPM_SINGLE("Beep Playback Switch", HPL_MIXER, 5, 1, 0), SOC_DAPM_SINGLE("Voice Playback Switch", HPL_MIXER, 4, 1, 0), SOC_DAPM_SINGLE("Aux Playback Switch", HPL_MIXER, 3, 1, 0), SOC_DAPM_SINGLE("PCM Playback Switch", HPL_MIXER, 2, 1, 0), @@ -276,7 +276,7 @@ SOC_DAPM_SINGLE("Bypass Playback Switch", HPL_MIXER, 0, 1, 0), /* Right Headphone Mixers */ static const struct snd_kcontrol_new wm9713_hpr_mixer_controls[] = { -SOC_DAPM_SINGLE("PC Beep Playback Switch", HPR_MIXER, 5, 1, 0), +SOC_DAPM_SINGLE("Beep Playback Switch", HPR_MIXER, 5, 1, 0), SOC_DAPM_SINGLE("Voice Playback Switch", HPR_MIXER, 4, 1, 0), SOC_DAPM_SINGLE("Aux Playback Switch", HPR_MIXER, 3, 1, 0), SOC_DAPM_SINGLE("PCM Playback Switch", HPR_MIXER, 2, 1, 0), @@ -294,7 +294,7 @@ SOC_DAPM_ENUM("Route", wm9713_enum[0]); /* Speaker Mixer */ static const struct snd_kcontrol_new wm9713_speaker_mixer_controls[] = { -SOC_DAPM_SINGLE("PC Beep Playback Switch", AC97_AUX, 11, 1, 1), +SOC_DAPM_SINGLE("Beep Playback Switch", AC97_AUX, 11, 1, 1), SOC_DAPM_SINGLE("Voice Playback Switch", AC97_PCM, 11, 1, 1), SOC_DAPM_SINGLE("Aux Playback Switch", AC97_REC_SEL, 11, 1, 1), SOC_DAPM_SINGLE("PCM Playback Switch", AC97_PHONE, 14, 1, 1), @@ -304,7 +304,7 @@ SOC_DAPM_SINGLE("Bypass Playback Switch", AC97_PC_BEEP, 14, 1, 1), /* Mono Mixer */ static const struct snd_kcontrol_new wm9713_mono_mixer_controls[] = { -SOC_DAPM_SINGLE("PC Beep Playback Switch", AC97_AUX, 7, 1, 1), +SOC_DAPM_SINGLE("Beep Playback Switch", AC97_AUX, 7, 1, 1), SOC_DAPM_SINGLE("Voice Playback Switch", AC97_PCM, 7, 1, 1), SOC_DAPM_SINGLE("Aux Playback Switch", AC97_REC_SEL, 7, 1, 1), SOC_DAPM_SINGLE("PCM Playback Switch", AC97_PHONE, 13, 1, 1), @@ -463,7 +463,7 @@ SND_SOC_DAPM_VMID("VMID"), static const struct snd_soc_dapm_route audio_map[] = { /* left HP mixer */ - {"Left HP Mixer", "PC Beep Playback Switch", "PCBEEP"}, + {"Left HP Mixer", "Beep Playback Switch", "PCBEEP"}, {"Left HP Mixer", "Voice Playback Switch", "Voice DAC"}, {"Left HP Mixer", "Aux Playback Switch", "Aux DAC"}, {"Left HP Mixer", "Bypass Playback Switch", "Left Line In"}, @@ -472,7 +472,7 @@ static const struct snd_soc_dapm_route audio_map[] = { {"Left HP Mixer", NULL, "Capture Headphone Mux"}, /* right HP mixer */ - {"Right HP Mixer", "PC Beep Playback Switch", "PCBEEP"}, + {"Right HP Mixer", "Beep Playback Switch", "PCBEEP"}, {"Right HP Mixer", "Voice Playback Switch", "Voice DAC"}, {"Right HP Mixer", "Aux Playback Switch", "Aux DAC"}, {"Right HP Mixer", "Bypass Playback Switch", "Right Line In"}, @@ -491,7 +491,7 @@ static const struct snd_soc_dapm_route audio_map[] = { {"Capture Mixer", NULL, "Right Capture Source"}, /* speaker mixer */ - {"Speaker Mixer", "PC Beep Playback Switch", "PCBEEP"}, + {"Speaker Mixer", "Beep Playback Switch", "PCBEEP"}, {"Speaker Mixer", "Voice Playback Switch", "Voice DAC"}, {"Speaker Mixer", "Aux Playback Switch", "Aux DAC"}, {"Speaker Mixer", "Bypass Playback Switch", "Line Mixer"}, @@ -499,7 +499,7 @@ static const struct snd_soc_dapm_route audio_map[] = { {"Speaker Mixer", "MonoIn Playback Switch", "Mono In"}, /* mono mixer */ - {"Mono Mixer", "PC Beep Playback Switch", "PCBEEP"}, + {"Mono Mixer", "Beep Playback Switch", "PCBEEP"}, {"Mono Mixer", "Voice Playback Switch", "Voice DAC"}, {"Mono Mixer", "Aux Playback Switch", "Aux DAC"}, {"Mono Mixer", "Bypass Playback Switch", "Line Mixer"}, diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 8db0374e10d5..b074a594c595 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -2893,7 +2893,9 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) if ((altsd->bInterfaceClass == USB_CLASS_AUDIO || altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC) && altsd->bInterfaceSubClass == USB_SUBCLASS_MIDI_STREAMING) { - if (snd_usb_create_midi_interface(chip, iface, NULL) < 0) { + int err = snd_usbmidi_create(chip->card, iface, + &chip->midi_list, NULL); + if (err < 0) { snd_printk(KERN_ERR "%d:%u:%d: cannot create sequencer device\n", dev->devnum, ctrlif, j); continue; } @@ -3038,12 +3040,11 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip, .type = QUIRK_MIDI_FIXED_ENDPOINT, .data = &uaxx_ep }; - if (chip->usb_id == USB_ID(0x0582, 0x002b)) - return snd_usb_create_midi_interface(chip, iface, - &ua700_quirk); - else - return snd_usb_create_midi_interface(chip, iface, - &uaxx_quirk); + const struct snd_usb_audio_quirk *quirk = + chip->usb_id == USB_ID(0x0582, 0x002b) + ? &ua700_quirk : &uaxx_quirk; + return snd_usbmidi_create(chip->card, iface, + &chip->midi_list, quirk); } if (altsd->bNumEndpoints != 1) @@ -3370,6 +3371,13 @@ static int audiophile_skip_setting_quirk(struct snd_usb_audio *chip, return 0; /* keep this altsetting */ } +static int create_any_midi_quirk(struct snd_usb_audio *chip, + struct usb_interface *intf, + const struct snd_usb_audio_quirk *quirk) +{ + return snd_usbmidi_create(chip->card, intf, &chip->midi_list, quirk); +} + /* * audio-interface quirks * @@ -3387,14 +3395,14 @@ static int snd_usb_create_quirk(struct snd_usb_audio *chip, static const quirk_func_t quirk_funcs[] = { [QUIRK_IGNORE_INTERFACE] = ignore_interface_quirk, [QUIRK_COMPOSITE] = create_composite_quirk, - [QUIRK_MIDI_STANDARD_INTERFACE] = snd_usb_create_midi_interface, - [QUIRK_MIDI_FIXED_ENDPOINT] = snd_usb_create_midi_interface, - [QUIRK_MIDI_YAMAHA] = snd_usb_create_midi_interface, - [QUIRK_MIDI_MIDIMAN] = snd_usb_create_midi_interface, - [QUIRK_MIDI_NOVATION] = snd_usb_create_midi_interface, - [QUIRK_MIDI_FASTLANE] = snd_usb_create_midi_interface, - [QUIRK_MIDI_EMAGIC] = snd_usb_create_midi_interface, - [QUIRK_MIDI_CME] = snd_usb_create_midi_interface, + [QUIRK_MIDI_STANDARD_INTERFACE] = create_any_midi_quirk, + [QUIRK_MIDI_FIXED_ENDPOINT] = create_any_midi_quirk, + [QUIRK_MIDI_YAMAHA] = create_any_midi_quirk, + [QUIRK_MIDI_MIDIMAN] = create_any_midi_quirk, + [QUIRK_MIDI_NOVATION] = create_any_midi_quirk, + [QUIRK_MIDI_FASTLANE] = create_any_midi_quirk, + [QUIRK_MIDI_EMAGIC] = create_any_midi_quirk, + [QUIRK_MIDI_CME] = create_any_midi_quirk, [QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk, [QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk, [QUIRK_AUDIO_EDIROL_UA1000] = create_ua1000_quirk, diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 8e7f78941ba6..40ba8115fb81 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -132,7 +132,6 @@ struct snd_usb_audio { int pcm_devs; struct list_head midi_list; /* list of midi interfaces */ - int next_midi_device; struct list_head mixer_list; /* list of mixer interfaces */ }; @@ -210,7 +209,7 @@ struct snd_usb_midi_endpoint_info { /* */ -#define combine_word(s) ((*s) | ((unsigned int)(s)[1] << 8)) +#define combine_word(s) ((*(s)) | ((unsigned int)(s)[1] << 8)) #define combine_triple(s) (combine_word(s) | ((unsigned int)(s)[2] << 16)) #define combine_quad(s) (combine_triple(s) | ((unsigned int)(s)[3] << 24)) @@ -227,8 +226,10 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, int ignore_error); void snd_usb_mixer_disconnect(struct list_head *p); -int snd_usb_create_midi_interface(struct snd_usb_audio *chip, struct usb_interface *iface, - const struct snd_usb_audio_quirk *quirk); +int snd_usbmidi_create(struct snd_card *card, + struct usb_interface *iface, + struct list_head *midi_list, + const struct snd_usb_audio_quirk *quirk); void snd_usbmidi_input_stop(struct list_head* p); void snd_usbmidi_input_start(struct list_head* p); void snd_usbmidi_disconnect(struct list_head *p); diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c index 0eff19ceb7e1..6e89b8368d9a 100644 --- a/sound/usb/usbmidi.c +++ b/sound/usb/usbmidi.c @@ -1,7 +1,7 @@ /* * usbmidi.c - ALSA USB MIDI driver * - * Copyright (c) 2002-2007 Clemens Ladisch + * Copyright (c) 2002-2009 Clemens Ladisch * All rights reserved. * * Based on the OSS usb-midi driver by NAGANO Daisuke, @@ -47,6 +47,7 @@ #include <linux/usb.h> #include <linux/wait.h> #include <sound/core.h> +#include <sound/control.h> #include <sound/rawmidi.h> #include <sound/asequencer.h> #include "usbaudio.h" @@ -101,7 +102,8 @@ struct usb_protocol_ops { }; struct snd_usb_midi { - struct snd_usb_audio *chip; + struct usb_device *dev; + struct snd_card *card; struct usb_interface *iface; const struct snd_usb_audio_quirk *quirk; struct snd_rawmidi *rmidi; @@ -109,13 +111,19 @@ struct snd_usb_midi { struct list_head list; struct timer_list error_timer; spinlock_t disc_lock; + struct mutex mutex; + u32 usb_id; + int next_midi_device; struct snd_usb_midi_endpoint { struct snd_usb_midi_out_endpoint *out; struct snd_usb_midi_in_endpoint *in; } endpoints[MIDI_MAX_ENDPOINTS]; unsigned long input_triggered; + unsigned int opened; unsigned char disconnected; + + struct snd_kcontrol *roland_load_ctl; }; struct snd_usb_midi_out_endpoint { @@ -255,7 +263,7 @@ static void snd_usbmidi_in_urb_complete(struct urb* urb) } } - urb->dev = ep->umidi->chip->dev; + urb->dev = ep->umidi->dev; snd_usbmidi_submit_urb(urb, GFP_ATOMIC); } @@ -296,7 +304,7 @@ static void snd_usbmidi_do_output(struct snd_usb_midi_out_endpoint* ep) unsigned long flags; spin_lock_irqsave(&ep->buffer_lock, flags); - if (ep->umidi->chip->shutdown) { + if (ep->umidi->disconnected) { spin_unlock_irqrestore(&ep->buffer_lock, flags); return; } @@ -312,7 +320,7 @@ static void snd_usbmidi_do_output(struct snd_usb_midi_out_endpoint* ep) dump_urb("sending", urb->transfer_buffer, urb->transfer_buffer_length); - urb->dev = ep->umidi->chip->dev; + urb->dev = ep->umidi->dev; if (snd_usbmidi_submit_urb(urb, GFP_ATOMIC) < 0) break; ep->active_urbs |= 1 << urb_index; @@ -349,7 +357,7 @@ static void snd_usbmidi_error_timer(unsigned long data) if (in && in->error_resubmit) { in->error_resubmit = 0; for (j = 0; j < INPUT_URBS; ++j) { - in->urbs[j]->dev = umidi->chip->dev; + in->urbs[j]->dev = umidi->dev; snd_usbmidi_submit_urb(in->urbs[j], GFP_ATOMIC); } } @@ -369,7 +377,7 @@ static int send_bulk_static_data(struct snd_usb_midi_out_endpoint* ep, return -ENOMEM; dump_urb("sending", buf, len); if (ep->urbs[0].urb) - err = usb_bulk_msg(ep->umidi->chip->dev, ep->urbs[0].urb->pipe, + err = usb_bulk_msg(ep->umidi->dev, ep->urbs[0].urb->pipe, buf, len, NULL, 250); kfree(buf); return err; @@ -724,8 +732,7 @@ static void snd_usbmidi_us122l_output(struct snd_usb_midi_out_endpoint *ep, if (!ep->ports[0].active) return; - count = snd_usb_get_speed(ep->umidi->chip->dev) == USB_SPEED_HIGH - ? 1 : 2; + count = snd_usb_get_speed(ep->umidi->dev) == USB_SPEED_HIGH ? 1 : 2; count = snd_rawmidi_transmit(ep->ports[0].substream, urb->transfer_buffer, count); @@ -879,6 +886,50 @@ static struct usb_protocol_ops snd_usbmidi_emagic_ops = { }; +static void update_roland_altsetting(struct snd_usb_midi* umidi) +{ + struct usb_interface *intf; + struct usb_host_interface *hostif; + struct usb_interface_descriptor *intfd; + int is_light_load; + + intf = umidi->iface; + is_light_load = intf->cur_altsetting != intf->altsetting; + if (umidi->roland_load_ctl->private_value == is_light_load) + return; + hostif = &intf->altsetting[umidi->roland_load_ctl->private_value]; + intfd = get_iface_desc(hostif); + snd_usbmidi_input_stop(&umidi->list); + usb_set_interface(umidi->dev, intfd->bInterfaceNumber, + intfd->bAlternateSetting); + snd_usbmidi_input_start(&umidi->list); +} + +static void substream_open(struct snd_rawmidi_substream *substream, int open) +{ + struct snd_usb_midi* umidi = substream->rmidi->private_data; + struct snd_kcontrol *ctl; + + mutex_lock(&umidi->mutex); + if (open) { + if (umidi->opened++ == 0 && umidi->roland_load_ctl) { + ctl = umidi->roland_load_ctl; + ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; + snd_ctl_notify(umidi->card, + SNDRV_CTL_EVENT_MASK_INFO, &ctl->id); + update_roland_altsetting(umidi); + } + } else { + if (--umidi->opened == 0 && umidi->roland_load_ctl) { + ctl = umidi->roland_load_ctl; + ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; + snd_ctl_notify(umidi->card, + SNDRV_CTL_EVENT_MASK_INFO, &ctl->id); + } + } + mutex_unlock(&umidi->mutex); +} + static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream) { struct snd_usb_midi* umidi = substream->rmidi->private_data; @@ -898,11 +949,13 @@ static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream) } substream->runtime->private_data = port; port->state = STATE_UNKNOWN; + substream_open(substream, 1); return 0; } static int snd_usbmidi_output_close(struct snd_rawmidi_substream *substream) { + substream_open(substream, 0); return 0; } @@ -912,7 +965,7 @@ static void snd_usbmidi_output_trigger(struct snd_rawmidi_substream *substream, port->active = up; if (up) { - if (port->ep->umidi->chip->shutdown) { + if (port->ep->umidi->disconnected) { /* gobble up remaining bytes to prevent wait in * snd_rawmidi_drain_output */ while (!snd_rawmidi_transmit_empty(substream)) @@ -954,11 +1007,13 @@ static void snd_usbmidi_output_drain(struct snd_rawmidi_substream *substream) static int snd_usbmidi_input_open(struct snd_rawmidi_substream *substream) { + substream_open(substream, 1); return 0; } static int snd_usbmidi_input_close(struct snd_rawmidi_substream *substream) { + substream_open(substream, 0); return 0; } @@ -988,7 +1043,7 @@ static struct snd_rawmidi_ops snd_usbmidi_input_ops = { static void free_urb_and_buffer(struct snd_usb_midi *umidi, struct urb *urb, unsigned int buffer_length) { - usb_buffer_free(umidi->chip->dev, buffer_length, + usb_buffer_free(umidi->dev, buffer_length, urb->transfer_buffer, urb->transfer_dma); usb_free_urb(urb); } @@ -1035,24 +1090,24 @@ static int snd_usbmidi_in_endpoint_create(struct snd_usb_midi* umidi, } } if (ep_info->in_interval) - pipe = usb_rcvintpipe(umidi->chip->dev, ep_info->in_ep); + pipe = usb_rcvintpipe(umidi->dev, ep_info->in_ep); else - pipe = usb_rcvbulkpipe(umidi->chip->dev, ep_info->in_ep); - length = usb_maxpacket(umidi->chip->dev, pipe, 0); + pipe = usb_rcvbulkpipe(umidi->dev, ep_info->in_ep); + length = usb_maxpacket(umidi->dev, pipe, 0); for (i = 0; i < INPUT_URBS; ++i) { - buffer = usb_buffer_alloc(umidi->chip->dev, length, GFP_KERNEL, + buffer = usb_buffer_alloc(umidi->dev, length, GFP_KERNEL, &ep->urbs[i]->transfer_dma); if (!buffer) { snd_usbmidi_in_endpoint_delete(ep); return -ENOMEM; } if (ep_info->in_interval) - usb_fill_int_urb(ep->urbs[i], umidi->chip->dev, + usb_fill_int_urb(ep->urbs[i], umidi->dev, pipe, buffer, length, snd_usbmidi_in_urb_complete, ep, ep_info->in_interval); else - usb_fill_bulk_urb(ep->urbs[i], umidi->chip->dev, + usb_fill_bulk_urb(ep->urbs[i], umidi->dev, pipe, buffer, length, snd_usbmidi_in_urb_complete, ep); ep->urbs[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP; @@ -1062,15 +1117,6 @@ static int snd_usbmidi_in_endpoint_create(struct snd_usb_midi* umidi, return 0; } -static unsigned int snd_usbmidi_count_bits(unsigned int x) -{ - unsigned int bits; - - for (bits = 0; x; ++bits) - x &= x - 1; - return bits; -} - /* * Frees an output endpoint. * May be called when ep hasn't been initialized completely. @@ -1113,15 +1159,15 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi* umidi, ep->urbs[i].ep = ep; } if (ep_info->out_interval) - pipe = usb_sndintpipe(umidi->chip->dev, ep_info->out_ep); + pipe = usb_sndintpipe(umidi->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 */ + pipe = usb_sndbulkpipe(umidi->dev, ep_info->out_ep); + if (umidi->usb_id == USB_ID(0x0a92, 0x1020)) /* ESI M4U */ ep->max_transfer = 4; else - ep->max_transfer = usb_maxpacket(umidi->chip->dev, pipe, 1); + ep->max_transfer = usb_maxpacket(umidi->dev, pipe, 1); for (i = 0; i < OUTPUT_URBS; ++i) { - buffer = usb_buffer_alloc(umidi->chip->dev, + buffer = usb_buffer_alloc(umidi->dev, ep->max_transfer, GFP_KERNEL, &ep->urbs[i].urb->transfer_dma); if (!buffer) { @@ -1129,12 +1175,12 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi* umidi, return -ENOMEM; } if (ep_info->out_interval) - usb_fill_int_urb(ep->urbs[i].urb, umidi->chip->dev, + usb_fill_int_urb(ep->urbs[i].urb, umidi->dev, pipe, buffer, ep->max_transfer, snd_usbmidi_out_urb_complete, &ep->urbs[i], ep_info->out_interval); else - usb_fill_bulk_urb(ep->urbs[i].urb, umidi->chip->dev, + usb_fill_bulk_urb(ep->urbs[i].urb, umidi->dev, pipe, buffer, ep->max_transfer, snd_usbmidi_out_urb_complete, &ep->urbs[i]); @@ -1172,6 +1218,7 @@ static void snd_usbmidi_free(struct snd_usb_midi* umidi) if (ep->in) snd_usbmidi_in_endpoint_delete(ep->in); } + mutex_destroy(&umidi->mutex); kfree(umidi); } @@ -1367,7 +1414,7 @@ static struct port_info *find_port_info(struct snd_usb_midi* umidi, int number) int i; for (i = 0; i < ARRAY_SIZE(snd_usbmidi_port_info); ++i) { - if (snd_usbmidi_port_info[i].id == umidi->chip->usb_id && + if (snd_usbmidi_port_info[i].id == umidi->usb_id && snd_usbmidi_port_info[i].port == number) return &snd_usbmidi_port_info[i]; } @@ -1405,7 +1452,7 @@ static void snd_usbmidi_init_substream(struct snd_usb_midi* umidi, port_info = find_port_info(umidi, number); name_format = port_info ? port_info->name : "%s MIDI %d"; snprintf(substream->name, sizeof(substream->name), - name_format, umidi->chip->card->shortname, number + 1); + name_format, umidi->card->shortname, number + 1); *rsubstream = substream; } @@ -1503,7 +1550,7 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi, endpoints[epidx].out_ep = usb_endpoint_num(ep); if (usb_endpoint_xfer_int(ep)) endpoints[epidx].out_interval = ep->bInterval; - else if (snd_usb_get_speed(umidi->chip->dev) == USB_SPEED_LOW) + else if (snd_usb_get_speed(umidi->dev) == USB_SPEED_LOW) /* * Low speed bulk transfers don't exist, so * force interrupt transfers for devices like @@ -1523,7 +1570,7 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi, endpoints[epidx].in_ep = usb_endpoint_num(ep); if (usb_endpoint_xfer_int(ep)) endpoints[epidx].in_interval = ep->bInterval; - else if (snd_usb_get_speed(umidi->chip->dev) == USB_SPEED_LOW) + else if (snd_usb_get_speed(umidi->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", @@ -1533,6 +1580,52 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi, return 0; } +static int roland_load_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *info) +{ + static const char *const names[] = { "High Load", "Light Load" }; + + info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + info->count = 1; + info->value.enumerated.items = 2; + if (info->value.enumerated.item > 1) + info->value.enumerated.item = 1; + strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); + return 0; +} + +static int roland_load_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *value) +{ + value->value.enumerated.item[0] = kcontrol->private_value; + return 0; +} + +static int roland_load_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *value) +{ + struct snd_usb_midi* umidi = kcontrol->private_data; + int changed; + + if (value->value.enumerated.item[0] > 1) + return -EINVAL; + mutex_lock(&umidi->mutex); + changed = value->value.enumerated.item[0] != kcontrol->private_value; + if (changed) + kcontrol->private_value = value->value.enumerated.item[0]; + mutex_unlock(&umidi->mutex); + return changed; +} + +static struct snd_kcontrol_new roland_load_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "MIDI Input Mode", + .info = roland_load_info, + .get = roland_load_get, + .put = roland_load_put, + .private_value = 1, +}; + /* * On Roland devices, use the second alternate setting to be able to use * the interrupt input endpoint. @@ -1556,8 +1649,12 @@ static void snd_usbmidi_switch_roland_altsetting(struct snd_usb_midi* umidi) snd_printdd(KERN_INFO "switching to altsetting %d with int ep\n", intfd->bAlternateSetting); - usb_set_interface(umidi->chip->dev, intfd->bInterfaceNumber, + usb_set_interface(umidi->dev, intfd->bInterfaceNumber, intfd->bAlternateSetting); + + umidi->roland_load_ctl = snd_ctl_new1(&roland_load_ctl, umidi); + if (snd_ctl_add(umidi->card, umidi->roland_load_ctl) < 0) + umidi->roland_load_ctl = NULL; } /* @@ -1573,7 +1670,7 @@ static int snd_usbmidi_detect_endpoints(struct snd_usb_midi* umidi, struct usb_endpoint_descriptor* epd; int i, out_eps = 0, in_eps = 0; - if (USB_ID_VENDOR(umidi->chip->usb_id) == 0x0582) + if (USB_ID_VENDOR(umidi->usb_id) == 0x0582) snd_usbmidi_switch_roland_altsetting(umidi); if (endpoint[0].out_ep || endpoint[0].in_ep) @@ -1760,12 +1857,12 @@ static int snd_usbmidi_create_rawmidi(struct snd_usb_midi* umidi, struct snd_rawmidi *rmidi; int err; - err = snd_rawmidi_new(umidi->chip->card, "USB MIDI", - umidi->chip->next_midi_device++, + err = snd_rawmidi_new(umidi->card, "USB MIDI", + umidi->next_midi_device++, out_ports, in_ports, &rmidi); if (err < 0) return err; - strcpy(rmidi->name, umidi->chip->card->shortname); + strcpy(rmidi->name, umidi->card->shortname); rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX; @@ -1804,7 +1901,7 @@ static void snd_usbmidi_input_start_ep(struct snd_usb_midi_in_endpoint* ep) return; for (i = 0; i < INPUT_URBS; ++i) { struct urb* urb = ep->urbs[i]; - urb->dev = ep->umidi->chip->dev; + urb->dev = ep->umidi->dev; snd_usbmidi_submit_urb(urb, GFP_KERNEL); } } @@ -1825,9 +1922,10 @@ void snd_usbmidi_input_start(struct list_head* p) /* * Creates and registers everything needed for a MIDI streaming interface. */ -int snd_usb_create_midi_interface(struct snd_usb_audio* chip, - struct usb_interface* iface, - const struct snd_usb_audio_quirk* quirk) +int snd_usbmidi_create(struct snd_card *card, + struct usb_interface* iface, + struct list_head *midi_list, + const struct snd_usb_audio_quirk* quirk) { struct snd_usb_midi* umidi; struct snd_usb_midi_endpoint_info endpoints[MIDI_MAX_ENDPOINTS]; @@ -1837,12 +1935,16 @@ int snd_usb_create_midi_interface(struct snd_usb_audio* chip, umidi = kzalloc(sizeof(*umidi), GFP_KERNEL); if (!umidi) return -ENOMEM; - umidi->chip = chip; + umidi->dev = interface_to_usbdev(iface); + umidi->card = card; umidi->iface = iface; umidi->quirk = quirk; umidi->usb_protocol_ops = &snd_usbmidi_standard_ops; init_timer(&umidi->error_timer); spin_lock_init(&umidi->disc_lock); + mutex_init(&umidi->mutex); + umidi->usb_id = USB_ID(le16_to_cpu(umidi->dev->descriptor.idVendor), + le16_to_cpu(umidi->dev->descriptor.idProduct)); umidi->error_timer.function = snd_usbmidi_error_timer; umidi->error_timer.data = (unsigned long)umidi; @@ -1851,7 +1953,7 @@ int snd_usb_create_midi_interface(struct snd_usb_audio* chip, switch (quirk ? quirk->type : QUIRK_MIDI_STANDARD_INTERFACE) { case QUIRK_MIDI_STANDARD_INTERFACE: err = snd_usbmidi_get_ms_info(umidi, endpoints); - if (chip->usb_id == USB_ID(0x0763, 0x0150)) /* M-Audio Uno */ + if (umidi->usb_id == USB_ID(0x0763, 0x0150)) /* M-Audio Uno */ umidi->usb_protocol_ops = &snd_usbmidi_maudio_broken_running_status_ops; break; @@ -1887,7 +1989,7 @@ int snd_usb_create_midi_interface(struct snd_usb_audio* chip, * interface 0, so we have to make sure that the USB core looks * again at interface 0 by calling usb_set_interface() on it. */ - usb_set_interface(umidi->chip->dev, 0, 0); + usb_set_interface(umidi->dev, 0, 0); err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); break; case QUIRK_MIDI_EMAGIC: @@ -1914,8 +2016,8 @@ int snd_usb_create_midi_interface(struct snd_usb_audio* chip, out_ports = 0; in_ports = 0; for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) { - out_ports += snd_usbmidi_count_bits(endpoints[i].out_cables); - in_ports += snd_usbmidi_count_bits(endpoints[i].in_cables); + out_ports += hweight16(endpoints[i].out_cables); + in_ports += hweight16(endpoints[i].in_cables); } err = snd_usbmidi_create_rawmidi(umidi, out_ports, in_ports); if (err < 0) { @@ -1933,14 +2035,14 @@ int snd_usb_create_midi_interface(struct snd_usb_audio* chip, return err; } - list_add(&umidi->list, &umidi->chip->midi_list); + list_add_tail(&umidi->list, midi_list); for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) snd_usbmidi_input_start_ep(umidi->endpoints[i].in); return 0; } -EXPORT_SYMBOL(snd_usb_create_midi_interface); +EXPORT_SYMBOL(snd_usbmidi_create); EXPORT_SYMBOL(snd_usbmidi_input_stop); EXPORT_SYMBOL(snd_usbmidi_input_start); EXPORT_SYMBOL(snd_usbmidi_disconnect); diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index 9efcfd08d747..c998220b99c6 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -1071,6 +1071,15 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, unsig channels = (ftr[0] - 7) / csize - 1; master_bits = snd_usb_combine_bytes(ftr + 6, csize); + /* master configuration quirks */ + switch (state->chip->usb_id) { + case USB_ID(0x08bb, 0x2702): + snd_printk(KERN_INFO + "usbmixer: master volume quirk for PCM2702 chip\n"); + /* disable non-functional volume control */ + master_bits &= ~(1 << (USB_FEATURE_VOLUME - 1)); + break; + } if (channels > 0) first_ch_bits = snd_usb_combine_bytes(ftr + 6 + csize, csize); else diff --git a/sound/usb/usbmixer_maps.c b/sound/usb/usbmixer_maps.c index 3e5d66cf1f5a..77c35885e21c 100644 --- a/sound/usb/usbmixer_maps.c +++ b/sound/usb/usbmixer_maps.c @@ -277,6 +277,22 @@ static struct usbmix_name_map scratch_live_map[] = { { 0 } /* terminator */ }; +/* "Gamesurround Muse Pocket LT" looks same like "Sound Blaster MP3+" + * most importand difference is SU[8], it should be set to "Capture Source" + * to make alsamixer and PA working properly. + * FIXME: or mp3plus_map should use "Capture Source" too, + * so this maps can be merget + */ +static struct usbmix_name_map hercules_usb51_map[] = { + { 8, "Capture Source" }, /* SU, default "PCM Capture Source" */ + { 9, "Master Playback" }, /* FU, default "Speaker Playback" */ + { 10, "Mic Boost", 7 }, /* FU, default "Auto Gain Input" */ + { 11, "Line Capture" }, /* FU, default "PCM Capture" */ + { 13, "Mic Bypass Playback" }, /* FU, default "Mic Playback" */ + { 14, "Line Bypass Playback" }, /* FU, default "Line Playback" */ + { 0 } /* terminator */ +}; + /* * Control map entries */ @@ -316,6 +332,13 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = { .ignore_ctl_error = 1, }, { + /* Hercules Gamesurround Muse Pocket LT + * (USB 5.1 Channel Audio Adapter) + */ + .id = USB_ID(0x06f8, 0xc000), + .map = hercules_usb51_map, + }, + { .id = USB_ID(0x08bb, 0x2702), .map = linex_map, .ignore_ctl_error = 1, diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h index f6f201eb24ce..a892bda03df9 100644 --- a/sound/usb/usbquirks.h +++ b/sound/usb/usbquirks.h @@ -1563,6 +1563,29 @@ YAMAHA_DEVICE(0x7010, "UB99"), } } }, +{ + /* has ID 0x00ea when not in Advanced Driver mode */ + USB_DEVICE_VENDOR_SPEC(0x0582, 0x00e9), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + /* .vendor_name = "Roland", */ + /* .product_name = "UA-1G", */ + .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 + } + } + } +}, /* Guillemot devices */ { diff --git a/sound/usb/usx2y/us122l.c b/sound/usb/usx2y/us122l.c index 99f33766cd51..f71cd28eca6b 100644 --- a/sound/usb/usx2y/us122l.c +++ b/sound/usb/usx2y/us122l.c @@ -59,11 +59,33 @@ static int us122l_create_usbmidi(struct snd_card *card) .type = QUIRK_MIDI_US122L, .data = &quirk_data }; - struct usb_device *dev = US122L(card)->chip.dev; + struct usb_device *dev = US122L(card)->dev; struct usb_interface *iface = usb_ifnum_to_if(dev, 1); - return snd_usb_create_midi_interface(&US122L(card)->chip, - iface, &quirk); + return snd_usbmidi_create(card, iface, + &US122L(card)->midi_list, &quirk); +} + +static int us144_create_usbmidi(struct snd_card *card) +{ + static struct snd_usb_midi_endpoint_info quirk_data = { + .out_ep = 4, + .in_ep = 3, + .out_cables = 0x001, + .in_cables = 0x001 + }; + static struct snd_usb_audio_quirk quirk = { + .vendor_name = "US144", + .product_name = NAME_ALLCAPS, + .ifnum = 0, + .type = QUIRK_MIDI_US122L, + .data = &quirk_data + }; + struct usb_device *dev = US122L(card)->dev; + struct usb_interface *iface = usb_ifnum_to_if(dev, 0); + + return snd_usbmidi_create(card, iface, + &US122L(card)->midi_list, &quirk); } /* @@ -171,7 +193,12 @@ static int usb_stream_hwdep_open(struct snd_hwdep *hw, struct file *file) if (!us122l->first) us122l->first = file; - iface = usb_ifnum_to_if(us122l->chip.dev, 1); + + if (us122l->dev->descriptor.idProduct == USB_ID_US144) { + iface = usb_ifnum_to_if(us122l->dev, 0); + usb_autopm_get_interface(iface); + } + iface = usb_ifnum_to_if(us122l->dev, 1); usb_autopm_get_interface(iface); return 0; } @@ -179,8 +206,14 @@ static int usb_stream_hwdep_open(struct snd_hwdep *hw, struct file *file) static int usb_stream_hwdep_release(struct snd_hwdep *hw, struct file *file) { struct us122l *us122l = hw->private_data; - struct usb_interface *iface = usb_ifnum_to_if(us122l->chip.dev, 1); + struct usb_interface *iface; snd_printdd(KERN_DEBUG "%p %p\n", hw, file); + + if (us122l->dev->descriptor.idProduct == USB_ID_US144) { + iface = usb_ifnum_to_if(us122l->dev, 0); + usb_autopm_put_interface(iface); + } + iface = usb_ifnum_to_if(us122l->dev, 1); usb_autopm_put_interface(iface); if (us122l->first == file) us122l->first = NULL; @@ -264,7 +297,7 @@ static unsigned int usb_stream_hwdep_poll(struct snd_hwdep *hw, static void us122l_stop(struct us122l *us122l) { struct list_head *p; - list_for_each(p, &us122l->chip.midi_list) + list_for_each(p, &us122l->midi_list) snd_usbmidi_input_stop(p); usb_stream_stop(&us122l->sk); @@ -297,7 +330,7 @@ static bool us122l_start(struct us122l *us122l, unsigned use_packsize = 0; bool success = false; - if (us122l->chip.dev->speed == USB_SPEED_HIGH) { + if (us122l->dev->speed == USB_SPEED_HIGH) { /* The us-122l's descriptor defaults to iso max_packsize 78, which isn't needed for samplerates <= 48000. Lets save some memory: @@ -314,11 +347,11 @@ static bool us122l_start(struct us122l *us122l, break; } } - if (!usb_stream_new(&us122l->sk, us122l->chip.dev, 1, 2, + if (!usb_stream_new(&us122l->sk, us122l->dev, 1, 2, rate, use_packsize, period_frames, 6)) goto out; - err = us122l_set_sample_rate(us122l->chip.dev, rate); + err = us122l_set_sample_rate(us122l->dev, rate); if (err < 0) { us122l_stop(us122l); snd_printk(KERN_ERR "us122l_set_sample_rate error \n"); @@ -330,7 +363,7 @@ static bool us122l_start(struct us122l *us122l, snd_printk(KERN_ERR "us122l_start error %i \n", err); goto out; } - list_for_each(p, &us122l->chip.midi_list) + list_for_each(p, &us122l->midi_list) snd_usbmidi_input_start(p); success = true; out: @@ -357,7 +390,7 @@ static int usb_stream_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, err = -ENXIO; goto free; } - high_speed = us122l->chip.dev->speed == USB_SPEED_HIGH; + high_speed = us122l->dev->speed == USB_SPEED_HIGH; if ((cfg->sample_rate != 44100 && cfg->sample_rate != 48000 && (!high_speed || (cfg->sample_rate != 88200 && cfg->sample_rate != 96000))) || @@ -417,7 +450,7 @@ static int usb_stream_hwdep_new(struct snd_card *card) { int err; struct snd_hwdep *hw; - struct usb_device *dev = US122L(card)->chip.dev; + struct usb_device *dev = US122L(card)->dev; err = snd_hwdep_new(card, SND_USB_STREAM_ID, 0, &hw); if (err < 0) @@ -443,19 +476,29 @@ static bool us122l_create_card(struct snd_card *card) int err; struct us122l *us122l = US122L(card); - err = usb_set_interface(us122l->chip.dev, 1, 1); + if (us122l->dev->descriptor.idProduct == USB_ID_US144) { + err = usb_set_interface(us122l->dev, 0, 1); + if (err) { + snd_printk(KERN_ERR "usb_set_interface error \n"); + return false; + } + } + err = usb_set_interface(us122l->dev, 1, 1); if (err) { snd_printk(KERN_ERR "usb_set_interface error \n"); return false; } - pt_info_set(us122l->chip.dev, 0x11); - pt_info_set(us122l->chip.dev, 0x10); + pt_info_set(us122l->dev, 0x11); + pt_info_set(us122l->dev, 0x10); if (!us122l_start(us122l, 44100, 256)) return false; - err = us122l_create_usbmidi(card); + if (us122l->dev->descriptor.idProduct == USB_ID_US144) + err = us144_create_usbmidi(card); + else + err = us122l_create_usbmidi(card); if (err < 0) { snd_printk(KERN_ERR "us122l_create_usbmidi error %i \n", err); us122l_stop(us122l); @@ -465,7 +508,7 @@ static bool us122l_create_card(struct snd_card *card) if (err < 0) { /* release the midi resources */ struct list_head *p; - list_for_each(p, &us122l->chip.midi_list) + list_for_each(p, &us122l->midi_list) snd_usbmidi_disconnect(p); us122l_stop(us122l); @@ -477,7 +520,7 @@ static bool us122l_create_card(struct snd_card *card) static void snd_us122l_free(struct snd_card *card) { struct us122l *us122l = US122L(card); - int index = us122l->chip.index; + int index = us122l->card_index; if (index >= 0 && index < SNDRV_CARDS) snd_us122l_card_used[index] = 0; } @@ -497,13 +540,12 @@ static int usx2y_create_card(struct usb_device *device, struct snd_card **cardp) sizeof(struct us122l), &card); if (err < 0) return err; - snd_us122l_card_used[US122L(card)->chip.index = dev] = 1; + snd_us122l_card_used[US122L(card)->card_index = dev] = 1; card->private_free = snd_us122l_free; - US122L(card)->chip.dev = device; - US122L(card)->chip.card = card; + US122L(card)->dev = device; mutex_init(&US122L(card)->mutex); init_waitqueue_head(&US122L(card)->sk.sleep); - INIT_LIST_HEAD(&US122L(card)->chip.midi_list); + INIT_LIST_HEAD(&US122L(card)->midi_list); strcpy(card->driver, "USB "NAME_ALLCAPS""); sprintf(card->shortname, "TASCAM "NAME_ALLCAPS""); sprintf(card->longname, "%s (%x:%x if %d at %03d/%03d)", @@ -511,8 +553,8 @@ static int usx2y_create_card(struct usb_device *device, struct snd_card **cardp) le16_to_cpu(device->descriptor.idVendor), le16_to_cpu(device->descriptor.idProduct), 0, - US122L(card)->chip.dev->bus->busnum, - US122L(card)->chip.dev->devnum + US122L(card)->dev->bus->busnum, + US122L(card)->dev->devnum ); *cardp = card; return 0; @@ -542,6 +584,7 @@ static int us122l_usb_probe(struct usb_interface *intf, return err; } + usb_get_intf(usb_ifnum_to_if(device, 0)); usb_get_dev(device); *cardp = card; return 0; @@ -550,9 +593,16 @@ static int us122l_usb_probe(struct usb_interface *intf, static int snd_us122l_probe(struct usb_interface *intf, const struct usb_device_id *id) { + struct usb_device *device = interface_to_usbdev(intf); struct snd_card *card; int err; + if (device->descriptor.idProduct == USB_ID_US144 + && device->speed == USB_SPEED_HIGH) { + snd_printk(KERN_ERR "disable ehci-hcd to run US-144 \n"); + return -ENODEV; + } + snd_printdd(KERN_DEBUG"%p:%i\n", intf, intf->cur_altsetting->desc.bInterfaceNumber); if (intf->cur_altsetting->desc.bInterfaceNumber != 1) @@ -584,15 +634,15 @@ static void snd_us122l_disconnect(struct usb_interface *intf) mutex_lock(&us122l->mutex); us122l_stop(us122l); mutex_unlock(&us122l->mutex); - us122l->chip.shutdown = 1; /* release the midi resources */ - list_for_each(p, &us122l->chip.midi_list) { + list_for_each(p, &us122l->midi_list) { snd_usbmidi_disconnect(p); } - usb_put_intf(intf); - usb_put_dev(us122l->chip.dev); + usb_put_intf(usb_ifnum_to_if(us122l->dev, 0)); + usb_put_intf(usb_ifnum_to_if(us122l->dev, 1)); + usb_put_dev(us122l->dev); while (atomic_read(&us122l->mmap_count)) msleep(500); @@ -615,7 +665,7 @@ static int snd_us122l_suspend(struct usb_interface *intf, pm_message_t message) if (!us122l) return 0; - list_for_each(p, &us122l->chip.midi_list) + list_for_each(p, &us122l->midi_list) snd_usbmidi_input_stop(p); mutex_lock(&us122l->mutex); @@ -642,16 +692,23 @@ static int snd_us122l_resume(struct usb_interface *intf) mutex_lock(&us122l->mutex); /* needed, doesn't restart without: */ - err = usb_set_interface(us122l->chip.dev, 1, 1); + if (us122l->dev->descriptor.idProduct == USB_ID_US144) { + err = usb_set_interface(us122l->dev, 0, 1); + if (err) { + snd_printk(KERN_ERR "usb_set_interface error \n"); + goto unlock; + } + } + err = usb_set_interface(us122l->dev, 1, 1); if (err) { snd_printk(KERN_ERR "usb_set_interface error \n"); goto unlock; } - pt_info_set(us122l->chip.dev, 0x11); - pt_info_set(us122l->chip.dev, 0x10); + pt_info_set(us122l->dev, 0x11); + pt_info_set(us122l->dev, 0x10); - err = us122l_set_sample_rate(us122l->chip.dev, + err = us122l_set_sample_rate(us122l->dev, us122l->sk.s->cfg.sample_rate); if (err < 0) { snd_printk(KERN_ERR "us122l_set_sample_rate error \n"); @@ -661,7 +718,7 @@ static int snd_us122l_resume(struct usb_interface *intf) if (err) goto unlock; - list_for_each(p, &us122l->chip.midi_list) + list_for_each(p, &us122l->midi_list) snd_usbmidi_input_start(p); unlock: mutex_unlock(&us122l->mutex); @@ -675,11 +732,11 @@ static struct usb_device_id snd_us122l_usb_id_table[] = { .idVendor = 0x0644, .idProduct = USB_ID_US122L }, -/* { */ /* US-144 maybe works when @USB1.1. Untested. */ -/* .match_flags = USB_DEVICE_ID_MATCH_DEVICE, */ -/* .idVendor = 0x0644, */ -/* .idProduct = USB_ID_US144 */ -/* }, */ + { /* US-144 only works at USB1.1! Disable module ehci-hcd. */ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = 0x0644, + .idProduct = USB_ID_US144 + }, { /* terminator */ } }; diff --git a/sound/usb/usx2y/us122l.h b/sound/usb/usx2y/us122l.h index 3d10c4b2a0f5..4daf1982e821 100644 --- a/sound/usb/usx2y/us122l.h +++ b/sound/usb/usx2y/us122l.h @@ -3,7 +3,8 @@ struct us122l { - struct snd_usb_audio chip; + struct usb_device *dev; + int card_index; int stride; struct usb_stream_kernel sk; @@ -12,6 +13,7 @@ struct us122l { unsigned second_periods_polled; struct file *master; struct file *slave; + struct list_head midi_list; atomic_t mmap_count; }; diff --git a/sound/usb/usx2y/usX2Yhwdep.c b/sound/usb/usx2y/usX2Yhwdep.c index 52e04b2f35d3..1879b72c40f8 100644 --- a/sound/usb/usx2y/usX2Yhwdep.c +++ b/sound/usb/usx2y/usX2Yhwdep.c @@ -114,7 +114,7 @@ static int snd_usX2Y_hwdep_dsp_status(struct snd_hwdep *hw, struct usX2Ydev *us428 = hw->private_data; int id = -1; - switch (le16_to_cpu(us428->chip.dev->descriptor.idProduct)) { + switch (le16_to_cpu(us428->dev->descriptor.idProduct)) { case USB_ID_US122: id = USX2Y_TYPE_122; break; @@ -164,14 +164,14 @@ static int usX2Y_create_usbmidi(struct snd_card *card) .type = QUIRK_MIDI_FIXED_ENDPOINT, .data = &quirk_data_2 }; - struct usb_device *dev = usX2Y(card)->chip.dev; + struct usb_device *dev = usX2Y(card)->dev; struct usb_interface *iface = usb_ifnum_to_if(dev, 0); struct snd_usb_audio_quirk *quirk = le16_to_cpu(dev->descriptor.idProduct) == USB_ID_US428 ? &quirk_2 : &quirk_1; snd_printdd("usX2Y_create_usbmidi \n"); - return snd_usb_create_midi_interface(&usX2Y(card)->chip, iface, quirk); + return snd_usbmidi_create(card, iface, &usX2Y(card)->midi_list, quirk); } static int usX2Y_create_alsa_devices(struct snd_card *card) @@ -202,7 +202,7 @@ static int snd_usX2Y_hwdep_dsp_load(struct snd_hwdep *hw, snd_printdd( "dsp_load %s\n", dsp->name); if (access_ok(VERIFY_READ, dsp->image, dsp->length)) { - struct usb_device* dev = priv->chip.dev; + struct usb_device* dev = priv->dev; char *buf; buf = memdup_user(dsp->image, dsp->length); diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c index cb4bb8373ca2..c42350eed2eb 100644 --- a/sound/usb/usx2y/usbusx2y.c +++ b/sound/usb/usx2y/usbusx2y.c @@ -239,8 +239,8 @@ static void i_usX2Y_In04Int(struct urb *urb) for (j = 0; j < URBS_AsyncSeq && !err; ++j) if (0 == usX2Y->AS04.urb[j]->status) { struct us428_p4out *p4out = us428ctls->p4out + send; // FIXME if more than 1 p4out is new, 1 gets lost. - usb_fill_bulk_urb(usX2Y->AS04.urb[j], usX2Y->chip.dev, - usb_sndbulkpipe(usX2Y->chip.dev, 0x04), &p4out->val.vol, + usb_fill_bulk_urb(usX2Y->AS04.urb[j], usX2Y->dev, + usb_sndbulkpipe(usX2Y->dev, 0x04), &p4out->val.vol, p4out->type == eLT_Light ? sizeof(struct us428_lights) : 5, i_usX2Y_Out04Int, usX2Y); err = usb_submit_urb(usX2Y->AS04.urb[j], GFP_ATOMIC); @@ -253,7 +253,7 @@ static void i_usX2Y_In04Int(struct urb *urb) if (err) snd_printk(KERN_ERR "In04Int() usb_submit_urb err=%i\n", err); - urb->dev = usX2Y->chip.dev; + urb->dev = usX2Y->dev; usb_submit_urb(urb, GFP_ATOMIC); } @@ -273,8 +273,8 @@ int usX2Y_AsyncSeq04_init(struct usX2Ydev *usX2Y) err = -ENOMEM; break; } - usb_fill_bulk_urb( usX2Y->AS04.urb[i], usX2Y->chip.dev, - usb_sndbulkpipe(usX2Y->chip.dev, 0x04), + usb_fill_bulk_urb( usX2Y->AS04.urb[i], usX2Y->dev, + usb_sndbulkpipe(usX2Y->dev, 0x04), usX2Y->AS04.buffer + URB_DataLen_AsyncSeq*i, 0, i_usX2Y_Out04Int, usX2Y ); @@ -293,7 +293,7 @@ int usX2Y_In04_init(struct usX2Ydev *usX2Y) } init_waitqueue_head(&usX2Y->In04WaitQueue); - usb_fill_int_urb(usX2Y->In04urb, usX2Y->chip.dev, usb_rcvintpipe(usX2Y->chip.dev, 0x4), + usb_fill_int_urb(usX2Y->In04urb, usX2Y->dev, usb_rcvintpipe(usX2Y->dev, 0x4), usX2Y->In04Buf, 21, i_usX2Y_In04Int, usX2Y, 10); @@ -348,13 +348,12 @@ static int usX2Y_create_card(struct usb_device *device, struct snd_card **cardp) sizeof(struct usX2Ydev), &card); if (err < 0) return err; - snd_usX2Y_card_used[usX2Y(card)->chip.index = dev] = 1; + snd_usX2Y_card_used[usX2Y(card)->card_index = dev] = 1; card->private_free = snd_usX2Y_card_private_free; - usX2Y(card)->chip.dev = device; - usX2Y(card)->chip.card = card; + usX2Y(card)->dev = device; init_waitqueue_head(&usX2Y(card)->prepare_wait_queue); mutex_init(&usX2Y(card)->prepare_mutex); - INIT_LIST_HEAD(&usX2Y(card)->chip.midi_list); + INIT_LIST_HEAD(&usX2Y(card)->midi_list); strcpy(card->driver, "USB "NAME_ALLCAPS""); sprintf(card->shortname, "TASCAM "NAME_ALLCAPS""); sprintf(card->longname, "%s (%x:%x if %d at %03d/%03d)", @@ -362,7 +361,7 @@ static int usX2Y_create_card(struct usb_device *device, struct snd_card **cardp) le16_to_cpu(device->descriptor.idVendor), le16_to_cpu(device->descriptor.idProduct), 0,//us428(card)->usbmidi.ifnum, - usX2Y(card)->chip.dev->bus->busnum, usX2Y(card)->chip.dev->devnum + usX2Y(card)->dev->bus->busnum, usX2Y(card)->dev->devnum ); *cardp = card; return 0; @@ -432,8 +431,8 @@ static void snd_usX2Y_card_private_free(struct snd_card *card) usb_free_urb(usX2Y(card)->In04urb); if (usX2Y(card)->us428ctls_sharedmem) snd_free_pages(usX2Y(card)->us428ctls_sharedmem, sizeof(*usX2Y(card)->us428ctls_sharedmem)); - if (usX2Y(card)->chip.index >= 0 && usX2Y(card)->chip.index < SNDRV_CARDS) - snd_usX2Y_card_used[usX2Y(card)->chip.index] = 0; + if (usX2Y(card)->card_index >= 0 && usX2Y(card)->card_index < SNDRV_CARDS) + snd_usX2Y_card_used[usX2Y(card)->card_index] = 0; } /* @@ -445,13 +444,12 @@ static void usX2Y_usb_disconnect(struct usb_device *device, void* ptr) struct snd_card *card = ptr; struct usX2Ydev *usX2Y = usX2Y(card); struct list_head *p; - usX2Y->chip.shutdown = 1; usX2Y->chip_status = USX2Y_STAT_CHIP_HUP; usX2Y_unlinkSeq(&usX2Y->AS04); usb_kill_urb(usX2Y->In04urb); snd_card_disconnect(card); /* release the midi resources */ - list_for_each(p, &usX2Y->chip.midi_list) { + list_for_each(p, &usX2Y->midi_list) { snd_usbmidi_disconnect(p); } if (usX2Y->us428ctls_sharedmem) diff --git a/sound/usb/usx2y/usbusx2y.h b/sound/usb/usx2y/usbusx2y.h index 456b5fdbc339..1d174cea352b 100644 --- a/sound/usb/usx2y/usbusx2y.h +++ b/sound/usb/usx2y/usbusx2y.h @@ -22,7 +22,8 @@ struct snd_usX2Y_urbSeq { #include "usx2yhwdeppcm.h" struct usX2Ydev { - struct snd_usb_audio chip; + struct usb_device *dev; + int card_index; int stride; struct urb *In04urb; void *In04Buf; @@ -42,6 +43,9 @@ struct usX2Ydev { struct snd_usX2Y_substream *subs[4]; struct snd_usX2Y_substream * volatile prepare_subs; wait_queue_head_t prepare_wait_queue; + struct list_head midi_list; + struct list_head pcm_list; + int pcm_devs; }; diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c index 9efd27f6b52f..74a67a85aa81 100644 --- a/sound/usb/usx2y/usbusx2yaudio.c +++ b/sound/usb/usx2y/usbusx2yaudio.c @@ -199,7 +199,7 @@ static int usX2Y_urb_submit(struct snd_usX2Y_substream *subs, struct urb *urb, i return -ENODEV; urb->start_frame = (frame + NRURBS * nr_of_packs()); // let hcd do rollover sanity checks urb->hcpriv = NULL; - urb->dev = subs->usX2Y->chip.dev; /* we need to set this at each time */ + urb->dev = subs->usX2Y->dev; /* we need to set this at each time */ if ((err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { snd_printk(KERN_ERR "usb_submit_urb() returned %i\n", err); return err; @@ -300,7 +300,7 @@ static void usX2Y_error_sequence(struct usX2Ydev *usX2Y, "Sequence Error!(hcd_frame=%i ep=%i%s;wait=%i,frame=%i).\n" "Most propably some urb of usb-frame %i is still missing.\n" "Cause could be too long delays in usb-hcd interrupt handling.\n", - usb_get_current_frame_number(usX2Y->chip.dev), + usb_get_current_frame_number(usX2Y->dev), subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out", usX2Y->wait_iso_frame, urb->start_frame, usX2Y->wait_iso_frame); usX2Y_clients_stop(usX2Y); @@ -313,7 +313,7 @@ static void i_usX2Y_urb_complete(struct urb *urb) if (unlikely(atomic_read(&subs->state) < state_PREPARED)) { snd_printdd("hcd_frame=%i ep=%i%s status=%i start_frame=%i\n", - usb_get_current_frame_number(usX2Y->chip.dev), + usb_get_current_frame_number(usX2Y->dev), subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out", urb->status, urb->start_frame); return; @@ -424,7 +424,7 @@ static int usX2Y_urbs_allocate(struct snd_usX2Y_substream *subs) int i; unsigned int pipe; int is_playback = subs == subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK]; - struct usb_device *dev = subs->usX2Y->chip.dev; + struct usb_device *dev = subs->usX2Y->dev; pipe = is_playback ? usb_sndisocpipe(dev, subs->endpoint) : usb_rcvisocpipe(dev, subs->endpoint); @@ -500,7 +500,7 @@ static int usX2Y_urbs_start(struct snd_usX2Y_substream *subs) unsigned long pack; if (0 == i) atomic_set(&subs->state, state_STARTING3); - urb->dev = usX2Y->chip.dev; + urb->dev = usX2Y->dev; urb->transfer_flags = URB_ISO_ASAP; for (pack = 0; pack < nr_of_packs(); pack++) { urb->iso_frame_desc[pack].offset = subs->maxpacksize * pack; @@ -692,7 +692,7 @@ static int usX2Y_rate_set(struct usX2Ydev *usX2Y, int rate) } ((char*)(usbdata + i))[0] = ra[i].c1; ((char*)(usbdata + i))[1] = ra[i].c2; - usb_fill_bulk_urb(us->urb[i], usX2Y->chip.dev, usb_sndbulkpipe(usX2Y->chip.dev, 4), + usb_fill_bulk_urb(us->urb[i], usX2Y->dev, usb_sndbulkpipe(usX2Y->dev, 4), usbdata + i, 2, i_usX2Y_04Int, usX2Y); #ifdef OLD_USB us->urb[i]->transfer_flags = USB_QUEUE_BULK; @@ -740,17 +740,17 @@ static int usX2Y_format_set(struct usX2Ydev *usX2Y, snd_pcm_format_t format) alternate = 1; usX2Y->stride = 4; } - list_for_each(p, &usX2Y->chip.midi_list) { + list_for_each(p, &usX2Y->midi_list) { snd_usbmidi_input_stop(p); } usb_kill_urb(usX2Y->In04urb); - if ((err = usb_set_interface(usX2Y->chip.dev, 0, alternate))) { + if ((err = usb_set_interface(usX2Y->dev, 0, alternate))) { snd_printk(KERN_ERR "usb_set_interface error \n"); return err; } - usX2Y->In04urb->dev = usX2Y->chip.dev; + usX2Y->In04urb->dev = usX2Y->dev; err = usb_submit_urb(usX2Y->In04urb, GFP_KERNEL); - list_for_each(p, &usX2Y->chip.midi_list) { + list_for_each(p, &usX2Y->midi_list) { snd_usbmidi_input_start(p); } usX2Y->format = format; @@ -955,7 +955,7 @@ static int usX2Y_audio_stream_new(struct snd_card *card, int playback_endpoint, struct snd_pcm *pcm; int err, i; struct snd_usX2Y_substream **usX2Y_substream = - usX2Y(card)->subs + 2 * usX2Y(card)->chip.pcm_devs; + usX2Y(card)->subs + 2 * usX2Y(card)->pcm_devs; for (i = playback_endpoint ? SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE; i <= SNDRV_PCM_STREAM_CAPTURE; ++i) { @@ -971,7 +971,7 @@ static int usX2Y_audio_stream_new(struct snd_card *card, int playback_endpoint, usX2Y_substream[SNDRV_PCM_STREAM_PLAYBACK]->endpoint = playback_endpoint; usX2Y_substream[SNDRV_PCM_STREAM_CAPTURE]->endpoint = capture_endpoint; - err = snd_pcm_new(card, NAME_ALLCAPS" Audio", usX2Y(card)->chip.pcm_devs, + err = snd_pcm_new(card, NAME_ALLCAPS" Audio", usX2Y(card)->pcm_devs, playback_endpoint ? 1 : 0, 1, &pcm); if (err < 0) { @@ -987,7 +987,7 @@ static int usX2Y_audio_stream_new(struct snd_card *card, int playback_endpoint, pcm->private_free = snd_usX2Y_pcm_private_free; pcm->info_flags = 0; - sprintf(pcm->name, NAME_ALLCAPS" Audio #%d", usX2Y(card)->chip.pcm_devs); + sprintf(pcm->name, NAME_ALLCAPS" Audio #%d", usX2Y(card)->pcm_devs); if ((playback_endpoint && 0 > (err = snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream, @@ -1001,7 +1001,7 @@ static int usX2Y_audio_stream_new(struct snd_card *card, int playback_endpoint, snd_usX2Y_pcm_private_free(pcm); return err; } - usX2Y(card)->chip.pcm_devs++; + usX2Y(card)->pcm_devs++; return 0; } @@ -1013,14 +1013,14 @@ int usX2Y_audio_create(struct snd_card *card) { int err = 0; - INIT_LIST_HEAD(&usX2Y(card)->chip.pcm_list); + INIT_LIST_HEAD(&usX2Y(card)->pcm_list); if (0 > (err = usX2Y_audio_stream_new(card, 0xA, 0x8))) return err; - if (le16_to_cpu(usX2Y(card)->chip.dev->descriptor.idProduct) == USB_ID_US428) + if (le16_to_cpu(usX2Y(card)->dev->descriptor.idProduct) == USB_ID_US428) if (0 > (err = usX2Y_audio_stream_new(card, 0, 0xA))) return err; - if (le16_to_cpu(usX2Y(card)->chip.dev->descriptor.idProduct) != USB_ID_US122) + if (le16_to_cpu(usX2Y(card)->dev->descriptor.idProduct) != USB_ID_US122) err = usX2Y_rate_set(usX2Y(card), 44100); // Lets us428 recognize output-volume settings, disturbs us122. return err; } diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c index 4b2304c2e02d..9ed6c3956ca7 100644 --- a/sound/usb/usx2y/usx2yhwdeppcm.c +++ b/sound/usb/usx2y/usx2yhwdeppcm.c @@ -234,7 +234,7 @@ static void i_usX2Y_usbpcm_urb_complete(struct urb *urb) if (unlikely(atomic_read(&subs->state) < state_PREPARED)) { snd_printdd("hcd_frame=%i ep=%i%s status=%i start_frame=%i\n", - usb_get_current_frame_number(usX2Y->chip.dev), + usb_get_current_frame_number(usX2Y->dev), subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out", urb->status, urb->start_frame); return; @@ -318,7 +318,7 @@ static int usX2Y_usbpcm_urbs_allocate(struct snd_usX2Y_substream *subs) int i; unsigned int pipe; int is_playback = subs == subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK]; - struct usb_device *dev = subs->usX2Y->chip.dev; + struct usb_device *dev = subs->usX2Y->dev; pipe = is_playback ? usb_sndisocpipe(dev, subs->endpoint) : usb_rcvisocpipe(dev, subs->endpoint); @@ -441,7 +441,7 @@ static int usX2Y_usbpcm_urbs_start(struct snd_usX2Y_substream *subs) unsigned long pack; if (0 == u) atomic_set(&subs->state, state_STARTING3); - urb->dev = usX2Y->chip.dev; + urb->dev = usX2Y->dev; urb->transfer_flags = URB_ISO_ASAP; for (pack = 0; pack < nr_of_packs(); pack++) { urb->iso_frame_desc[pack].offset = subs->maxpacksize * (pack + u * nr_of_packs()); @@ -741,7 +741,7 @@ int usX2Y_hwdep_pcm_new(struct snd_card *card) int err; struct snd_hwdep *hw; struct snd_pcm *pcm; - struct usb_device *dev = usX2Y(card)->chip.dev; + struct usb_device *dev = usX2Y(card)->dev; if (1 != nr_of_packs()) return 0; |