summaryrefslogtreecommitdiffstats
path: root/sound/core
diff options
context:
space:
mode:
Diffstat (limited to 'sound/core')
-rw-r--r--sound/core/control.c5
-rw-r--r--sound/core/pcm_native.c55
-rw-r--r--sound/core/seq/seq.c5
-rw-r--r--sound/core/seq/seq_device.c103
4 files changed, 103 insertions, 65 deletions
diff --git a/sound/core/control.c b/sound/core/control.c
index b9611344ff9e..5c35bbaf881e 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -1745,8 +1745,13 @@ int snd_ctl_enum_info(struct snd_ctl_elem_info *info, unsigned int channels,
info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
info->count = channels;
info->value.enumerated.items = items;
+ if (!items)
+ return 0;
if (info->value.enumerated.item >= items)
info->value.enumerated.item = items - 1;
+ WARN(strlen(names[info->value.enumerated.item]) >= sizeof(info->value.enumerated.name),
+ "ALSA: too long item name '%s'\n",
+ names[info->value.enumerated.item]);
strlcpy(info->value.enumerated.name,
names[info->value.enumerated.item],
sizeof(info->value.enumerated.name));
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 166d59cdc86b..2f7ad10ee7c3 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -35,9 +35,6 @@
#include <sound/timer.h>
#include <sound/minors.h>
#include <asm/io.h>
-#if defined(CONFIG_MIPS) && defined(CONFIG_DMA_NONCOHERENT)
-#include <dma-coherence.h>
-#endif
/*
* Compatibility
@@ -195,6 +192,21 @@ int snd_pcm_info_user(struct snd_pcm_substream *substream,
return err;
}
+static bool hw_support_mmap(struct snd_pcm_substream *substream)
+{
+ if (!(substream->runtime->hw.info & SNDRV_PCM_INFO_MMAP))
+ return false;
+ /* check architectures that return -EINVAL from dma_mmap_coherent() */
+ /* FIXME: this should be some global flag */
+#if defined(CONFIG_C6X) || defined(CONFIG_FRV) || defined(CONFIG_MN10300) ||\
+ defined(CONFIG_PARISC) || defined(CONFIG_XTENSA)
+ if (!substream->ops->mmap &&
+ substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV)
+ return false;
+#endif
+ return true;
+}
+
#undef RULES_DEBUG
#ifdef RULES_DEBUG
@@ -372,8 +384,12 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
}
hw = &substream->runtime->hw;
- if (!params->info)
+ if (!params->info) {
params->info = hw->info & ~SNDRV_PCM_INFO_FIFO_IN_FRAMES;
+ if (!hw_support_mmap(substream))
+ params->info &= ~(SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID);
+ }
if (!params->fifo_size) {
m = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
@@ -2070,7 +2086,7 @@ int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream)
mask |= 1 << SNDRV_PCM_ACCESS_RW_INTERLEAVED;
if (hw->info & SNDRV_PCM_INFO_NONINTERLEAVED)
mask |= 1 << SNDRV_PCM_ACCESS_RW_NONINTERLEAVED;
- if (hw->info & SNDRV_PCM_INFO_MMAP) {
+ if (hw_support_mmap(substream)) {
if (hw->info & SNDRV_PCM_INFO_INTERLEAVED)
mask |= 1 << SNDRV_PCM_ACCESS_MMAP_INTERLEAVED;
if (hw->info & SNDRV_PCM_INFO_NONINTERLEAVED)
@@ -3249,20 +3265,6 @@ 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);
}
@@ -3307,13 +3309,6 @@ static const struct vm_operations_struct snd_pcm_vm_ops_data_fault = {
.fault = snd_pcm_mmap_data_fault,
};
-#ifndef ARCH_HAS_DMA_MMAP_COHERENT
-/* This should be defined / handled globally! */
-#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
-#define ARCH_HAS_DMA_MMAP_COHERENT
-#endif
-#endif
-
/*
* mmap the DMA buffer on RAM
*/
@@ -3329,7 +3324,7 @@ int snd_pcm_lib_default_mmap(struct snd_pcm_substream *substream,
area->vm_end - area->vm_start, area->vm_page_prot);
}
#endif /* CONFIG_GENERIC_ALLOCATOR */
-#ifdef ARCH_HAS_DMA_MMAP_COHERENT
+#ifndef CONFIG_X86 /* for avoiding warnings arch/x86/mm/pat.c */
if (!substream->ops->page &&
substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV)
return dma_mmap_coherent(substream->dma_buffer.dev.dev,
@@ -3337,11 +3332,7 @@ int snd_pcm_lib_default_mmap(struct snd_pcm_substream *substream,
substream->runtime->dma_area,
substream->runtime->dma_addr,
area->vm_end - area->vm_start);
-#elif defined(CONFIG_MIPS) && defined(CONFIG_DMA_NONCOHERENT)
- if (substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV &&
- !plat_device_is_coherent(substream->dma_buffer.dev.dev))
- area->vm_page_prot = pgprot_noncached(area->vm_page_prot);
-#endif /* ARCH_HAS_DMA_MMAP_COHERENT */
+#endif /* CONFIG_X86 */
/* mmap with fault handler */
area->vm_ops = &snd_pcm_vm_ops_data_fault;
return 0;
diff --git a/sound/core/seq/seq.c b/sound/core/seq/seq.c
index 712110561082..7e0aabb808a6 100644
--- a/sound/core/seq/seq.c
+++ b/sound/core/seq/seq.c
@@ -86,7 +86,6 @@ static int __init alsa_seq_init(void)
{
int err;
- snd_seq_autoload_lock();
if ((err = client_init_data()) < 0)
goto error;
@@ -110,8 +109,8 @@ static int __init alsa_seq_init(void)
if ((err = snd_seq_system_client_init()) < 0)
goto error;
+ snd_seq_autoload_init();
error:
- snd_seq_autoload_unlock();
return err;
}
@@ -131,6 +130,8 @@ static void __exit alsa_seq_exit(void)
/* release event memory */
snd_sequencer_memory_done();
+
+ snd_seq_autoload_exit();
}
module_init(alsa_seq_init)
diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c
index 91a786a783e1..0631bdadd12b 100644
--- a/sound/core/seq/seq_device.c
+++ b/sound/core/seq/seq_device.c
@@ -56,6 +56,7 @@ MODULE_LICENSE("GPL");
#define DRIVER_LOADED (1<<0)
#define DRIVER_REQUESTED (1<<1)
#define DRIVER_LOCKED (1<<2)
+#define DRIVER_REQUESTING (1<<3)
struct ops_list {
char id[ID_LEN]; /* driver id */
@@ -127,42 +128,82 @@ static void snd_seq_device_info(struct snd_info_entry *entry,
#ifdef CONFIG_MODULES
/* avoid auto-loading during module_init() */
-static int snd_seq_in_init;
+static atomic_t snd_seq_in_init = ATOMIC_INIT(1); /* blocked as default */
void snd_seq_autoload_lock(void)
{
- snd_seq_in_init++;
+ atomic_inc(&snd_seq_in_init);
}
void snd_seq_autoload_unlock(void)
{
- snd_seq_in_init--;
+ atomic_dec(&snd_seq_in_init);
}
-#endif
-void snd_seq_device_load_drivers(void)
+static void autoload_drivers(void)
{
-#ifdef CONFIG_MODULES
- struct ops_list *ops;
+ /* avoid reentrance */
+ if (atomic_inc_return(&snd_seq_in_init) == 1) {
+ struct ops_list *ops;
+
+ mutex_lock(&ops_mutex);
+ list_for_each_entry(ops, &opslist, list) {
+ if ((ops->driver & DRIVER_REQUESTING) &&
+ !(ops->driver & DRIVER_REQUESTED)) {
+ ops->used++;
+ mutex_unlock(&ops_mutex);
+ ops->driver |= DRIVER_REQUESTED;
+ request_module("snd-%s", ops->id);
+ mutex_lock(&ops_mutex);
+ ops->used--;
+ }
+ }
+ mutex_unlock(&ops_mutex);
+ }
+ atomic_dec(&snd_seq_in_init);
+}
- /* Calling request_module during module_init()
- * may cause blocking.
- */
- if (snd_seq_in_init)
- return;
+static void call_autoload(struct work_struct *work)
+{
+ autoload_drivers();
+}
- mutex_lock(&ops_mutex);
- list_for_each_entry(ops, &opslist, list) {
- if (! (ops->driver & DRIVER_LOADED) &&
- ! (ops->driver & DRIVER_REQUESTED)) {
- ops->used++;
- mutex_unlock(&ops_mutex);
- ops->driver |= DRIVER_REQUESTED;
- request_module("snd-%s", ops->id);
- mutex_lock(&ops_mutex);
- ops->used--;
- }
+static DECLARE_WORK(autoload_work, call_autoload);
+
+static void try_autoload(struct ops_list *ops)
+{
+ if (!ops->driver) {
+ ops->driver |= DRIVER_REQUESTING;
+ schedule_work(&autoload_work);
}
+}
+
+static void queue_autoload_drivers(void)
+{
+ struct ops_list *ops;
+
+ mutex_lock(&ops_mutex);
+ list_for_each_entry(ops, &opslist, list)
+ try_autoload(ops);
mutex_unlock(&ops_mutex);
+}
+
+void snd_seq_autoload_init(void)
+{
+ atomic_dec(&snd_seq_in_init);
+#ifdef CONFIG_SND_SEQUENCER_MODULE
+ /* initial autoload only when snd-seq is a module */
+ queue_autoload_drivers();
+#endif
+}
+#else
+#define try_autoload(ops) /* NOP */
+#endif
+
+void snd_seq_device_load_drivers(void)
+{
+#ifdef CONFIG_MODULES
+ queue_autoload_drivers();
+ flush_work(&autoload_work);
#endif
}
@@ -214,13 +255,14 @@ int snd_seq_device_new(struct snd_card *card, int device, char *id, int argsize,
ops->num_devices++;
mutex_unlock(&ops->reg_mutex);
- unlock_driver(ops);
-
if ((err = snd_device_new(card, SNDRV_DEV_SEQUENCER, dev, &dops)) < 0) {
snd_seq_device_free(dev);
return err;
}
+ try_autoload(ops);
+ unlock_driver(ops);
+
if (result)
*result = dev;
@@ -318,16 +360,12 @@ int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry,
entry->init_device == NULL || entry->free_device == NULL)
return -EINVAL;
- snd_seq_autoload_lock();
ops = find_driver(id, 1);
- if (ops == NULL) {
- snd_seq_autoload_unlock();
+ if (ops == NULL)
return -ENOMEM;
- }
if (ops->driver & DRIVER_LOADED) {
pr_warn("ALSA: seq: driver_register: driver '%s' already exists\n", id);
unlock_driver(ops);
- snd_seq_autoload_unlock();
return -EBUSY;
}
@@ -344,7 +382,6 @@ int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry,
mutex_unlock(&ops->reg_mutex);
unlock_driver(ops);
- snd_seq_autoload_unlock();
return 0;
}
@@ -554,6 +591,9 @@ static int __init alsa_seq_device_init(void)
static void __exit alsa_seq_device_exit(void)
{
+#ifdef CONFIG_MODULES
+ cancel_work_sync(&autoload_work);
+#endif
remove_drivers();
#ifdef CONFIG_PROC_FS
snd_info_free_entry(info_entry);
@@ -570,6 +610,7 @@ EXPORT_SYMBOL(snd_seq_device_new);
EXPORT_SYMBOL(snd_seq_device_register_driver);
EXPORT_SYMBOL(snd_seq_device_unregister_driver);
#ifdef CONFIG_MODULES
+EXPORT_SYMBOL(snd_seq_autoload_init);
EXPORT_SYMBOL(snd_seq_autoload_lock);
EXPORT_SYMBOL(snd_seq_autoload_unlock);
#endif
OpenPOWER on IntegriCloud