aboutsummaryrefslogtreecommitdiff
path: root/sound/core/pcm_native.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/core/pcm_native.c')
-rw-r--r--sound/core/pcm_native.c261
1 files changed, 149 insertions, 112 deletions
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 8bc7cb3db33..b653ab001fb 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -20,12 +20,12 @@
*/
#include <linux/mm.h>
+#include <linux/module.h>
#include <linux/file.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/time.h>
-#include <linux/pm_qos_params.h>
-#include <linux/uio.h>
+#include <linux/pm_qos.h>
+#include <linux/aio.h>
#include <linux/dma-mapping.h>
#include <sound/core.h>
#include <sound/control.h>
@@ -190,12 +190,12 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
if (!(params->rmask & (1 << k)))
continue;
#ifdef RULES_DEBUG
- printk(KERN_DEBUG "%s = ", snd_pcm_hw_param_names[k]);
- printk("%04x%04x%04x%04x -> ", m->bits[3], m->bits[2], m->bits[1], m->bits[0]);
+ pr_debug("%s = ", snd_pcm_hw_param_names[k]);
+ pr_cont("%04x%04x%04x%04x -> ", m->bits[3], m->bits[2], m->bits[1], m->bits[0]);
#endif
changed = snd_mask_refine(m, constrs_mask(constrs, k));
#ifdef RULES_DEBUG
- printk("%04x%04x%04x%04x\n", m->bits[3], m->bits[2], m->bits[1], m->bits[0]);
+ pr_cont("%04x%04x%04x%04x\n", m->bits[3], m->bits[2], m->bits[1], m->bits[0]);
#endif
if (changed)
params->cmask |= 1 << k;
@@ -210,21 +210,21 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
if (!(params->rmask & (1 << k)))
continue;
#ifdef RULES_DEBUG
- printk(KERN_DEBUG "%s = ", snd_pcm_hw_param_names[k]);
+ pr_debug("%s = ", snd_pcm_hw_param_names[k]);
if (i->empty)
- printk("empty");
+ pr_cont("empty");
else
- printk("%c%u %u%c",
+ pr_cont("%c%u %u%c",
i->openmin ? '(' : '[', i->min,
i->max, i->openmax ? ')' : ']');
- printk(" -> ");
+ pr_cont(" -> ");
#endif
changed = snd_interval_refine(i, constrs_interval(constrs, k));
#ifdef RULES_DEBUG
if (i->empty)
- printk("empty\n");
+ pr_cont("empty\n");
else
- printk("%c%u %u%c\n",
+ pr_cont("%c%u %u%c\n",
i->openmin ? '(' : '[', i->min,
i->max, i->openmax ? ')' : ']');
#endif
@@ -255,18 +255,18 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
if (!doit)
continue;
#ifdef RULES_DEBUG
- printk(KERN_DEBUG "Rule %d [%p]: ", k, r->func);
+ pr_debug("Rule %d [%p]: ", k, r->func);
if (r->var >= 0) {
- printk("%s = ", snd_pcm_hw_param_names[r->var]);
+ pr_cont("%s = ", snd_pcm_hw_param_names[r->var]);
if (hw_is_mask(r->var)) {
m = hw_param_mask(params, r->var);
- printk("%x", *m->bits);
+ pr_cont("%x", *m->bits);
} else {
i = hw_param_interval(params, r->var);
if (i->empty)
- printk("empty");
+ pr_cont("empty");
else
- printk("%c%u %u%c",
+ pr_cont("%c%u %u%c",
i->openmin ? '(' : '[', i->min,
i->max, i->openmax ? ')' : ']');
}
@@ -275,19 +275,19 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
changed = r->func(params, r);
#ifdef RULES_DEBUG
if (r->var >= 0) {
- printk(" -> ");
+ pr_cont(" -> ");
if (hw_is_mask(r->var))
- printk("%x", *m->bits);
+ pr_cont("%x", *m->bits);
else {
if (i->empty)
- printk("empty");
+ pr_cont("empty");
else
- printk("%c%u %u%c",
+ pr_cont("%c%u %u%c",
i->openmin ? '(' : '[', i->min,
i->max, i->openmax ? ')' : ']');
}
}
- printk("\n");
+ pr_cont("\n");
#endif
rstamps[k] = stamp;
if (changed && r->var >= 0) {
@@ -369,6 +369,14 @@ static int period_to_usecs(struct snd_pcm_runtime *runtime)
return usecs;
}
+static void snd_pcm_set_state(struct snd_pcm_substream *substream, int state)
+{
+ snd_pcm_stream_lock_irq(substream);
+ if (substream->runtime->status->state != SNDRV_PCM_STATE_DISCONNECTED)
+ substream->runtime->status->state = state;
+ snd_pcm_stream_unlock_irq(substream);
+}
+
static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
@@ -391,7 +399,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
return -EBADFD;
}
snd_pcm_stream_unlock_irq(substream);
-#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
+#if IS_ENABLED(CONFIG_SND_PCM_OSS)
if (!substream->oss.oss)
#endif
if (atomic_read(&substream->mmap_count))
@@ -423,6 +431,9 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
runtime->info = params->info;
runtime->rate_num = params->rate_num;
runtime->rate_den = params->rate_den;
+ runtime->no_period_wakeup =
+ (params->info & SNDRV_PCM_INFO_NO_PERIOD_WAKEUP) &&
+ (params->flags & SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP);
bits = snd_pcm_format_physical_width(runtime->format);
runtime->sample_bits = bits;
@@ -449,7 +460,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
runtime->boundary *= 2;
snd_pcm_timer_resolution_change(substream);
- runtime->status->state = SNDRV_PCM_STATE_SETUP;
+ snd_pcm_set_state(substream, SNDRV_PCM_STATE_SETUP);
if (pm_qos_request_active(&substream->latency_pm_qos_req))
pm_qos_remove_request(&substream->latency_pm_qos_req);
@@ -458,10 +469,10 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
PM_QOS_CPU_DMA_LATENCY, usecs);
return 0;
_error:
- /* hardware might be unuseable from this time,
+ /* hardware might be unusable from this time,
so we force application to retry to set
the correct hardware parameter settings */
- runtime->status->state = SNDRV_PCM_STATE_OPEN;
+ snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN);
if (substream->ops->hw_free != NULL)
substream->ops->hw_free(substream);
return err;
@@ -509,7 +520,7 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *substream)
return -EBADFD;
if (substream->ops->hw_free)
result = substream->ops->hw_free(substream);
- runtime->status->state = SNDRV_PCM_STATE_OPEN;
+ snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN);
pm_qos_remove_request(&substream->latency_pm_qos_req);
return result;
}
@@ -591,6 +602,8 @@ int snd_pcm_status(struct snd_pcm_substream *substream,
snd_pcm_update_hw_ptr(substream);
if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) {
status->tstamp = runtime->status->tstamp;
+ status->audio_tstamp =
+ runtime->status->audio_tstamp;
goto _tstamp_end;
}
}
@@ -885,6 +898,8 @@ static struct action_ops snd_pcm_action_start = {
/**
* snd_pcm_start - start all linked streams
* @substream: the PCM substream instance
+ *
+ * Return: Zero if successful, or a negative error code.
*/
int snd_pcm_start(struct snd_pcm_substream *substream)
{
@@ -938,8 +953,10 @@ static struct action_ops snd_pcm_action_stop = {
* @state: PCM state after stopping the stream
*
* The state of each stream is then changed to the given state unconditionally.
+ *
+ * Return: Zero if successful, or a negative error code.
*/
-int snd_pcm_stop(struct snd_pcm_substream *substream, int state)
+int snd_pcm_stop(struct snd_pcm_substream *substream, snd_pcm_state_t state)
{
return snd_pcm_action(&snd_pcm_action_stop, substream, state);
}
@@ -952,6 +969,8 @@ EXPORT_SYMBOL(snd_pcm_stop);
*
* After stopping, the state is changed to SETUP.
* Unlike snd_pcm_stop(), this affects only the given stream.
+ *
+ * Return: Zero if succesful, or a negative error code.
*/
int snd_pcm_drain_done(struct snd_pcm_substream *substream)
{
@@ -985,7 +1004,7 @@ static int snd_pcm_do_pause(struct snd_pcm_substream *substream, int push)
if (push)
snd_pcm_update_hw_ptr(substream);
/* The jiffies check in snd_pcm_update_hw_ptr*() is done by
- * a delta betwen the current jiffies, this gives a large enough
+ * a delta between the current jiffies, this gives a large enough
* delta, effectively to skip the check once.
*/
substream->runtime->hw_ptr_jiffies = jiffies - HZ * 1000;
@@ -1085,6 +1104,9 @@ static struct action_ops snd_pcm_action_suspend = {
* @substream: the PCM substream
*
* After this call, all streams are changed to SUSPENDED state.
+ *
+ * Return: Zero if successful (or @substream is %NULL), or a negative error
+ * code.
*/
int snd_pcm_suspend(struct snd_pcm_substream *substream)
{
@@ -1107,6 +1129,8 @@ EXPORT_SYMBOL(snd_pcm_suspend);
* @pcm: the PCM instance
*
* After this call, all streams are changed to SUSPENDED state.
+ *
+ * Return: Zero if successful (or @pcm is %NULL), or a negative error code.
*/
int snd_pcm_suspend_all(struct snd_pcm *pcm)
{
@@ -1317,7 +1341,7 @@ static void snd_pcm_post_prepare(struct snd_pcm_substream *substream, int state)
{
struct snd_pcm_runtime *runtime = substream->runtime;
runtime->control->appl_ptr = runtime->status->hw_ptr;
- runtime->status->state = SNDRV_PCM_STATE_PREPARED;
+ snd_pcm_set_state(substream, SNDRV_PCM_STATE_PREPARED);
}
static struct action_ops snd_pcm_action_prepare = {
@@ -1330,6 +1354,8 @@ static struct action_ops snd_pcm_action_prepare = {
* snd_pcm_prepare - prepare the PCM substream to be triggerable
* @substream: the PCM substream instance
* @file: file to refer f_flags
+ *
+ * Return: Zero if successful, or a negative error code.
*/
static int snd_pcm_prepare(struct snd_pcm_substream *substream,
struct file *file)
@@ -1357,7 +1383,14 @@ static int snd_pcm_prepare(struct snd_pcm_substream *substream,
static int snd_pcm_pre_drain_init(struct snd_pcm_substream *substream, int state)
{
- substream->runtime->trigger_master = substream;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ switch (runtime->status->state) {
+ case SNDRV_PCM_STATE_OPEN:
+ case SNDRV_PCM_STATE_DISCONNECTED:
+ case SNDRV_PCM_STATE_SUSPENDED:
+ return -EBADFD;
+ }
+ runtime->trigger_master = substream;
return 0;
}
@@ -1376,6 +1409,9 @@ static int snd_pcm_do_drain_init(struct snd_pcm_substream *substream, int state)
case SNDRV_PCM_STATE_RUNNING:
runtime->status->state = SNDRV_PCM_STATE_DRAINING;
break;
+ case SNDRV_PCM_STATE_XRUN:
+ runtime->status->state = SNDRV_PCM_STATE_SETUP;
+ break;
default:
break;
}
@@ -1479,20 +1515,34 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream,
break; /* all drained */
init_waitqueue_entry(&wait, current);
add_wait_queue(&to_check->sleep, &wait);
- set_current_state(TASK_INTERRUPTIBLE);
snd_pcm_stream_unlock_irq(substream);
up_read(&snd_pcm_link_rwsem);
snd_power_unlock(card);
- tout = schedule_timeout(10 * HZ);
+ if (runtime->no_period_wakeup)
+ tout = MAX_SCHEDULE_TIMEOUT;
+ else {
+ tout = 10;
+ if (runtime->rate) {
+ long t = runtime->period_size * 2 / runtime->rate;
+ tout = max(t, tout);
+ }
+ tout = msecs_to_jiffies(tout * 1000);
+ }
+ tout = schedule_timeout_interruptible(tout);
snd_power_lock(card);
down_read(&snd_pcm_link_rwsem);
snd_pcm_stream_lock_irq(substream);
remove_wait_queue(&to_check->sleep, &wait);
+ if (card->shutdown) {
+ result = -ENODEV;
+ break;
+ }
if (tout == 0) {
if (substream->runtime->status->state == SNDRV_PCM_STATE_SUSPENDED)
result = -ESTRPIPE;
else {
- snd_printd("playback drain error (DMA or IRQ trouble?)\n");
+ dev_dbg(substream->pcm->card->dev,
+ "playback drain error (DMA or IRQ trouble?)\n");
snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
result = -EIO;
}
@@ -1516,13 +1566,11 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream,
static int snd_pcm_drop(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime;
- struct snd_card *card;
int result = 0;
if (PCM_RUNTIME_CHECK(substream))
return -ENXIO;
runtime = substream->runtime;
- card = substream->pcm->card;
if (runtime->status->state == SNDRV_PCM_STATE_OPEN ||
runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED ||
@@ -1542,29 +1590,16 @@ static int snd_pcm_drop(struct snd_pcm_substream *substream)
}
-/* WARNING: Don't forget to fput back the file */
-static struct file *snd_pcm_file_fd(int fd)
+static bool is_pcm_file(struct file *file)
{
- struct file *file;
- struct inode *inode;
+ struct inode *inode = file_inode(file);
unsigned int minor;
- file = fget(fd);
- if (!file)
- return NULL;
- inode = file->f_path.dentry->d_inode;
- if (!S_ISCHR(inode->i_mode) ||
- imajor(inode) != snd_major) {
- fput(file);
- return NULL;
- }
+ if (!S_ISCHR(inode->i_mode) || imajor(inode) != snd_major)
+ return false;
minor = iminor(inode);
- if (!snd_lookup_minor_data(minor, SNDRV_DEVICE_TYPE_PCM_PLAYBACK) &&
- !snd_lookup_minor_data(minor, SNDRV_DEVICE_TYPE_PCM_CAPTURE)) {
- fput(file);
- return NULL;
- }
- return file;
+ return snd_lookup_minor_data(minor, SNDRV_DEVICE_TYPE_PCM_PLAYBACK) ||
+ snd_lookup_minor_data(minor, SNDRV_DEVICE_TYPE_PCM_CAPTURE);
}
/*
@@ -1573,15 +1608,24 @@ static struct file *snd_pcm_file_fd(int fd)
static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
{
int res = 0;
- struct file *file;
struct snd_pcm_file *pcm_file;
struct snd_pcm_substream *substream1;
+ struct snd_pcm_group *group;
+ struct fd f = fdget(fd);
- file = snd_pcm_file_fd(fd);
- if (!file)
+ if (!f.file)
return -EBADFD;
- pcm_file = file->private_data;
+ if (!is_pcm_file(f.file)) {
+ res = -EBADFD;
+ goto _badf;
+ }
+ pcm_file = f.file->private_data;
substream1 = pcm_file->substream;
+ group = kmalloc(sizeof(*group), GFP_KERNEL);
+ if (!group) {
+ res = -ENOMEM;
+ goto _nolock;
+ }
down_write(&snd_pcm_link_rwsem);
write_lock_irq(&snd_pcm_link_rwlock);
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN ||
@@ -1594,11 +1638,8 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
goto _end;
}
if (!snd_pcm_stream_linked(substream)) {
- substream->group = kmalloc(sizeof(struct snd_pcm_group), GFP_ATOMIC);
- if (substream->group == NULL) {
- res = -ENOMEM;
- goto _end;
- }
+ substream->group = group;
+ group = NULL;
spin_lock_init(&substream->group->lock);
INIT_LIST_HEAD(&substream->group->substreams);
list_add_tail(&substream->link_list, &substream->group->substreams);
@@ -1610,7 +1651,11 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
_end:
write_unlock_irq(&snd_pcm_link_rwlock);
up_write(&snd_pcm_link_rwsem);
- fput(file);
+ _nolock:
+ snd_card_unref(substream1->pcm->card);
+ kfree(group);
+ _badf:
+ fdput(f);
return res;
}
@@ -1959,7 +2004,7 @@ int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream)
if (runtime->dma_bytes) {
err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 0, runtime->dma_bytes);
if (err < 0)
- return -EINVAL;
+ return err;
}
if (!(hw->rates & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))) {
@@ -2022,7 +2067,7 @@ int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,
err = snd_pcm_hw_constraints_init(substream);
if (err < 0) {
- snd_printd("snd_pcm_hw_constraints_init failed\n");
+ pcm_dbg(pcm, "snd_pcm_hw_constraints_init failed\n");
goto error;
}
@@ -2033,7 +2078,7 @@ int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,
err = snd_pcm_hw_constraints_complete(substream);
if (err < 0) {
- snd_printd("snd_pcm_hw_constraints_complete failed\n");
+ pcm_dbg(pcm, "snd_pcm_hw_constraints_complete failed\n");
goto error;
}
@@ -2049,17 +2094,12 @@ EXPORT_SYMBOL(snd_pcm_open_substream);
static int snd_pcm_open_file(struct file *file,
struct snd_pcm *pcm,
- int stream,
- struct snd_pcm_file **rpcm_file)
+ int stream)
{
struct snd_pcm_file *pcm_file;
struct snd_pcm_substream *substream;
- struct snd_pcm_str *str;
int err;
- if (rpcm_file)
- *rpcm_file = NULL;
-
err = snd_pcm_open_substream(pcm, stream, file, &substream);
if (err < 0)
return err;
@@ -2071,13 +2111,11 @@ static int snd_pcm_open_file(struct file *file,
}
pcm_file->substream = substream;
if (substream->ref_count == 1) {
- str = substream->pstr;
substream->file = pcm_file;
substream->pcm_release = pcm_release_private;
}
file->private_data = pcm_file;
- if (rpcm_file)
- *rpcm_file = pcm_file;
+
return 0;
}
@@ -2089,7 +2127,10 @@ static int snd_pcm_playback_open(struct inode *inode, struct file *file)
return err;
pcm = snd_lookup_minor_data(iminor(inode),
SNDRV_DEVICE_TYPE_PCM_PLAYBACK);
- return snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_PLAYBACK);
+ err = snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_PLAYBACK);
+ if (pcm)
+ snd_card_unref(pcm->card);
+ return err;
}
static int snd_pcm_capture_open(struct inode *inode, struct file *file)
@@ -2100,13 +2141,15 @@ static int snd_pcm_capture_open(struct inode *inode, struct file *file)
return err;
pcm = snd_lookup_minor_data(iminor(inode),
SNDRV_DEVICE_TYPE_PCM_CAPTURE);
- return snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_CAPTURE);
+ err = snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_CAPTURE);
+ if (pcm)
+ snd_card_unref(pcm->card);
+ return err;
}
static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream)
{
int err;
- struct snd_pcm_file *pcm_file;
wait_queue_t wait;
if (pcm == NULL) {
@@ -2124,7 +2167,7 @@ static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream)
add_wait_queue(&pcm->open_wait, &wait);
mutex_lock(&pcm->open_mutex);
while (1) {
- err = snd_pcm_open_file(file, pcm, stream, &pcm_file);
+ err = snd_pcm_open_file(file, pcm, stream);
if (err >= 0)
break;
if (err == -EAGAIN) {
@@ -2138,6 +2181,10 @@ static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream)
mutex_unlock(&pcm->open_mutex);
schedule();
mutex_lock(&pcm->open_mutex);
+ if (pcm->card->shutdown) {
+ err = -ENODEV;
+ break;
+ }
if (signal_pending(current)) {
err = -ERESTARTSYS;
break;
@@ -2382,6 +2429,7 @@ static int snd_pcm_hwsync(struct snd_pcm_substream *substream)
case SNDRV_PCM_STATE_DRAINING:
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
goto __badfd;
+ /* Fall through */
case SNDRV_PCM_STATE_RUNNING:
if ((err = snd_pcm_update_hw_ptr(substream)) < 0)
break;
@@ -2414,6 +2462,7 @@ static int snd_pcm_delay(struct snd_pcm_substream *substream,
case SNDRV_PCM_STATE_DRAINING:
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
goto __badfd;
+ /* Fall through */
case SNDRV_PCM_STATE_RUNNING:
if ((err = snd_pcm_update_hw_ptr(substream)) < 0)
break;
@@ -2561,7 +2610,7 @@ static int snd_pcm_common_ioctl1(struct file *file,
return res;
}
}
- snd_printd("unknown ioctl = 0x%x\n", cmd);
+ pcm_dbg(substream->pcm, "unknown ioctl = 0x%x\n", cmd);
return -ENOTTY;
}
@@ -3013,17 +3062,15 @@ static const struct vm_operations_struct snd_pcm_vm_ops_status =
static int snd_pcm_mmap_status(struct snd_pcm_substream *substream, struct file *file,
struct vm_area_struct *area)
{
- struct snd_pcm_runtime *runtime;
long size;
if (!(area->vm_flags & VM_READ))
return -EINVAL;
- runtime = substream->runtime;
size = area->vm_end - area->vm_start;
if (size != PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status)))
return -EINVAL;
area->vm_ops = &snd_pcm_vm_ops_status;
area->vm_private_data = substream;
- area->vm_flags |= VM_RESERVED;
+ area->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
return 0;
}
@@ -3052,17 +3099,15 @@ static const struct vm_operations_struct snd_pcm_vm_ops_control =
static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file *file,
struct vm_area_struct *area)
{
- struct snd_pcm_runtime *runtime;
long size;
if (!(area->vm_flags & VM_READ))
return -EINVAL;
- runtime = substream->runtime;
size = area->vm_end - area->vm_start;
if (size != PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control)))
return -EINVAL;
area->vm_ops = &snd_pcm_vm_ops_control;
area->vm_private_data = substream;
- area->vm_flags |= VM_RESERVED;
+ area->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
return 0;
}
#else /* ! coherent mmap */
@@ -3153,10 +3198,18 @@ static const struct vm_operations_struct snd_pcm_vm_ops_data_fault = {
/*
* mmap the DMA buffer on RAM
*/
-static int snd_pcm_default_mmap(struct snd_pcm_substream *substream,
- struct vm_area_struct *area)
-{
- area->vm_flags |= VM_RESERVED;
+int snd_pcm_lib_default_mmap(struct snd_pcm_substream *substream,
+ struct vm_area_struct *area)
+{
+ area->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
+#ifdef CONFIG_GENERIC_ALLOCATOR
+ if (substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV_IRAM) {
+ area->vm_page_prot = pgprot_writecombine(area->vm_page_prot);
+ return remap_pfn_range(area, area->vm_start,
+ substream->dma_buffer.addr >> PAGE_SHIFT,
+ area->vm_end - area->vm_start, area->vm_page_prot);
+ }
+#endif /* CONFIG_GENERIC_ALLOCATOR */
#ifdef ARCH_HAS_DMA_MMAP_COHERENT
if (!substream->ops->page &&
substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV)
@@ -3174,6 +3227,7 @@ static int snd_pcm_default_mmap(struct snd_pcm_substream *substream,
area->vm_ops = &snd_pcm_vm_ops_data_fault;
return 0;
}
+EXPORT_SYMBOL_GPL(snd_pcm_lib_default_mmap);
/*
* mmap the DMA buffer on I/O memory area
@@ -3182,32 +3236,15 @@ static int snd_pcm_default_mmap(struct snd_pcm_substream *substream,
int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream,
struct vm_area_struct *area)
{
- long size;
- unsigned long offset;
+ struct snd_pcm_runtime *runtime = substream->runtime;;
area->vm_page_prot = pgprot_noncached(area->vm_page_prot);
- area->vm_flags |= VM_IO;
- size = area->vm_end - area->vm_start;
- offset = area->vm_pgoff << PAGE_SHIFT;
- if (io_remap_pfn_range(area, area->vm_start,
- (substream->runtime->dma_addr + offset) >> PAGE_SHIFT,
- size, area->vm_page_prot))
- return -EAGAIN;
- return 0;
+ return vm_iomap_memory(area, runtime->dma_addr, runtime->dma_bytes);
}
EXPORT_SYMBOL(snd_pcm_lib_mmap_iomem);
#endif /* SNDRV_PCM_INFO_MMAP */
-/* mmap callback with pgprot_noncached */
-int snd_pcm_lib_mmap_noncached(struct snd_pcm_substream *substream,
- struct vm_area_struct *area)
-{
- area->vm_page_prot = pgprot_noncached(area->vm_page_prot);
- return snd_pcm_default_mmap(substream, area);
-}
-EXPORT_SYMBOL(snd_pcm_lib_mmap_noncached);
-
/*
* mmap DMA buffer
*/
@@ -3248,7 +3285,7 @@ int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file,
if (substream->ops->mmap)
err = substream->ops->mmap(substream, area);
else
- err = snd_pcm_default_mmap(substream, area);
+ err = snd_pcm_lib_default_mmap(substream, area);
if (!err)
atomic_inc(&substream->mmap_count);
return err;