diff options
Diffstat (limited to 'sound/core/pcm_native.c')
| -rw-r--r-- | sound/core/pcm_native.c | 261 | 
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;  | 
