aboutsummaryrefslogtreecommitdiff
path: root/sound/core
diff options
context:
space:
mode:
Diffstat (limited to 'sound/core')
-rw-r--r--sound/core/Kconfig1
-rw-r--r--sound/core/control.c9
-rw-r--r--sound/core/hrtimer.c15
-rw-r--r--sound/core/isadma.c10
-rw-r--r--sound/core/oss/mixer_oss.c4
-rw-r--r--sound/core/pcm.c6
-rw-r--r--sound/core/pcm_lib.c4
-rw-r--r--sound/core/pcm_native.c91
-rw-r--r--sound/core/pcm_timer.c17
-rw-r--r--sound/core/rawmidi.c19
-rw-r--r--sound/core/sound.c4
-rw-r--r--sound/core/sound_oss.c2
12 files changed, 117 insertions, 65 deletions
diff --git a/sound/core/Kconfig b/sound/core/Kconfig
index c15682a2f9d..475455c7661 100644
--- a/sound/core/Kconfig
+++ b/sound/core/Kconfig
@@ -5,6 +5,7 @@ config SND_TIMER
config SND_PCM
tristate
select SND_TIMER
+ select GCD
config SND_HWDEP
tristate
diff --git a/sound/core/control.c b/sound/core/control.c
index a8b7fabe645..268ab747122 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/hrtimer.c b/sound/core/hrtimer.c
index 34c7d48f506..7f4d744ae40 100644
--- a/sound/core/hrtimer.c
+++ b/sound/core/hrtimer.c
@@ -37,14 +37,22 @@ static unsigned int resolution;
struct snd_hrtimer {
struct snd_timer *timer;
struct hrtimer hrt;
+ atomic_t running;
};
static enum hrtimer_restart snd_hrtimer_callback(struct hrtimer *hrt)
{
struct snd_hrtimer *stime = container_of(hrt, struct snd_hrtimer, hrt);
struct snd_timer *t = stime->timer;
+
+ if (!atomic_read(&stime->running))
+ return HRTIMER_NORESTART;
+
hrtimer_forward_now(hrt, ns_to_ktime(t->sticks * resolution));
snd_timer_interrupt(stime->timer, t->sticks);
+
+ if (!atomic_read(&stime->running))
+ return HRTIMER_NORESTART;
return HRTIMER_RESTART;
}
@@ -58,6 +66,7 @@ static int snd_hrtimer_open(struct snd_timer *t)
hrtimer_init(&stime->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
stime->timer = t;
stime->hrt.function = snd_hrtimer_callback;
+ atomic_set(&stime->running, 0);
t->private_data = stime;
return 0;
}
@@ -78,16 +87,18 @@ static int snd_hrtimer_start(struct snd_timer *t)
{
struct snd_hrtimer *stime = t->private_data;
+ atomic_set(&stime->running, 0);
+ hrtimer_cancel(&stime->hrt);
hrtimer_start(&stime->hrt, ns_to_ktime(t->sticks * resolution),
HRTIMER_MODE_REL);
+ atomic_set(&stime->running, 1);
return 0;
}
static int snd_hrtimer_stop(struct snd_timer *t)
{
struct snd_hrtimer *stime = t->private_data;
-
- hrtimer_cancel(&stime->hrt);
+ atomic_set(&stime->running, 0);
return 0;
}
diff --git a/sound/core/isadma.c b/sound/core/isadma.c
index 79f0f16af33..950e19ba91f 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 772423889eb..54e2eb56e4c 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 c69c60b2a48..6884ae031f6 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_lib.c b/sound/core/pcm_lib.c
index 30f410832a2..a27545b23ee 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -758,7 +758,7 @@ int snd_interval_ratnum(struct snd_interval *i,
int diff;
if (q == 0)
q = 1;
- den = div_down(num, q);
+ den = div_up(num, q);
if (den < rats[k].den_min)
continue;
if (den > rats[k].den_max)
@@ -794,7 +794,7 @@ int snd_interval_ratnum(struct snd_interval *i,
i->empty = 1;
return -EINVAL;
}
- den = div_up(num, q);
+ den = div_down(num, q);
if (den > rats[k].den_max)
continue;
if (den < rats[k].den_min)
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index ab73edf2c89..25b0641e6b8 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>
@@ -1917,13 +1918,13 @@ int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream)
err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_RATE,
hw->rate_min, hw->rate_max);
- if (err < 0)
- return err;
+ if (err < 0)
+ return err;
err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
hw->period_bytes_min, hw->period_bytes_max);
- if (err < 0)
- return err;
+ if (err < 0)
+ return err;
err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIODS,
hw->periods_min, hw->periods_max);
@@ -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/pcm_timer.c b/sound/core/pcm_timer.c
index ca8068b63d6..b01d9481d63 100644
--- a/sound/core/pcm_timer.c
+++ b/sound/core/pcm_timer.c
@@ -20,6 +20,7 @@
*/
#include <linux/time.h>
+#include <linux/gcd.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/timer.h>
@@ -28,22 +29,6 @@
* Timer functions
*/
-/* Greatest common divisor */
-static unsigned long gcd(unsigned long a, unsigned long b)
-{
- unsigned long r;
- if (a < b) {
- r = a;
- a = b;
- b = r;
- }
- while ((r = a % b) != 0) {
- a = b;
- b = r;
- }
- return b;
-}
-
void snd_pcm_timer_resolution_change(struct snd_pcm_substream *substream)
{
unsigned long rate, mult, fsize, l, post;
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c
index 70d6f25ba52..0f5a194695d 100644
--- a/sound/core/rawmidi.c
+++ b/sound/core/rawmidi.c
@@ -242,8 +242,6 @@ 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) {
@@ -280,9 +278,10 @@ static int open_substream(struct snd_rawmidi *rmidi,
substream->active_sensing = 0;
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++;
- rmidi->streams[substream->stream].substream_opened++;
return 0;
}
@@ -413,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;
@@ -466,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;
@@ -491,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)
@@ -1256,7 +1257,7 @@ static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf,
break;
count -= count1;
}
- if (file->f_flags & O_SYNC) {
+ if (file->f_flags & O_DSYNC) {
spin_lock_irq(&runtime->lock);
while (runtime->avail != runtime->buffer_size) {
wait_queue_t wait;
@@ -1338,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"
@@ -1359,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/core/sound.c b/sound/core/sound.c
index 7872a02f6ca..563d1967a0a 100644
--- a/sound/core/sound.c
+++ b/sound/core/sound.c
@@ -468,5 +468,5 @@ static void __exit alsa_sound_exit(void)
unregister_chrdev(major, "alsa");
}
-module_init(alsa_sound_init)
-module_exit(alsa_sound_exit)
+subsys_initcall(alsa_sound_init);
+module_exit(alsa_sound_exit);
diff --git a/sound/core/sound_oss.c b/sound/core/sound_oss.c
index 7fe12264ff8..0c164e5e432 100644
--- a/sound/core/sound_oss.c
+++ b/sound/core/sound_oss.c
@@ -93,7 +93,7 @@ static int snd_oss_kernel_minor(int type, struct snd_card *card, int dev)
default:
return -EINVAL;
}
- if (snd_BUG_ON(minor < 0 || minor >= SNDRV_OSS_MINORS))
+ if (minor < 0 || minor >= SNDRV_OSS_MINORS)
return -EINVAL;
return minor;
}