diff options
Diffstat (limited to 'sound/core')
44 files changed, 1332 insertions, 1290 deletions
| diff --git a/sound/core/Kconfig b/sound/core/Kconfig index 9749f9e8b45c..6e937a8146a1 100644 --- a/sound/core/Kconfig +++ b/sound/core/Kconfig @@ -18,8 +18,12 @@ config SND_DMAENGINE_PCM  config SND_HWDEP  	tristate +config SND_SEQ_DEVICE +	tristate +  config SND_RAWMIDI  	tristate +	select SND_SEQ_DEVICE if SND_SEQUENCER != n  config SND_COMPRESS_OFFLOAD  	tristate @@ -33,38 +37,15 @@ config SND_JACK_INPUT_DEV  	depends on SND_JACK  	default y if INPUT=y || INPUT=SND -config SND_SEQUENCER -	tristate "Sequencer support" -	select SND_TIMER -	help -	  Say Y or M to enable MIDI sequencer and router support.  This -	  feature allows routing and enqueueing of MIDI events.  Events -	  can be processed at a given time. - -	  Many programs require this feature, so you should enable it -	  unless you know what you're doing. - -config SND_SEQ_DUMMY -	tristate "Sequencer dummy client" -	depends on SND_SEQUENCER -	help -	  Say Y here to enable the dummy sequencer client.  This client -	  is a simple MIDI-through client: all normal input events are -	  redirected to the output port immediately. - -	  You don't need this unless you want to connect many MIDI -	  devices or applications together. - -	  To compile this driver as a module, choose M here: the module -	  will be called snd-seq-dummy. -  config SND_OSSEMUL +	bool "Enable OSS Emulation"  	select SOUND_OSS_CORE -	bool +	help +	  This option enables the build of OSS emulation layer.  config SND_MIXER_OSS  	tristate "OSS Mixer API" -	select SND_OSSEMUL +	depends on SND_OSSEMUL  	help  	  To enable OSS mixer API emulation (/dev/mixer*), say Y here  	  and read <file:Documentation/sound/alsa/OSS-Emulation.txt>. @@ -76,7 +57,7 @@ config SND_MIXER_OSS  config SND_PCM_OSS  	tristate "OSS PCM (digital audio) API" -	select SND_OSSEMUL +	depends on SND_OSSEMUL  	select SND_PCM  	help  	  To enable OSS digital audio (PCM) emulation (/dev/dsp*), say Y @@ -107,20 +88,6 @@ config SND_PCM_TIMER  	  For some embedded devices, we may disable it to reduce memory  	  footprint, about 20KB on x86_64 platform. -config SND_SEQUENCER_OSS -	bool "OSS Sequencer API" -	depends on SND_SEQUENCER -	select SND_OSSEMUL -	help -	  Say Y here to enable OSS sequencer emulation (both -	  /dev/sequencer and /dev/music interfaces). - -	  Many programs still use the OSS API, so say Y. - -	  If you choose M in "Sequencer support" (SND_SEQUENCER), -	  this will be compiled as a module. The module will be called -	  snd-seq-oss. -  config SND_HRTIMER  	tristate "HR-timer backend support"  	depends on HIGH_RES_TIMERS @@ -133,14 +100,6 @@ config SND_HRTIMER  	  To compile this driver as a module, choose M here: the module  	  will be called snd-hrtimer. -config SND_SEQ_HRTIMER_DEFAULT -	bool "Use HR-timer as default sequencer timer" -	depends on SND_HRTIMER && SND_SEQUENCER -	default y -	help -	  Say Y here to use the HR-timer backend as the default sequencer -	  timer. -  config SND_DYNAMIC_MINORS  	bool "Dynamic device file minor numbers"  	help diff --git a/sound/core/Makefile b/sound/core/Makefile index e85d9dd12c2d..e2066e2ef9f8 100644 --- a/sound/core/Makefile +++ b/sound/core/Makefile @@ -22,6 +22,7 @@ snd-pcm-$(CONFIG_SND_PCM_IEC958) += pcm_iec958.o  # for trace-points  CFLAGS_pcm_lib.o := -I$(src) +CFLAGS_pcm_native.o := -I$(src)  snd-pcm-dmaengine-objs := pcm_dmaengine.o @@ -30,6 +31,7 @@ snd-timer-objs    := timer.o  snd-hrtimer-objs  := hrtimer.o  snd-rtctimer-objs := rtctimer.o  snd-hwdep-objs    := hwdep.o +snd-seq-device-objs := seq_device.o  snd-compress-objs := compress_offload.o @@ -39,6 +41,7 @@ obj-$(CONFIG_SND_TIMER)		+= snd-timer.o  obj-$(CONFIG_SND_HRTIMER)	+= snd-hrtimer.o  obj-$(CONFIG_SND_PCM)		+= snd-pcm.o  obj-$(CONFIG_SND_DMAENGINE_PCM)	+= snd-pcm-dmaengine.o +obj-$(CONFIG_SND_SEQ_DEVICE)	+= snd-seq-device.o  obj-$(CONFIG_SND_RAWMIDI)	+= snd-rawmidi.o  obj-$(CONFIG_SND_OSSEMUL)	+= oss/ diff --git a/sound/core/control.c b/sound/core/control.c index c109b82eef4b..3c6be1452e35 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -747,65 +747,45 @@ static int snd_ctl_card_info(struct snd_card *card, struct snd_ctl_file * ctl,  static int snd_ctl_elem_list(struct snd_card *card,  			     struct snd_ctl_elem_list __user *_list)  { -	struct list_head *plist;  	struct snd_ctl_elem_list list;  	struct snd_kcontrol *kctl; -	struct snd_ctl_elem_id *dst, *id; +	struct snd_ctl_elem_id id;  	unsigned int offset, space, jidx; +	int err = 0;  	if (copy_from_user(&list, _list, sizeof(list)))  		return -EFAULT;  	offset = list.offset;  	space = list.space; -	/* try limit maximum space */ -	if (space > 16384) -		return -ENOMEM; + +	down_read(&card->controls_rwsem); +	list.count = card->controls_count; +	list.used = 0;  	if (space > 0) { -		/* allocate temporary buffer for atomic operation */ -		dst = vmalloc(space * sizeof(struct snd_ctl_elem_id)); -		if (dst == NULL) -			return -ENOMEM; -		down_read(&card->controls_rwsem); -		list.count = card->controls_count; -		plist = card->controls.next; -		while (plist != &card->controls) { -			if (offset == 0) -				break; -			kctl = snd_kcontrol(plist); -			if (offset < kctl->count) -				break; -			offset -= kctl->count; -			plist = plist->next; -		} -		list.used = 0; -		id = dst; -		while (space > 0 && plist != &card->controls) { -			kctl = snd_kcontrol(plist); -			for (jidx = offset; space > 0 && jidx < kctl->count; jidx++) { -				snd_ctl_build_ioff(id, kctl, jidx); -				id++; -				space--; +		list_for_each_entry(kctl, &card->controls, list) { +			if (offset >= kctl->count) { +				offset -= kctl->count; +				continue; +			} +			for (jidx = offset; jidx < kctl->count; jidx++) { +				snd_ctl_build_ioff(&id, kctl, jidx); +				if (copy_to_user(list.pids + list.used, &id, +						 sizeof(id))) { +					err = -EFAULT; +					goto out; +				}  				list.used++; +				if (!--space) +					goto out;  			} -			plist = plist->next;  			offset = 0;  		} -		up_read(&card->controls_rwsem); -		if (list.used > 0 && -		    copy_to_user(list.pids, dst, -				 list.used * sizeof(struct snd_ctl_elem_id))) { -			vfree(dst); -			return -EFAULT; -		} -		vfree(dst); -	} else { -		down_read(&card->controls_rwsem); -		list.count = card->controls_count; -		up_read(&card->controls_rwsem);  	} -	if (copy_to_user(_list, &list, sizeof(list))) -		return -EFAULT; -	return 0; + out: +	up_read(&card->controls_rwsem); +	if (!err && copy_to_user(_list, &list, sizeof(list))) +		err = -EFAULT; +	return err;  }  static bool validate_element_member_dimension(struct snd_ctl_elem_info *info) @@ -1577,7 +1557,7 @@ static ssize_t snd_ctl_read(struct file *file, char __user *buffer,  		struct snd_ctl_event ev;  		struct snd_kctl_event *kev;  		while (list_empty(&ctl->events)) { -			wait_queue_t wait; +			wait_queue_entry_t wait;  			if ((file->f_flags & O_NONBLOCK) != 0 || result > 0) {  				err = -EAGAIN;  				goto __end_lock; diff --git a/sound/core/ctljack.c b/sound/core/ctljack.c index 84a3cd683068..0249d5e6ac23 100644 --- a/sound/core/ctljack.c +++ b/sound/core/ctljack.c @@ -23,7 +23,7 @@ static int jack_detect_kctl_get(struct snd_kcontrol *kcontrol,  	return 0;  } -static struct snd_kcontrol_new jack_detect_kctl = { +static const struct snd_kcontrol_new jack_detect_kctl = {  	/* name is filled later */  	.iface = SNDRV_CTL_ELEM_IFACE_CARD,  	.access = SNDRV_CTL_ELEM_ACCESS_READ, diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c index 9602a7e38d8a..a73baa1242be 100644 --- a/sound/core/hwdep.c +++ b/sound/core/hwdep.c @@ -85,7 +85,7 @@ static int snd_hwdep_open(struct inode *inode, struct file * file)  	int major = imajor(inode);  	struct snd_hwdep *hw;  	int err; -	wait_queue_t wait; +	wait_queue_entry_t wait;  	if (major == snd_major) {  		hw = snd_lookup_minor_data(iminor(inode), diff --git a/sound/core/info.c b/sound/core/info.c index 8ab72e0f5932..bcf6a48cc70d 100644 --- a/sound/core/info.c +++ b/sound/core/info.c @@ -344,12 +344,12 @@ static ssize_t snd_info_text_entry_write(struct file *file,  		}  	}  	if (next > buf->len) { -		char *nbuf = krealloc(buf->buffer, PAGE_ALIGN(next), -				      GFP_KERNEL | __GFP_ZERO); +		char *nbuf = kvzalloc(PAGE_ALIGN(next), GFP_KERNEL);  		if (!nbuf) {  			err = -ENOMEM;  			goto error;  		} +		kvfree(buf->buffer);  		buf->buffer = nbuf;  		buf->len = PAGE_ALIGN(next);  	} @@ -427,7 +427,7 @@ static int snd_info_text_entry_release(struct inode *inode, struct file *file)  	single_release(inode, file);  	kfree(data->rbuffer);  	if (data->wbuffer) { -		kfree(data->wbuffer->buffer); +		kvfree(data->wbuffer->buffer);  		kfree(data->wbuffer);  	} @@ -652,7 +652,6 @@ int snd_info_get_line(struct snd_info_buffer *buffer, char *line, int len)  	*line = '\0';  	return 0;  } -  EXPORT_SYMBOL(snd_info_get_line);  /** @@ -690,7 +689,6 @@ const char *snd_info_get_str(char *dest, const char *src, int len)  		src++;  	return src;  } -  EXPORT_SYMBOL(snd_info_get_str);  /* @@ -748,7 +746,6 @@ struct snd_info_entry *snd_info_create_module_entry(struct module * module,  		entry->module = module;  	return entry;  } -  EXPORT_SYMBOL(snd_info_create_module_entry);  /** @@ -772,7 +769,6 @@ struct snd_info_entry *snd_info_create_card_entry(struct snd_card *card,  	}  	return entry;  } -  EXPORT_SYMBOL(snd_info_create_card_entry);  static void snd_info_disconnect(struct snd_info_entry *entry) @@ -815,7 +811,6 @@ void snd_info_free_entry(struct snd_info_entry * entry)  		entry->private_free(entry);  	kfree(entry);  } -  EXPORT_SYMBOL(snd_info_free_entry);  /** @@ -858,7 +853,6 @@ int snd_info_register(struct snd_info_entry * entry)  	mutex_unlock(&info_mutex);  	return 0;  } -  EXPORT_SYMBOL(snd_info_register);  /* diff --git a/sound/core/info_oss.c b/sound/core/info_oss.c index 1478c8dfd473..f479374b6bd8 100644 --- a/sound/core/info_oss.c +++ b/sound/core/info_oss.c @@ -61,7 +61,6 @@ int snd_oss_info_register(int dev, int num, char *string)  	mutex_unlock(&strings);  	return 0;  } -  EXPORT_SYMBOL(snd_oss_info_register);  static int snd_sndstat_show_strings(struct snd_info_buffer *buf, char *id, int dev) diff --git a/sound/core/init.c b/sound/core/init.c index 6bda8436d765..b4365bcf28a7 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -452,7 +452,6 @@ int snd_card_disconnect(struct snd_card *card)  #endif  	return 0;	  } -  EXPORT_SYMBOL(snd_card_disconnect);  static int snd_card_do_free(struct snd_card *card) @@ -718,7 +717,7 @@ int snd_card_add_dev_attr(struct snd_card *card,  	dev_err(card->dev, "Too many groups assigned\n");  	return -ENOSPC; -}; +}  EXPORT_SYMBOL_GPL(snd_card_add_dev_attr);  /** @@ -775,7 +774,6 @@ int snd_card_register(struct snd_card *card)  #endif  	return 0;  } -  EXPORT_SYMBOL(snd_card_register);  #ifdef CONFIG_SND_PROC_FS @@ -895,7 +893,6 @@ int snd_component_add(struct snd_card *card, const char *component)  	strcat(card->components, component);  	return 0;  } -  EXPORT_SYMBOL(snd_component_add);  /** @@ -930,7 +927,6 @@ int snd_card_file_add(struct snd_card *card, struct file *file)  	spin_unlock(&card->files_lock);  	return 0;  } -  EXPORT_SYMBOL(snd_card_file_add);  /** @@ -972,7 +968,6 @@ int snd_card_file_remove(struct snd_card *card, struct file *file)  	put_device(&card->card_dev);  	return 0;  } -  EXPORT_SYMBOL(snd_card_file_remove);  #ifdef CONFIG_PM @@ -989,7 +984,7 @@ EXPORT_SYMBOL(snd_card_file_remove);   */  int snd_power_wait(struct snd_card *card, unsigned int power_state)  { -	wait_queue_t wait; +	wait_queue_entry_t wait;  	int result = 0;  	/* fastpath */ @@ -1012,6 +1007,5 @@ int snd_power_wait(struct snd_card *card, unsigned int power_state)  	remove_wait_queue(&card->power_sleep, &wait);  	return result;  } -  EXPORT_SYMBOL(snd_power_wait);  #endif /* CONFIG_PM */ diff --git a/sound/core/isadma.c b/sound/core/isadma.c index 31e8544d7f2d..7a8515abb5f9 100644 --- a/sound/core/isadma.c +++ b/sound/core/isadma.c @@ -55,7 +55,6 @@ void snd_dma_program(unsigned long dma,  		enable_dma(dma);  	release_dma_lock(flags);  } -  EXPORT_SYMBOL(snd_dma_program);  /** @@ -73,7 +72,6 @@ void snd_dma_disable(unsigned long dma)  	disable_dma(dma);  	release_dma_lock(flags);  } -  EXPORT_SYMBOL(snd_dma_disable);  /** @@ -113,5 +111,4 @@ unsigned int snd_dma_pointer(unsigned long dma, unsigned int size)  	else  		return size - result;  } -  EXPORT_SYMBOL(snd_dma_pointer); diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c index f05cb6a8cbe0..7f89d3c79a4b 100644 --- a/sound/core/memalloc.c +++ b/sound/core/memalloc.c @@ -54,6 +54,7 @@ void *snd_malloc_pages(size_t size, gfp_t gfp_flags)  	pg = get_order(size);  	return (void *) __get_free_pages(gfp_flags, pg);  } +EXPORT_SYMBOL(snd_malloc_pages);  /**   * snd_free_pages - release the pages @@ -71,6 +72,7 @@ void snd_free_pages(void *ptr, size_t size)  	pg = get_order(size);  	free_pages((unsigned long) ptr, pg);  } +EXPORT_SYMBOL(snd_free_pages);  /*   * @@ -217,6 +219,7 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size,  	dmab->bytes = size;  	return 0;  } +EXPORT_SYMBOL(snd_dma_alloc_pages);  /**   * snd_dma_alloc_pages_fallback - allocate the buffer area according to the given type with fallback @@ -254,6 +257,7 @@ int snd_dma_alloc_pages_fallback(int type, struct device *device, size_t size,  		return -ENOMEM;  	return 0;  } +EXPORT_SYMBOL(snd_dma_alloc_pages_fallback);  /** @@ -287,13 +291,4 @@ void snd_dma_free_pages(struct snd_dma_buffer *dmab)  		pr_err("snd-malloc: invalid device type %d\n", dmab->dev.type);  	}  } - -/* - * exports - */ -EXPORT_SYMBOL(snd_dma_alloc_pages); -EXPORT_SYMBOL(snd_dma_alloc_pages_fallback);  EXPORT_SYMBOL(snd_dma_free_pages); - -EXPORT_SYMBOL(snd_malloc_pages); -EXPORT_SYMBOL(snd_free_pages); diff --git a/sound/core/memory.c b/sound/core/memory.c index 4cd664efad77..19c9ea90d9bf 100644 --- a/sound/core/memory.c +++ b/sound/core/memory.c @@ -55,7 +55,6 @@ int copy_to_user_fromio(void __user *dst, const volatile void __iomem *src, size  	return 0;  #endif  } -  EXPORT_SYMBOL(copy_to_user_fromio);  /** @@ -88,5 +87,4 @@ int copy_from_user_toio(volatile void __iomem *dst, const void __user *src, size  	return 0;  #endif  } -  EXPORT_SYMBOL(copy_from_user_toio); diff --git a/sound/core/misc.c b/sound/core/misc.c index 21b228046e88..0f818d593c9e 100644 --- a/sound/core/misc.c +++ b/sound/core/misc.c @@ -48,7 +48,6 @@ void release_and_free_resource(struct resource *res)  		kfree(res);  	}  } -  EXPORT_SYMBOL(release_and_free_resource);  #ifdef CONFIG_SND_VERBOSE_PRINTK diff --git a/sound/core/oss/io.c b/sound/core/oss/io.c index 6faa1d719206..d870b2d93135 100644 --- a/sound/core/oss/io.c +++ b/sound/core/oss/io.c @@ -26,9 +26,9 @@  #include "pcm_plugin.h"  #define pcm_write(plug,buf,count) snd_pcm_oss_write3(plug,buf,count,1) -#define pcm_writev(plug,vec,count) snd_pcm_oss_writev3(plug,vec,count,1) +#define pcm_writev(plug,vec,count) snd_pcm_oss_writev3(plug,vec,count)  #define pcm_read(plug,buf,count) snd_pcm_oss_read3(plug,buf,count,1) -#define pcm_readv(plug,vec,count) snd_pcm_oss_readv3(plug,vec,count,1) +#define pcm_readv(plug,vec,count) snd_pcm_oss_readv3(plug,vec,count)  /*   *  Basic io plugin diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c index 2ff9c12d664a..379bf486ccc7 100644 --- a/sound/core/oss/mixer_oss.c +++ b/sound/core/oss/mixer_oss.c @@ -395,6 +395,7 @@ int snd_mixer_oss_ioctl_card(struct snd_card *card, unsigned int cmd, unsigned l  	fmixer.mixer = card->mixer_oss;  	return snd_mixer_oss_ioctl1(&fmixer, cmd, arg);  } +EXPORT_SYMBOL(snd_mixer_oss_ioctl_card);  #ifdef CONFIG_COMPAT  /* all compatible */ @@ -1425,5 +1426,3 @@ static void __exit alsa_mixer_oss_exit(void)  module_init(alsa_mixer_oss_init)  module_exit(alsa_mixer_oss_exit) - -EXPORT_SYMBOL(snd_mixer_oss_ioctl_card); diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 36baf962f9b0..e49f448ee04f 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -67,18 +67,6 @@ static int snd_pcm_oss_get_rate(struct snd_pcm_oss_file *pcm_oss_file);  static int snd_pcm_oss_get_channels(struct snd_pcm_oss_file *pcm_oss_file);  static int snd_pcm_oss_get_format(struct snd_pcm_oss_file *pcm_oss_file); -static inline mm_segment_t snd_enter_user(void) -{ -	mm_segment_t fs = get_fs(); -	set_fs(get_ds()); -	return fs; -} - -static inline void snd_leave_user(mm_segment_t fs) -{ -	set_fs(fs); -} -  /*   * helper functions to process hw_params   */ @@ -799,7 +787,7 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream,  static int choose_rate(struct snd_pcm_substream *substream,  		       struct snd_pcm_hw_params *params, unsigned int best_rate)  { -	struct snd_interval *it; +	const struct snd_interval *it;  	struct snd_pcm_hw_params *save;  	unsigned int rate, prev; @@ -807,7 +795,7 @@ static int choose_rate(struct snd_pcm_substream *substream,  	if (save == NULL)  		return -ENOMEM;  	*save = *params; -	it = hw_param_interval(save, SNDRV_PCM_HW_PARAM_RATE); +	it = hw_param_interval_c(save, SNDRV_PCM_HW_PARAM_RATE);  	/* try multiples of the best rate */  	rate = best_rate; @@ -848,7 +836,7 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream,  	int direct;  	snd_pcm_format_t format, sformat;  	int n; -	struct snd_mask sformat_mask; +	const struct snd_mask *sformat_mask;  	struct snd_mask mask;  	if (trylock) { @@ -891,18 +879,18 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream,  	format = snd_pcm_oss_format_from(runtime->oss.format); -	sformat_mask = *hw_param_mask(sparams, SNDRV_PCM_HW_PARAM_FORMAT); +	sformat_mask = hw_param_mask_c(sparams, SNDRV_PCM_HW_PARAM_FORMAT);  	if (direct)  		sformat = format;  	else -		sformat = snd_pcm_plug_slave_format(format, &sformat_mask); +		sformat = snd_pcm_plug_slave_format(format, sformat_mask);  	if ((__force int)sformat < 0 || -	    !snd_mask_test(&sformat_mask, (__force int)sformat)) { +	    !snd_mask_test(sformat_mask, (__force int)sformat)) {  		for (sformat = (__force snd_pcm_format_t)0;  		     (__force int)sformat <= (__force int)SNDRV_PCM_FORMAT_LAST;  		     sformat = (__force snd_pcm_format_t)((__force int)sformat + 1)) { -			if (snd_mask_test(&sformat_mask, (__force int)sformat) && +			if (snd_mask_test(sformat_mask, (__force int)sformat) &&  			    snd_pcm_oss_format_to(sformat) >= 0)  				break;  		} @@ -1191,14 +1179,8 @@ snd_pcm_sframes_t snd_pcm_oss_write3(struct snd_pcm_substream *substream, const  			if (ret < 0)  				break;  		} -		if (in_kernel) { -			mm_segment_t fs; -			fs = snd_enter_user(); -			ret = snd_pcm_lib_write(substream, (void __force __user *)ptr, frames); -			snd_leave_user(fs); -		} else { -			ret = snd_pcm_lib_write(substream, (void __force __user *)ptr, frames); -		} +		ret = __snd_pcm_lib_xfer(substream, (void *)ptr, true, +					 frames, in_kernel);  		if (ret != -EPIPE && ret != -ESTRPIPE)  			break;  		/* test, if we can't store new data, because the stream */ @@ -1234,14 +1216,8 @@ snd_pcm_sframes_t snd_pcm_oss_read3(struct snd_pcm_substream *substream, char *p  		ret = snd_pcm_oss_capture_position_fixup(substream, &delay);  		if (ret < 0)  			break; -		if (in_kernel) { -			mm_segment_t fs; -			fs = snd_enter_user(); -			ret = snd_pcm_lib_read(substream, (void __force __user *)ptr, frames); -			snd_leave_user(fs); -		} else { -			ret = snd_pcm_lib_read(substream, (void __force __user *)ptr, frames); -		} +		ret = __snd_pcm_lib_xfer(substream, (void *)ptr, true, +					 frames, in_kernel);  		if (ret == -EPIPE) {  			if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) {  				ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL); @@ -1256,7 +1232,8 @@ snd_pcm_sframes_t snd_pcm_oss_read3(struct snd_pcm_substream *substream, char *p  	return ret;  } -snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream, void **bufs, snd_pcm_uframes_t frames, int in_kernel) +#ifdef CONFIG_SND_PCM_OSS_PLUGINS +snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream, void **bufs, snd_pcm_uframes_t frames)  {  	struct snd_pcm_runtime *runtime = substream->runtime;  	int ret; @@ -1273,14 +1250,7 @@ snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream, void  			if (ret < 0)  				break;  		} -		if (in_kernel) { -			mm_segment_t fs; -			fs = snd_enter_user(); -			ret = snd_pcm_lib_writev(substream, (void __user **)bufs, frames); -			snd_leave_user(fs); -		} else { -			ret = snd_pcm_lib_writev(substream, (void __user **)bufs, frames); -		} +		ret = snd_pcm_kernel_writev(substream, bufs, frames);  		if (ret != -EPIPE && ret != -ESTRPIPE)  			break; @@ -1292,7 +1262,7 @@ snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream, void  	return ret;  } -snd_pcm_sframes_t snd_pcm_oss_readv3(struct snd_pcm_substream *substream, void **bufs, snd_pcm_uframes_t frames, int in_kernel) +snd_pcm_sframes_t snd_pcm_oss_readv3(struct snd_pcm_substream *substream, void **bufs, snd_pcm_uframes_t frames)  {  	struct snd_pcm_runtime *runtime = substream->runtime;  	int ret; @@ -1313,19 +1283,13 @@ snd_pcm_sframes_t snd_pcm_oss_readv3(struct snd_pcm_substream *substream, void *  			if (ret < 0)  				break;  		} -		if (in_kernel) { -			mm_segment_t fs; -			fs = snd_enter_user(); -			ret = snd_pcm_lib_readv(substream, (void __user **)bufs, frames); -			snd_leave_user(fs); -		} else { -			ret = snd_pcm_lib_readv(substream, (void __user **)bufs, frames); -		} +		ret = snd_pcm_kernel_readv(substream, bufs, frames);  		if (ret != -EPIPE && ret != -ESTRPIPE)  			break;  	}  	return ret;  } +#endif /* CONFIG_SND_PCM_OSS_PLUGINS */  static ssize_t snd_pcm_oss_write2(struct snd_pcm_substream *substream, const char *buf, size_t bytes, int in_kernel)  { @@ -1554,7 +1518,7 @@ static int snd_pcm_oss_sync1(struct snd_pcm_substream *substream, size_t size)  	ssize_t result = 0;  	snd_pcm_state_t state;  	long res; -	wait_queue_t wait; +	wait_queue_entry_t wait;  	runtime = substream->runtime;  	init_waitqueue_entry(&wait, current); @@ -1650,27 +1614,10 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file)  		size = runtime->control->appl_ptr % runtime->period_size;  		if (size > 0) {  			size = runtime->period_size - size; -			if (runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) { -				size = (runtime->frame_bits * size) / 8; -				while (size > 0) { -					mm_segment_t fs; -					size_t size1 = size < runtime->oss.period_bytes ? size : runtime->oss.period_bytes; -					size -= size1; -					size1 *= 8; -					size1 /= runtime->sample_bits; -					snd_pcm_format_set_silence(runtime->format, -								   runtime->oss.buffer, -								   size1); -					size1 /= runtime->channels; /* frames */ -					fs = snd_enter_user(); -					snd_pcm_lib_write(substream, (void __force __user *)runtime->oss.buffer, size1); -					snd_leave_user(fs); -				} -			} else if (runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) { -				void __user *buffers[runtime->channels]; -				memset(buffers, 0, runtime->channels * sizeof(void *)); -				snd_pcm_lib_writev(substream, buffers, size); -			} +			if (runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) +				snd_pcm_lib_write(substream, NULL, size); +			else if (runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) +				snd_pcm_lib_writev(substream, NULL, size);  		}  		mutex_unlock(&runtime->oss.params_lock);  		/* @@ -1780,7 +1727,7 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file)  	int direct;  	struct snd_pcm_hw_params *params;  	unsigned int formats = 0; -	struct snd_mask format_mask; +	const struct snd_mask *format_mask;  	int fmt;  	if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0) @@ -1802,12 +1749,12 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file)  		return -ENOMEM;  	_snd_pcm_hw_params_any(params);  	err = snd_pcm_hw_refine(substream, params); -	format_mask = *hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);  +	format_mask = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT);  	kfree(params);  	if (err < 0)  		return err;  	for (fmt = 0; fmt < 32; ++fmt) { -		if (snd_mask_test(&format_mask, fmt)) { +		if (snd_mask_test(format_mask, fmt)) {  			int f = snd_pcm_oss_format_to(fmt);  			if (f >= 0)  				formats |= f; @@ -2387,7 +2334,7 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file)  	struct snd_pcm_oss_file *pcm_oss_file;  	struct snd_pcm_oss_setup setup[2];  	int nonblock; -	wait_queue_t wait; +	wait_queue_entry_t wait;  	err = nonseekable_open(inode, file);  	if (err < 0) diff --git a/sound/core/oss/pcm_plugin.c b/sound/core/oss/pcm_plugin.c index 727ac44d39f4..cadc93792868 100644 --- a/sound/core/oss/pcm_plugin.c +++ b/sound/core/oss/pcm_plugin.c @@ -266,7 +266,8 @@ snd_pcm_sframes_t snd_pcm_plug_slave_size(struct snd_pcm_substream *plug, snd_pc  	return frames;  } -static int snd_pcm_plug_formats(struct snd_mask *mask, snd_pcm_format_t format) +static int snd_pcm_plug_formats(const struct snd_mask *mask, +				snd_pcm_format_t format)  {  	struct snd_mask formats = *mask;  	u64 linfmts = (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 | @@ -309,7 +310,7 @@ static snd_pcm_format_t preferred_formats[] = {  };  snd_pcm_format_t snd_pcm_plug_slave_format(snd_pcm_format_t format, -					   struct snd_mask *format_mask) +					   const struct snd_mask *format_mask)  {  	int i; diff --git a/sound/core/oss/pcm_plugin.h b/sound/core/oss/pcm_plugin.h index a5035c2369a6..c9cd29d86efd 100644 --- a/sound/core/oss/pcm_plugin.h +++ b/sound/core/oss/pcm_plugin.h @@ -126,7 +126,7 @@ int snd_pcm_plug_format_plugins(struct snd_pcm_substream *substream,  				struct snd_pcm_hw_params *slave_params);  snd_pcm_format_t snd_pcm_plug_slave_format(snd_pcm_format_t format, -					   struct snd_mask *format_mask); +					   const struct snd_mask *format_mask);  int snd_pcm_plugin_append(struct snd_pcm_plugin *plugin); @@ -162,17 +162,15 @@ snd_pcm_sframes_t snd_pcm_oss_write3(struct snd_pcm_substream *substream,  snd_pcm_sframes_t snd_pcm_oss_read3(struct snd_pcm_substream *substream,  				    char *ptr, snd_pcm_uframes_t size, int in_kernel);  snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream, -				      void **bufs, snd_pcm_uframes_t frames, -				      int in_kernel); +				      void **bufs, snd_pcm_uframes_t frames);  snd_pcm_sframes_t snd_pcm_oss_readv3(struct snd_pcm_substream *substream, -				     void **bufs, snd_pcm_uframes_t frames, -				     int in_kernel); +				     void **bufs, snd_pcm_uframes_t frames);  #else  static inline snd_pcm_sframes_t snd_pcm_plug_client_size(struct snd_pcm_substream *handle, snd_pcm_uframes_t drv_size) { return drv_size; }  static inline snd_pcm_sframes_t snd_pcm_plug_slave_size(struct snd_pcm_substream *handle, snd_pcm_uframes_t clt_size) { return clt_size; } -static inline int snd_pcm_plug_slave_format(int format, struct snd_mask *format_mask) { return format; } +static inline int snd_pcm_plug_slave_format(int format, const struct snd_mask *format_mask) { return format; }  #endif diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 8e980aa678d0..89c7485519cb 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -31,13 +31,17 @@  #include <sound/control.h>  #include <sound/info.h> +#include "pcm_local.h" +  MODULE_AUTHOR("Jaroslav Kysela <[email protected]>, Abramo Bagnara <[email protected]>");  MODULE_DESCRIPTION("Midlevel PCM code for ALSA.");  MODULE_LICENSE("GPL");  static LIST_HEAD(snd_pcm_devices); -static LIST_HEAD(snd_pcm_notify_list);  static DEFINE_MUTEX(register_mutex); +#if IS_ENABLED(CONFIG_SND_PCM_OSS) +static LIST_HEAD(snd_pcm_notify_list); +#endif  static int snd_pcm_free(struct snd_pcm *pcm);  static int snd_pcm_dev_free(struct snd_device *device); @@ -884,16 +888,23 @@ static void snd_pcm_free_stream(struct snd_pcm_str * pstr)  		put_device(&pstr->dev);  } +#if IS_ENABLED(CONFIG_SND_PCM_OSS) +#define pcm_call_notify(pcm, call)					\ +	do {								\ +		struct snd_pcm_notify *_notify;				\ +		list_for_each_entry(_notify, &snd_pcm_notify_list, list) \ +			_notify->call(pcm);				\ +	} while (0) +#else +#define pcm_call_notify(pcm, call) do {} while (0) +#endif +  static int snd_pcm_free(struct snd_pcm *pcm)  { -	struct snd_pcm_notify *notify; -  	if (!pcm)  		return 0; -	if (!pcm->internal) { -		list_for_each_entry(notify, &snd_pcm_notify_list, list) -			notify->n_unregister(pcm); -	} +	if (!pcm->internal) +		pcm_call_notify(pcm, n_unregister);  	if (pcm->private_free)  		pcm->private_free(pcm);  	snd_pcm_lib_preallocate_free_for_all(pcm); @@ -1056,7 +1067,7 @@ static struct attribute *pcm_dev_attrs[] = {  	NULL  }; -static struct attribute_group pcm_dev_attr_group = { +static const struct attribute_group pcm_dev_attr_group = {  	.attrs	= pcm_dev_attrs,  }; @@ -1069,7 +1080,6 @@ static int snd_pcm_dev_register(struct snd_device *device)  {  	int cidx, err;  	struct snd_pcm_substream *substream; -	struct snd_pcm_notify *notify;  	struct snd_pcm *pcm;  	if (snd_BUG_ON(!device || !device->device_data)) @@ -1107,8 +1117,7 @@ static int snd_pcm_dev_register(struct snd_device *device)  			snd_pcm_timer_init(substream);  	} -	list_for_each_entry(notify, &snd_pcm_notify_list, list) -		notify->n_register(pcm); +	pcm_call_notify(pcm, n_register);   unlock:  	mutex_unlock(®ister_mutex); @@ -1118,7 +1127,6 @@ static int snd_pcm_dev_register(struct snd_device *device)  static int snd_pcm_dev_disconnect(struct snd_device *device)  {  	struct snd_pcm *pcm = device->device_data; -	struct snd_pcm_notify *notify;  	struct snd_pcm_substream *substream;  	int cidx; @@ -1138,8 +1146,7 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)  		}  	}  	if (!pcm->internal) { -		list_for_each_entry(notify, &snd_pcm_notify_list, list) -			notify->n_disconnect(pcm); +		pcm_call_notify(pcm, n_disconnect);  	}  	for (cidx = 0; cidx < 2; cidx++) {  		if (!pcm->internal) @@ -1151,6 +1158,7 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)  	return 0;  } +#if IS_ENABLED(CONFIG_SND_PCM_OSS)  /**   * snd_pcm_notify - Add/remove the notify list   * @notify: PCM notify list @@ -1183,6 +1191,7 @@ int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree)  	return 0;  }  EXPORT_SYMBOL(snd_pcm_notify); +#endif /* CONFIG_SND_PCM_OSS */  #ifdef CONFIG_SND_PROC_FS  /* diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c index 1f64ab0c2a95..10f537f4d735 100644 --- a/sound/core/pcm_compat.c +++ b/sound/core/pcm_compat.c @@ -27,17 +27,13 @@ static int snd_pcm_ioctl_delay_compat(struct snd_pcm_substream *substream,  				      s32 __user *src)  {  	snd_pcm_sframes_t delay; -	mm_segment_t fs; -	int err; -	fs = snd_enter_user(); -	err = snd_pcm_delay(substream, &delay); -	snd_leave_user(fs); -	if (err < 0) -		return err; +	delay = snd_pcm_delay(substream); +	if (delay < 0) +		return delay;  	if (put_user(delay, src))  		return -EFAULT; -	return err; +	return 0;  }  static int snd_pcm_ioctl_rewind_compat(struct snd_pcm_substream *substream, @@ -680,6 +676,7 @@ static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned l  	case SNDRV_PCM_IOCTL_INFO:  	case SNDRV_PCM_IOCTL_TSTAMP:  	case SNDRV_PCM_IOCTL_TTSTAMP: +	case SNDRV_PCM_IOCTL_USER_PVERSION:  	case SNDRV_PCM_IOCTL_HWSYNC:  	case SNDRV_PCM_IOCTL_PREPARE:  	case SNDRV_PCM_IOCTL_RESET: diff --git a/sound/core/pcm_drm_eld.c b/sound/core/pcm_drm_eld.c index e70379fb63d0..9881d087756f 100644 --- a/sound/core/pcm_drm_eld.c +++ b/sound/core/pcm_drm_eld.c @@ -29,13 +29,13 @@ static int eld_limit_rates(struct snd_pcm_hw_params *params,  			   struct snd_pcm_hw_rule *rule)  {  	struct snd_interval *r = hw_param_interval(params, rule->var); -	struct snd_interval *c; +	const struct snd_interval *c;  	unsigned int rate_mask = 7, i;  	const u8 *sad, *eld = rule->private;  	sad = drm_eld_sad(eld);  	if (sad) { -		c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); +		c = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS);  		for (i = drm_eld_sad_count(eld); i > 0; i--, sad += 3) {  			unsigned max_channels = sad_max_channels(sad); @@ -57,7 +57,7 @@ static int eld_limit_channels(struct snd_pcm_hw_params *params,  			      struct snd_pcm_hw_rule *rule)  {  	struct snd_interval *c = hw_param_interval(params, rule->var); -	struct snd_interval *r; +	const struct snd_interval *r;  	struct snd_interval t = { .min = 1, .max = 2, .integer = 1, };  	unsigned int i;  	const u8 *sad, *eld = rule->private; @@ -67,7 +67,7 @@ static int eld_limit_channels(struct snd_pcm_hw_params *params,  		unsigned int rate_mask = 0;  		/* Convert the rate interval to a mask */ -		r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); +		r = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE);  		for (i = 0; i < ARRAY_SIZE(eld_rates); i++)  			if (r->min <= eld_rates[i] && r->max >= eld_rates[i])  				rate_mask |= BIT(i); diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 5088d4b8db22..a93a4235a332 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -33,6 +33,8 @@  #include <sound/pcm_params.h>  #include <sound/timer.h> +#include "pcm_local.h" +  #ifdef CONFIG_SND_PCM_XRUN_DEBUG  #define CREATE_TRACE_POINTS  #include "pcm_trace.h" @@ -40,8 +42,12 @@  #define trace_hwptr(substream, pos, in_interrupt)  #define trace_xrun(substream)  #define trace_hw_ptr_error(substream, reason) +#define trace_applptr(substream, prev, curr)  #endif +static int fill_silence_frames(struct snd_pcm_substream *substream, +			       snd_pcm_uframes_t off, snd_pcm_uframes_t frames); +  /*   * fill ring buffer with silence   * runtime->silence_start: starting pointer to silence area @@ -55,18 +61,20 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram  {  	struct snd_pcm_runtime *runtime = substream->runtime;  	snd_pcm_uframes_t frames, ofs, transfer; +	int err;  	if (runtime->silence_size < runtime->boundary) {  		snd_pcm_sframes_t noise_dist, n; -		if (runtime->silence_start != runtime->control->appl_ptr) { -			n = runtime->control->appl_ptr - runtime->silence_start; +		snd_pcm_uframes_t appl_ptr = READ_ONCE(runtime->control->appl_ptr); +		if (runtime->silence_start != appl_ptr) { +			n = appl_ptr - runtime->silence_start;  			if (n < 0)  				n += runtime->boundary;  			if ((snd_pcm_uframes_t)n < runtime->silence_filled)  				runtime->silence_filled -= n;  			else  				runtime->silence_filled = 0; -			runtime->silence_start = runtime->control->appl_ptr; +			runtime->silence_start = appl_ptr;  		}  		if (runtime->silence_filled >= runtime->buffer_size)  			return; @@ -107,33 +115,8 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram  	ofs = runtime->silence_start % runtime->buffer_size;  	while (frames > 0) {  		transfer = ofs + frames > runtime->buffer_size ? runtime->buffer_size - ofs : frames; -		if (runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED || -		    runtime->access == SNDRV_PCM_ACCESS_MMAP_INTERLEAVED) { -			if (substream->ops->silence) { -				int err; -				err = substream->ops->silence(substream, -1, ofs, transfer); -				snd_BUG_ON(err < 0); -			} else { -				char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, ofs); -				snd_pcm_format_set_silence(runtime->format, hwbuf, transfer * runtime->channels); -			} -		} else { -			unsigned int c; -			unsigned int channels = runtime->channels; -			if (substream->ops->silence) { -				for (c = 0; c < channels; ++c) { -					int err; -					err = substream->ops->silence(substream, c, ofs, transfer); -					snd_BUG_ON(err < 0); -				} -			} else { -				size_t dma_csize = runtime->dma_bytes / channels; -				for (c = 0; c < channels; ++c) { -					char *hwbuf = runtime->dma_area + (c * dma_csize) + samples_to_bytes(runtime, ofs); -					snd_pcm_format_set_silence(runtime->format, hwbuf, transfer); -				} -			} -		} +		err = fill_silence_frames(substream, ofs, transfer); +		snd_BUG_ON(err < 0);  		runtime->silence_filled += transfer;  		frames -= transfer;  		ofs = 0; @@ -508,7 +491,6 @@ void snd_pcm_set_ops(struct snd_pcm *pcm, int direction,  	for (substream = stream->substream; substream != NULL; substream = substream->next)  		substream->ops = ops;  } -  EXPORT_SYMBOL(snd_pcm_set_ops);  /** @@ -526,7 +508,6 @@ void snd_pcm_set_sync(struct snd_pcm_substream *substream)  	runtime->sync.id32[2] = -1;  	runtime->sync.id32[3] = -1;  } -  EXPORT_SYMBOL(snd_pcm_set_sync);  /* @@ -643,7 +624,6 @@ int snd_interval_refine(struct snd_interval *i, const struct snd_interval *v)  	}  	return changed;  } -  EXPORT_SYMBOL(snd_interval_refine);  static int snd_interval_refine_first(struct snd_interval *i) @@ -906,7 +886,6 @@ int snd_interval_ratnum(struct snd_interval *i,  	}  	return err;  } -  EXPORT_SYMBOL(snd_interval_ratnum);  /** @@ -1044,7 +1023,6 @@ int snd_interval_list(struct snd_interval *i, unsigned int count,          }  	return snd_interval_refine(i, &list_range);  } -  EXPORT_SYMBOL(snd_interval_list);  /** @@ -1183,7 +1161,6 @@ int snd_pcm_hw_rule_add(struct snd_pcm_runtime *runtime, unsigned int cond,  	va_end(args);  	return 0;  } -  EXPORT_SYMBOL(snd_pcm_hw_rule_add);  /** @@ -1247,7 +1224,6 @@ int snd_pcm_hw_constraint_integer(struct snd_pcm_runtime *runtime, snd_pcm_hw_pa  	struct snd_pcm_hw_constraints *constrs = &runtime->hw_constraints;  	return snd_interval_setinteger(constrs_interval(constrs, var));  } -  EXPORT_SYMBOL(snd_pcm_hw_constraint_integer);  /** @@ -1273,7 +1249,6 @@ int snd_pcm_hw_constraint_minmax(struct snd_pcm_runtime *runtime, snd_pcm_hw_par  	t.integer = 0;  	return snd_interval_refine(constrs_interval(constrs, var), &t);  } -  EXPORT_SYMBOL(snd_pcm_hw_constraint_minmax);  static int snd_pcm_hw_rule_list(struct snd_pcm_hw_params *params, @@ -1304,7 +1279,6 @@ int snd_pcm_hw_constraint_list(struct snd_pcm_runtime *runtime,  				   snd_pcm_hw_rule_list, (void *)l,  				   var, -1);  } -  EXPORT_SYMBOL(snd_pcm_hw_constraint_list);  static int snd_pcm_hw_rule_ranges(struct snd_pcm_hw_params *params, @@ -1371,7 +1345,6 @@ int snd_pcm_hw_constraint_ratnums(struct snd_pcm_runtime *runtime,  				   snd_pcm_hw_rule_ratnums, (void *)r,  				   var, -1);  } -  EXPORT_SYMBOL(snd_pcm_hw_constraint_ratnums);  static int snd_pcm_hw_rule_ratdens(struct snd_pcm_hw_params *params, @@ -1406,7 +1379,6 @@ int snd_pcm_hw_constraint_ratdens(struct snd_pcm_runtime *runtime,  				   snd_pcm_hw_rule_ratdens, (void *)r,  				   var, -1);  } -  EXPORT_SYMBOL(snd_pcm_hw_constraint_ratdens);  static int snd_pcm_hw_rule_msbits(struct snd_pcm_hw_params *params, @@ -1415,7 +1387,8 @@ static int snd_pcm_hw_rule_msbits(struct snd_pcm_hw_params *params,  	unsigned int l = (unsigned long) rule->private;  	int width = l & 0xffff;  	unsigned int msbits = l >> 16; -	struct snd_interval *i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); +	const struct snd_interval *i = +		hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS);  	if (!snd_interval_single(i))  		return 0; @@ -1452,7 +1425,6 @@ int snd_pcm_hw_constraint_msbits(struct snd_pcm_runtime *runtime,  				    (void*) l,  				    SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1);  } -  EXPORT_SYMBOL(snd_pcm_hw_constraint_msbits);  static int snd_pcm_hw_rule_step(struct snd_pcm_hw_params *params, @@ -1480,7 +1452,6 @@ int snd_pcm_hw_constraint_step(struct snd_pcm_runtime *runtime,  				   snd_pcm_hw_rule_step, (void *) step,  				   var, -1);  } -  EXPORT_SYMBOL(snd_pcm_hw_constraint_step);  static int snd_pcm_hw_rule_pow2(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) @@ -1511,7 +1482,6 @@ int snd_pcm_hw_constraint_pow2(struct snd_pcm_runtime *runtime,  				   snd_pcm_hw_rule_pow2, NULL,  				   var, -1);  } -  EXPORT_SYMBOL(snd_pcm_hw_constraint_pow2);  static int snd_pcm_hw_rule_noresample_func(struct snd_pcm_hw_params *params, @@ -1570,7 +1540,6 @@ void _snd_pcm_hw_params_any(struct snd_pcm_hw_params *params)  		_snd_pcm_hw_param_any(params, k);  	params->info = ~0U;  } -  EXPORT_SYMBOL(_snd_pcm_hw_params_any);  /** @@ -1603,7 +1572,6 @@ int snd_pcm_hw_param_value(const struct snd_pcm_hw_params *params,  	}  	return -EINVAL;  } -  EXPORT_SYMBOL(snd_pcm_hw_param_value);  void _snd_pcm_hw_param_setempty(struct snd_pcm_hw_params *params, @@ -1621,7 +1589,6 @@ void _snd_pcm_hw_param_setempty(struct snd_pcm_hw_params *params,  		snd_BUG();  	}  } -  EXPORT_SYMBOL(_snd_pcm_hw_param_setempty);  static int _snd_pcm_hw_param_first(struct snd_pcm_hw_params *params, @@ -1668,7 +1635,6 @@ int snd_pcm_hw_param_first(struct snd_pcm_substream *pcm,  	}  	return snd_pcm_hw_param_value(params, var, dir);  } -  EXPORT_SYMBOL(snd_pcm_hw_param_first);  static int _snd_pcm_hw_param_last(struct snd_pcm_hw_params *params, @@ -1715,48 +1681,8 @@ int snd_pcm_hw_param_last(struct snd_pcm_substream *pcm,  	}  	return snd_pcm_hw_param_value(params, var, dir);  } -  EXPORT_SYMBOL(snd_pcm_hw_param_last); -/** - * snd_pcm_hw_param_choose - choose a configuration defined by @params - * @pcm: PCM instance - * @params: the hw_params instance - * - * Choose one configuration from configuration space defined by @params. - * The configuration chosen is that obtained fixing in this order: - * first access, first format, first subformat, min channels, - * min rate, min period time, max buffer size, min tick time - * - * Return: Zero if successful, or a negative error code on failure. - */ -int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm, -			     struct snd_pcm_hw_params *params) -{ -	static int vars[] = { -		SNDRV_PCM_HW_PARAM_ACCESS, -		SNDRV_PCM_HW_PARAM_FORMAT, -		SNDRV_PCM_HW_PARAM_SUBFORMAT, -		SNDRV_PCM_HW_PARAM_CHANNELS, -		SNDRV_PCM_HW_PARAM_RATE, -		SNDRV_PCM_HW_PARAM_PERIOD_TIME, -		SNDRV_PCM_HW_PARAM_BUFFER_SIZE, -		SNDRV_PCM_HW_PARAM_TICK_TIME, -		-1 -	}; -	int err, *v; - -	for (v = vars; *v != -1; v++) { -		if (*v != SNDRV_PCM_HW_PARAM_BUFFER_SIZE) -			err = snd_pcm_hw_param_first(pcm, params, *v, NULL); -		else -			err = snd_pcm_hw_param_last(pcm, params, *v, NULL); -		if (snd_BUG_ON(err < 0)) -			return err; -	} -	return 0; -} -  static int snd_pcm_lib_ioctl_reset(struct snd_pcm_substream *substream,  				   void *arg)  { @@ -1843,8 +1769,6 @@ int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream,  		      unsigned int cmd, void *arg)  {  	switch (cmd) { -	case SNDRV_PCM_IOCTL1_INFO: -		return 0;  	case SNDRV_PCM_IOCTL1_RESET:  		return snd_pcm_lib_ioctl_reset(substream, arg);  	case SNDRV_PCM_IOCTL1_CHANNEL_INFO: @@ -1854,7 +1778,6 @@ int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream,  	}  	return -ENXIO;  } -  EXPORT_SYMBOL(snd_pcm_lib_ioctl);  /** @@ -1890,7 +1813,6 @@ void snd_pcm_period_elapsed(struct snd_pcm_substream *substream)  	kill_fasync(&runtime->fasync, SIGIO, POLL_IN);  	snd_pcm_stream_unlock_irqrestore(substream, flags);  } -  EXPORT_SYMBOL(snd_pcm_period_elapsed);  /* @@ -1904,7 +1826,7 @@ static int wait_for_avail(struct snd_pcm_substream *substream,  {  	struct snd_pcm_runtime *runtime = substream->runtime;  	int is_playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; -	wait_queue_t wait; +	wait_queue_entry_t wait;  	int err = 0;  	snd_pcm_uframes_t avail = 0;  	long wait_time, tout; @@ -1985,129 +1907,147 @@ static int wait_for_avail(struct snd_pcm_substream *substream,  	return err;  } -static int snd_pcm_lib_write_transfer(struct snd_pcm_substream *substream, -				      unsigned int hwoff, -				      unsigned long data, unsigned int off, -				      snd_pcm_uframes_t frames) +typedef int (*pcm_transfer_f)(struct snd_pcm_substream *substream, +			      int channel, unsigned long hwoff, +			      void *buf, unsigned long bytes); + +typedef int (*pcm_copy_f)(struct snd_pcm_substream *, snd_pcm_uframes_t, void *, +			  snd_pcm_uframes_t, snd_pcm_uframes_t, pcm_transfer_f); + +/* calculate the target DMA-buffer position to be written/read */ +static void *get_dma_ptr(struct snd_pcm_runtime *runtime, +			   int channel, unsigned long hwoff)  { -	struct snd_pcm_runtime *runtime = substream->runtime; -	int err; -	char __user *buf = (char __user *) data + frames_to_bytes(runtime, off); -	if (substream->ops->copy) { -		if ((err = substream->ops->copy(substream, -1, hwoff, buf, frames)) < 0) -			return err; -	} else { -		char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff); -		if (copy_from_user(hwbuf, buf, frames_to_bytes(runtime, frames))) -			return -EFAULT; -	} +	return runtime->dma_area + hwoff + +		channel * (runtime->dma_bytes / runtime->channels); +} + +/* default copy_user ops for write; used for both interleaved and non- modes */ +static int default_write_copy(struct snd_pcm_substream *substream, +			      int channel, unsigned long hwoff, +			      void *buf, unsigned long bytes) +{ +	if (copy_from_user(get_dma_ptr(substream->runtime, channel, hwoff), +			   (void __user *)buf, bytes)) +		return -EFAULT;  	return 0;  } -  -typedef int (*transfer_f)(struct snd_pcm_substream *substream, unsigned int hwoff, -			  unsigned long data, unsigned int off, -			  snd_pcm_uframes_t size); -static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream,  -					    unsigned long data, -					    snd_pcm_uframes_t size, -					    int nonblock, -					    transfer_f transfer) +/* default copy_kernel ops for write */ +static int default_write_copy_kernel(struct snd_pcm_substream *substream, +				     int channel, unsigned long hwoff, +				     void *buf, unsigned long bytes) +{ +	memcpy(get_dma_ptr(substream->runtime, channel, hwoff), buf, bytes); +	return 0; +} + +/* fill silence instead of copy data; called as a transfer helper + * from __snd_pcm_lib_write() or directly from noninterleaved_copy() when + * a NULL buffer is passed + */ +static int fill_silence(struct snd_pcm_substream *substream, int channel, +			unsigned long hwoff, void *buf, unsigned long bytes)  {  	struct snd_pcm_runtime *runtime = substream->runtime; -	snd_pcm_uframes_t xfer = 0; -	snd_pcm_uframes_t offset = 0; -	snd_pcm_uframes_t avail; -	int err = 0; -	if (size == 0) +	if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)  		return 0; +	if (substream->ops->fill_silence) +		return substream->ops->fill_silence(substream, channel, +						    hwoff, bytes); -	snd_pcm_stream_lock_irq(substream); -	switch (runtime->status->state) { -	case SNDRV_PCM_STATE_PREPARED: -	case SNDRV_PCM_STATE_RUNNING: -	case SNDRV_PCM_STATE_PAUSED: -		break; -	case SNDRV_PCM_STATE_XRUN: -		err = -EPIPE; -		goto _end_unlock; -	case SNDRV_PCM_STATE_SUSPENDED: -		err = -ESTRPIPE; -		goto _end_unlock; -	default: -		err = -EBADFD; -		goto _end_unlock; -	} +	snd_pcm_format_set_silence(runtime->format, +				   get_dma_ptr(runtime, channel, hwoff), +				   bytes_to_samples(runtime, bytes)); +	return 0; +} -	runtime->twake = runtime->control->avail_min ? : 1; -	if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) -		snd_pcm_update_hw_ptr(substream); -	avail = snd_pcm_playback_avail(runtime); -	while (size > 0) { -		snd_pcm_uframes_t frames, appl_ptr, appl_ofs; -		snd_pcm_uframes_t cont; -		if (!avail) { -			if (nonblock) { -				err = -EAGAIN; -				goto _end_unlock; -			} -			runtime->twake = min_t(snd_pcm_uframes_t, size, -					runtime->control->avail_min ? : 1); -			err = wait_for_avail(substream, &avail); -			if (err < 0) -				goto _end_unlock; -		} -		frames = size > avail ? avail : size; -		cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size; -		if (frames > cont) -			frames = cont; -		if (snd_BUG_ON(!frames)) { -			runtime->twake = 0; -			snd_pcm_stream_unlock_irq(substream); -			return -EINVAL; -		} -		appl_ptr = runtime->control->appl_ptr; -		appl_ofs = appl_ptr % runtime->buffer_size; -		snd_pcm_stream_unlock_irq(substream); -		err = transfer(substream, appl_ofs, data, offset, frames); -		snd_pcm_stream_lock_irq(substream); -		if (err < 0) -			goto _end_unlock; -		switch (runtime->status->state) { -		case SNDRV_PCM_STATE_XRUN: -			err = -EPIPE; -			goto _end_unlock; -		case SNDRV_PCM_STATE_SUSPENDED: -			err = -ESTRPIPE; -			goto _end_unlock; -		default: -			break; -		} -		appl_ptr += frames; -		if (appl_ptr >= runtime->boundary) -			appl_ptr -= runtime->boundary; -		runtime->control->appl_ptr = appl_ptr; -		if (substream->ops->ack) -			substream->ops->ack(substream); +/* default copy_user ops for read; used for both interleaved and non- modes */ +static int default_read_copy(struct snd_pcm_substream *substream, +			     int channel, unsigned long hwoff, +			     void *buf, unsigned long bytes) +{ +	if (copy_to_user((void __user *)buf, +			 get_dma_ptr(substream->runtime, channel, hwoff), +			 bytes)) +		return -EFAULT; +	return 0; +} -		offset += frames; -		size -= frames; -		xfer += frames; -		avail -= frames; -		if (runtime->status->state == SNDRV_PCM_STATE_PREPARED && -		    snd_pcm_playback_hw_avail(runtime) >= (snd_pcm_sframes_t)runtime->start_threshold) { -			err = snd_pcm_start(substream); -			if (err < 0) -				goto _end_unlock; -		} +/* default copy_kernel ops for read */ +static int default_read_copy_kernel(struct snd_pcm_substream *substream, +				    int channel, unsigned long hwoff, +				    void *buf, unsigned long bytes) +{ +	memcpy(buf, get_dma_ptr(substream->runtime, channel, hwoff), bytes); +	return 0; +} + +/* call transfer function with the converted pointers and sizes; + * for interleaved mode, it's one shot for all samples + */ +static int interleaved_copy(struct snd_pcm_substream *substream, +			    snd_pcm_uframes_t hwoff, void *data, +			    snd_pcm_uframes_t off, +			    snd_pcm_uframes_t frames, +			    pcm_transfer_f transfer) +{ +	struct snd_pcm_runtime *runtime = substream->runtime; + +	/* convert to bytes */ +	hwoff = frames_to_bytes(runtime, hwoff); +	off = frames_to_bytes(runtime, off); +	frames = frames_to_bytes(runtime, frames); +	return transfer(substream, 0, hwoff, data + off, frames); +} + +/* call transfer function with the converted pointers and sizes for each + * non-interleaved channel; when buffer is NULL, silencing instead of copying + */ +static int noninterleaved_copy(struct snd_pcm_substream *substream, +			       snd_pcm_uframes_t hwoff, void *data, +			       snd_pcm_uframes_t off, +			       snd_pcm_uframes_t frames, +			       pcm_transfer_f transfer) +{ +	struct snd_pcm_runtime *runtime = substream->runtime; +	int channels = runtime->channels; +	void **bufs = data; +	int c, err; + +	/* convert to bytes; note that it's not frames_to_bytes() here. +	 * in non-interleaved mode, we copy for each channel, thus +	 * each copy is n_samples bytes x channels = whole frames. +	 */ +	off = samples_to_bytes(runtime, off); +	frames = samples_to_bytes(runtime, frames); +	hwoff = samples_to_bytes(runtime, hwoff); +	for (c = 0; c < channels; ++c, ++bufs) { +		if (!data || !*bufs) +			err = fill_silence(substream, c, hwoff, NULL, frames); +		else +			err = transfer(substream, c, hwoff, *bufs + off, +				       frames); +		if (err < 0) +			return err;  	} - _end_unlock: -	runtime->twake = 0; -	if (xfer > 0 && err >= 0) -		snd_pcm_update_state(substream, runtime); -	snd_pcm_stream_unlock_irq(substream); -	return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; +	return 0; +} + +/* fill silence on the given buffer position; + * called from snd_pcm_playback_silence() + */ +static int fill_silence_frames(struct snd_pcm_substream *substream, +			       snd_pcm_uframes_t off, snd_pcm_uframes_t frames) +{ +	if (substream->runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED || +	    substream->runtime->access == SNDRV_PCM_ACCESS_MMAP_INTERLEAVED) +		return interleaved_copy(substream, off, NULL, 0, frames, +					fill_silence); +	else +		return noninterleaved_copy(substream, off, NULL, 0, frames, +					   fill_silence);  }  /* sanity-check for read/write methods */ @@ -2117,164 +2057,137 @@ static int pcm_sanity_check(struct snd_pcm_substream *substream)  	if (PCM_RUNTIME_CHECK(substream))  		return -ENXIO;  	runtime = substream->runtime; -	if (snd_BUG_ON(!substream->ops->copy && !runtime->dma_area)) +	if (snd_BUG_ON(!substream->ops->copy_user && !runtime->dma_area))  		return -EINVAL;  	if (runtime->status->state == SNDRV_PCM_STATE_OPEN)  		return -EBADFD;  	return 0;  } -snd_pcm_sframes_t snd_pcm_lib_write(struct snd_pcm_substream *substream, const void __user *buf, snd_pcm_uframes_t size) +static int pcm_accessible_state(struct snd_pcm_runtime *runtime)  { -	struct snd_pcm_runtime *runtime; -	int nonblock; -	int err; - -	err = pcm_sanity_check(substream); -	if (err < 0) -		return err; -	runtime = substream->runtime; -	nonblock = !!(substream->f_flags & O_NONBLOCK); - -	if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED && -	    runtime->channels > 1) -		return -EINVAL; -	return snd_pcm_lib_write1(substream, (unsigned long)buf, size, nonblock, -				  snd_pcm_lib_write_transfer); +	switch (runtime->status->state) { +	case SNDRV_PCM_STATE_PREPARED: +	case SNDRV_PCM_STATE_RUNNING: +	case SNDRV_PCM_STATE_PAUSED: +		return 0; +	case SNDRV_PCM_STATE_XRUN: +		return -EPIPE; +	case SNDRV_PCM_STATE_SUSPENDED: +		return -ESTRPIPE; +	default: +		return -EBADFD; +	}  } -EXPORT_SYMBOL(snd_pcm_lib_write); - -static int snd_pcm_lib_writev_transfer(struct snd_pcm_substream *substream, -				       unsigned int hwoff, -				       unsigned long data, unsigned int off, -				       snd_pcm_uframes_t frames) +/* update to the given appl_ptr and call ack callback if needed; + * when an error is returned, take back to the original value + */ +int pcm_lib_apply_appl_ptr(struct snd_pcm_substream *substream, +			   snd_pcm_uframes_t appl_ptr)  {  	struct snd_pcm_runtime *runtime = substream->runtime; -	int err; -	void __user **bufs = (void __user **)data; -	int channels = runtime->channels; -	int c; -	if (substream->ops->copy) { -		if (snd_BUG_ON(!substream->ops->silence)) -			return -EINVAL; -		for (c = 0; c < channels; ++c, ++bufs) { -			if (*bufs == NULL) { -				if ((err = substream->ops->silence(substream, c, hwoff, frames)) < 0) -					return err; -			} else { -				char __user *buf = *bufs + samples_to_bytes(runtime, off); -				if ((err = substream->ops->copy(substream, c, hwoff, buf, frames)) < 0) -					return err; -			} -		} -	} else { -		/* default transfer behaviour */ -		size_t dma_csize = runtime->dma_bytes / channels; -		for (c = 0; c < channels; ++c, ++bufs) { -			char *hwbuf = runtime->dma_area + (c * dma_csize) + samples_to_bytes(runtime, hwoff); -			if (*bufs == NULL) { -				snd_pcm_format_set_silence(runtime->format, hwbuf, frames); -			} else { -				char __user *buf = *bufs + samples_to_bytes(runtime, off); -				if (copy_from_user(hwbuf, buf, samples_to_bytes(runtime, frames))) -					return -EFAULT; -			} +	snd_pcm_uframes_t old_appl_ptr = runtime->control->appl_ptr; +	int ret; + +	if (old_appl_ptr == appl_ptr) +		return 0; + +	runtime->control->appl_ptr = appl_ptr; +	if (substream->ops->ack) { +		ret = substream->ops->ack(substream); +		if (ret < 0) { +			runtime->control->appl_ptr = old_appl_ptr; +			return ret;  		}  	} + +	trace_applptr(substream, old_appl_ptr, appl_ptr); +  	return 0;  } -  -snd_pcm_sframes_t snd_pcm_lib_writev(struct snd_pcm_substream *substream, -				     void __user **bufs, -				     snd_pcm_uframes_t frames) + +/* the common loop for read/write data */ +snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream, +				     void *data, bool interleaved, +				     snd_pcm_uframes_t size, bool in_kernel)  { -	struct snd_pcm_runtime *runtime; -	int nonblock; +	struct snd_pcm_runtime *runtime = substream->runtime; +	snd_pcm_uframes_t xfer = 0; +	snd_pcm_uframes_t offset = 0; +	snd_pcm_uframes_t avail; +	pcm_copy_f writer; +	pcm_transfer_f transfer; +	bool nonblock; +	bool is_playback;  	int err;  	err = pcm_sanity_check(substream);  	if (err < 0)  		return err; -	runtime = substream->runtime; -	nonblock = !!(substream->f_flags & O_NONBLOCK); - -	if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) -		return -EINVAL; -	return snd_pcm_lib_write1(substream, (unsigned long)bufs, frames, -				  nonblock, snd_pcm_lib_writev_transfer); -} - -EXPORT_SYMBOL(snd_pcm_lib_writev); -static int snd_pcm_lib_read_transfer(struct snd_pcm_substream *substream,  -				     unsigned int hwoff, -				     unsigned long data, unsigned int off, -				     snd_pcm_uframes_t frames) -{ -	struct snd_pcm_runtime *runtime = substream->runtime; -	int err; -	char __user *buf = (char __user *) data + frames_to_bytes(runtime, off); -	if (substream->ops->copy) { -		if ((err = substream->ops->copy(substream, -1, hwoff, buf, frames)) < 0) -			return err; +	is_playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; +	if (interleaved) { +		if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED && +		    runtime->channels > 1) +			return -EINVAL; +		writer = interleaved_copy;  	} else { -		char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff); -		if (copy_to_user(buf, hwbuf, frames_to_bytes(runtime, frames))) -			return -EFAULT; +		if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) +			return -EINVAL; +		writer = noninterleaved_copy;  	} -	return 0; -} -static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, -					   unsigned long data, -					   snd_pcm_uframes_t size, -					   int nonblock, -					   transfer_f transfer) -{ -	struct snd_pcm_runtime *runtime = substream->runtime; -	snd_pcm_uframes_t xfer = 0; -	snd_pcm_uframes_t offset = 0; -	snd_pcm_uframes_t avail; -	int err = 0; +	if (!data) { +		if (is_playback) +			transfer = fill_silence; +		else +			return -EINVAL; +	} else if (in_kernel) { +		if (substream->ops->copy_kernel) +			transfer = substream->ops->copy_kernel; +		else +			transfer = is_playback ? +				default_write_copy_kernel : default_read_copy_kernel; +	} else { +		if (substream->ops->copy_user) +			transfer = (pcm_transfer_f)substream->ops->copy_user; +		else +			transfer = is_playback ? +				default_write_copy : default_read_copy; +	}  	if (size == 0)  		return 0; +	nonblock = !!(substream->f_flags & O_NONBLOCK); +  	snd_pcm_stream_lock_irq(substream); -	switch (runtime->status->state) { -	case SNDRV_PCM_STATE_PREPARED: -		if (size >= runtime->start_threshold) { -			err = snd_pcm_start(substream); -			if (err < 0) -				goto _end_unlock; -		} -		break; -	case SNDRV_PCM_STATE_DRAINING: -	case SNDRV_PCM_STATE_RUNNING: -	case SNDRV_PCM_STATE_PAUSED: -		break; -	case SNDRV_PCM_STATE_XRUN: -		err = -EPIPE; -		goto _end_unlock; -	case SNDRV_PCM_STATE_SUSPENDED: -		err = -ESTRPIPE; -		goto _end_unlock; -	default: -		err = -EBADFD; +	err = pcm_accessible_state(runtime); +	if (err < 0)  		goto _end_unlock; + +	if (!is_playback && +	    runtime->status->state == SNDRV_PCM_STATE_PREPARED && +	    size >= runtime->start_threshold) { +		err = snd_pcm_start(substream); +		if (err < 0) +			goto _end_unlock;  	}  	runtime->twake = runtime->control->avail_min ? : 1;  	if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)  		snd_pcm_update_hw_ptr(substream); -	avail = snd_pcm_capture_avail(runtime); +	if (is_playback) +		avail = snd_pcm_playback_avail(runtime); +	else +		avail = snd_pcm_capture_avail(runtime);  	while (size > 0) {  		snd_pcm_uframes_t frames, appl_ptr, appl_ofs;  		snd_pcm_uframes_t cont;  		if (!avail) { -			if (runtime->status->state == -			    SNDRV_PCM_STATE_DRAINING) { +			if (!is_playback && +			    runtime->status->state == SNDRV_PCM_STATE_DRAINING) {  				snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);  				goto _end_unlock;  			} @@ -2291,7 +2204,9 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,  				continue; /* draining */  		}  		frames = size > avail ? avail : size; -		cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size; +		appl_ptr = READ_ONCE(runtime->control->appl_ptr); +		appl_ofs = appl_ptr % runtime->buffer_size; +		cont = runtime->buffer_size - appl_ofs;  		if (frames > cont)  			frames = cont;  		if (snd_BUG_ON(!frames)) { @@ -2299,34 +2214,33 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,  			snd_pcm_stream_unlock_irq(substream);  			return -EINVAL;  		} -		appl_ptr = runtime->control->appl_ptr; -		appl_ofs = appl_ptr % runtime->buffer_size;  		snd_pcm_stream_unlock_irq(substream); -		err = transfer(substream, appl_ofs, data, offset, frames); +		err = writer(substream, appl_ofs, data, offset, frames, +			     transfer);  		snd_pcm_stream_lock_irq(substream);  		if (err < 0)  			goto _end_unlock; -		switch (runtime->status->state) { -		case SNDRV_PCM_STATE_XRUN: -			err = -EPIPE; -			goto _end_unlock; -		case SNDRV_PCM_STATE_SUSPENDED: -			err = -ESTRPIPE; +		err = pcm_accessible_state(runtime); +		if (err < 0)  			goto _end_unlock; -		default: -			break; -		}  		appl_ptr += frames;  		if (appl_ptr >= runtime->boundary)  			appl_ptr -= runtime->boundary; -		runtime->control->appl_ptr = appl_ptr; -		if (substream->ops->ack) -			substream->ops->ack(substream); +		err = pcm_lib_apply_appl_ptr(substream, appl_ptr); +		if (err < 0) +			goto _end_unlock;  		offset += frames;  		size -= frames;  		xfer += frames;  		avail -= frames; +		if (is_playback && +		    runtime->status->state == SNDRV_PCM_STATE_PREPARED && +		    snd_pcm_playback_hw_avail(runtime) >= (snd_pcm_sframes_t)runtime->start_threshold) { +			err = snd_pcm_start(substream); +			if (err < 0) +				goto _end_unlock; +		}  	}   _end_unlock:  	runtime->twake = 0; @@ -2335,83 +2249,7 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,  	snd_pcm_stream_unlock_irq(substream);  	return xfer > 0 ? (snd_pcm_sframes_t)xfer : err;  } - -snd_pcm_sframes_t snd_pcm_lib_read(struct snd_pcm_substream *substream, void __user *buf, snd_pcm_uframes_t size) -{ -	struct snd_pcm_runtime *runtime; -	int nonblock; -	int err; -	 -	err = pcm_sanity_check(substream); -	if (err < 0) -		return err; -	runtime = substream->runtime; -	nonblock = !!(substream->f_flags & O_NONBLOCK); -	if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED) -		return -EINVAL; -	return snd_pcm_lib_read1(substream, (unsigned long)buf, size, nonblock, snd_pcm_lib_read_transfer); -} - -EXPORT_SYMBOL(snd_pcm_lib_read); - -static int snd_pcm_lib_readv_transfer(struct snd_pcm_substream *substream, -				      unsigned int hwoff, -				      unsigned long data, unsigned int off, -				      snd_pcm_uframes_t frames) -{ -	struct snd_pcm_runtime *runtime = substream->runtime; -	int err; -	void __user **bufs = (void __user **)data; -	int channels = runtime->channels; -	int c; -	if (substream->ops->copy) { -		for (c = 0; c < channels; ++c, ++bufs) { -			char __user *buf; -			if (*bufs == NULL) -				continue; -			buf = *bufs + samples_to_bytes(runtime, off); -			if ((err = substream->ops->copy(substream, c, hwoff, buf, frames)) < 0) -				return err; -		} -	} else { -		snd_pcm_uframes_t dma_csize = runtime->dma_bytes / channels; -		for (c = 0; c < channels; ++c, ++bufs) { -			char *hwbuf; -			char __user *buf; -			if (*bufs == NULL) -				continue; - -			hwbuf = runtime->dma_area + (c * dma_csize) + samples_to_bytes(runtime, hwoff); -			buf = *bufs + samples_to_bytes(runtime, off); -			if (copy_to_user(buf, hwbuf, samples_to_bytes(runtime, frames))) -				return -EFAULT; -		} -	} -	return 0; -} -  -snd_pcm_sframes_t snd_pcm_lib_readv(struct snd_pcm_substream *substream, -				    void __user **bufs, -				    snd_pcm_uframes_t frames) -{ -	struct snd_pcm_runtime *runtime; -	int nonblock; -	int err; - -	err = pcm_sanity_check(substream); -	if (err < 0) -		return err; -	runtime = substream->runtime; -	if (runtime->status->state == SNDRV_PCM_STATE_OPEN) -		return -EBADFD; - -	nonblock = !!(substream->f_flags & O_NONBLOCK); -	if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) -		return -EINVAL; -	return snd_pcm_lib_read1(substream, (unsigned long)bufs, frames, nonblock, snd_pcm_lib_readv_transfer); -} - -EXPORT_SYMBOL(snd_pcm_lib_readv); +EXPORT_SYMBOL(__snd_pcm_lib_xfer);  /*   * standard channel mapping helpers @@ -2492,7 +2330,7 @@ static int pcm_chmap_ctl_get(struct snd_kcontrol *kcontrol,  	struct snd_pcm_substream *substream;  	const struct snd_pcm_chmap_elem *map; -	if (snd_BUG_ON(!info->chmap)) +	if (!info->chmap)  		return -EINVAL;  	substream = snd_pcm_chmap_substream(info, idx);  	if (!substream) @@ -2524,7 +2362,7 @@ static int pcm_chmap_ctl_tlv(struct snd_kcontrol *kcontrol, int op_flag,  	unsigned int __user *dst;  	int c, count = 0; -	if (snd_BUG_ON(!info->chmap)) +	if (!info->chmap)  		return -EINVAL;  	if (size < 8)  		return -ENOMEM; diff --git a/sound/core/pcm_local.h b/sound/core/pcm_local.h new file mode 100644 index 000000000000..16f254732b2a --- /dev/null +++ b/sound/core/pcm_local.h @@ -0,0 +1,50 @@ +/* + * pcm_local.h - a local header file for snd-pcm module. + * + * Copyright (c) Takashi Sakamoto <[email protected]> + * + * Licensed under the terms of the GNU General Public License, version 2. + */ + +#ifndef __SOUND_CORE_PCM_LOCAL_H +#define __SOUND_CORE_PCM_LOCAL_H + +extern const struct snd_pcm_hw_constraint_list snd_pcm_known_rates; + +void snd_interval_mul(const struct snd_interval *a, +		      const struct snd_interval *b, struct snd_interval *c); +void snd_interval_div(const struct snd_interval *a, +		      const struct snd_interval *b, struct snd_interval *c); +void snd_interval_muldivk(const struct snd_interval *a, +			  const struct snd_interval *b, +			  unsigned int k, struct snd_interval *c); +void snd_interval_mulkdiv(const struct snd_interval *a, unsigned int k, +			  const struct snd_interval *b, struct snd_interval *c); + +int snd_pcm_hw_constraints_init(struct snd_pcm_substream *substream); +int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream); + +int snd_pcm_hw_constraint_mask(struct snd_pcm_runtime *runtime, +			       snd_pcm_hw_param_t var, u_int32_t mask); + +int pcm_lib_apply_appl_ptr(struct snd_pcm_substream *substream, +			   snd_pcm_uframes_t appl_ptr); +int snd_pcm_update_state(struct snd_pcm_substream *substream, +			 struct snd_pcm_runtime *runtime); +int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream); + +void snd_pcm_playback_silence(struct snd_pcm_substream *substream, +			      snd_pcm_uframes_t new_hw_ptr); + +#ifdef CONFIG_SND_PCM_TIMER +void snd_pcm_timer_resolution_change(struct snd_pcm_substream *substream); +void snd_pcm_timer_init(struct snd_pcm_substream *substream); +void snd_pcm_timer_done(struct snd_pcm_substream *substream); +#else +static inline void +snd_pcm_timer_resolution_change(struct snd_pcm_substream *substream) {} +static inline void snd_pcm_timer_init(struct snd_pcm_substream *substream) {} +static inline void snd_pcm_timer_done(struct snd_pcm_substream *substream) {} +#endif + +#endif	/* __SOUND_CORE_PCM_LOCAL_H */ diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index b45f6aa32264..ae33e456708c 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c @@ -120,7 +120,6 @@ int snd_pcm_lib_preallocate_free_for_all(struct snd_pcm *pcm)  			snd_pcm_lib_preallocate_free(substream);  	return 0;  } -  EXPORT_SYMBOL(snd_pcm_lib_preallocate_free_for_all);  #ifdef CONFIG_SND_VERBOSE_PROCFS @@ -263,7 +262,6 @@ int snd_pcm_lib_preallocate_pages(struct snd_pcm_substream *substream,  	substream->dma_buffer.dev.dev = data;  	return snd_pcm_lib_preallocate_pages1(substream, size, max);  } -  EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages);  /** @@ -292,7 +290,6 @@ int snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm,  				return err;  	return 0;  } -  EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages_for_all);  #ifdef CONFIG_SND_DMA_SGBUF @@ -314,7 +311,6 @@ struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream, unsigne  		return NULL;  	return sgbuf->page_table[idx];  } -  EXPORT_SYMBOL(snd_pcm_sgbuf_ops_page);  #endif /* CONFIG_SND_DMA_SGBUF */ @@ -370,7 +366,6 @@ int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size)  	runtime->dma_bytes = size;  	return 1;			/* area was changed */  } -  EXPORT_SYMBOL(snd_pcm_lib_malloc_pages);  /** @@ -398,7 +393,6 @@ int snd_pcm_lib_free_pages(struct snd_pcm_substream *substream)  	snd_pcm_set_runtime_buffer(substream, NULL);  	return 0;  } -  EXPORT_SYMBOL(snd_pcm_lib_free_pages);  int _snd_pcm_lib_alloc_vmalloc_buffer(struct snd_pcm_substream *substream, diff --git a/sound/core/pcm_misc.c b/sound/core/pcm_misc.c index 53dc37357bca..9be81025372f 100644 --- a/sound/core/pcm_misc.c +++ b/sound/core/pcm_misc.c @@ -23,6 +23,9 @@  #include <linux/export.h>  #include <sound/core.h>  #include <sound/pcm.h> + +#include "pcm_local.h" +  #define SND_PCM_FORMAT_UNKNOWN (-1)  /* NOTE: "signed" prefix must be given below since the default char is @@ -245,7 +248,6 @@ int snd_pcm_format_signed(snd_pcm_format_t format)  		return -EINVAL;  	return val;  } -  EXPORT_SYMBOL(snd_pcm_format_signed);  /** @@ -264,7 +266,6 @@ int snd_pcm_format_unsigned(snd_pcm_format_t format)  		return val;  	return !val;  } -  EXPORT_SYMBOL(snd_pcm_format_unsigned);  /** @@ -277,7 +278,6 @@ int snd_pcm_format_linear(snd_pcm_format_t format)  {  	return snd_pcm_format_signed(format) >= 0;  } -  EXPORT_SYMBOL(snd_pcm_format_linear);  /** @@ -296,7 +296,6 @@ int snd_pcm_format_little_endian(snd_pcm_format_t format)  		return -EINVAL;  	return val;  } -  EXPORT_SYMBOL(snd_pcm_format_little_endian);  /** @@ -315,7 +314,6 @@ int snd_pcm_format_big_endian(snd_pcm_format_t format)  		return val;  	return !val;  } -  EXPORT_SYMBOL(snd_pcm_format_big_endian);  /** @@ -334,7 +332,6 @@ int snd_pcm_format_width(snd_pcm_format_t format)  		return -EINVAL;  	return val;  } -  EXPORT_SYMBOL(snd_pcm_format_width);  /** @@ -353,7 +350,6 @@ int snd_pcm_format_physical_width(snd_pcm_format_t format)  		return -EINVAL;  	return val;  } -  EXPORT_SYMBOL(snd_pcm_format_physical_width);  /** @@ -371,7 +367,6 @@ ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples)  		return -EINVAL;  	return samples * phys_width / 8;  } -  EXPORT_SYMBOL(snd_pcm_format_size);  /** @@ -388,7 +383,6 @@ const unsigned char *snd_pcm_format_silence_64(snd_pcm_format_t format)  		return NULL;  	return pcm_formats[(INT)format].silence;  } -  EXPORT_SYMBOL(snd_pcm_format_silence_64);  /** @@ -459,7 +453,6 @@ int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int  #endif  	return 0;  } -  EXPORT_SYMBOL(snd_pcm_format_set_silence);  /** @@ -488,7 +481,6 @@ int snd_pcm_limit_hw_rates(struct snd_pcm_runtime *runtime)  	}  	return 0;  } -  EXPORT_SYMBOL(snd_pcm_limit_hw_rates);  /** diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 13dec5ec93f2..b3d5bed75029 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -37,6 +37,18 @@  #include <sound/minors.h>  #include <linux/uio.h> +#include "pcm_local.h" + +#ifdef CONFIG_SND_DEBUG +#define CREATE_TRACE_POINTS +#include "pcm_param_trace.h" +#else +#define trace_hw_mask_param_enabled()		0 +#define trace_hw_interval_param_enabled()	0 +#define trace_hw_mask_param(substream, type, index, prev, curr) +#define trace_hw_interval_param(substream, type, index, prev, curr) +#endif +  /*   *  Compatibility   */ @@ -181,20 +193,6 @@ void snd_pcm_stream_unlock_irqrestore(struct snd_pcm_substream *substream,  }  EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock_irqrestore); -static inline mm_segment_t snd_enter_user(void) -{ -	mm_segment_t fs = get_fs(); -	set_fs(get_ds()); -	return fs; -} - -static inline void snd_leave_user(mm_segment_t fs) -{ -	set_fs(fs); -} - - -  int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info)  {  	struct snd_pcm_runtime *runtime; @@ -214,11 +212,7 @@ int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info)  	info->subdevices_avail = pstr->substream_count - pstr->substream_opened;  	strlcpy(info->subname, substream->name, sizeof(info->subname));  	runtime = substream->runtime; -	/* AB: FIXME!!! This is definitely nonsense */ -	if (runtime) { -		info->sync = runtime->sync; -		substream->ops->ioctl(substream, SNDRV_PCM_IOCTL1_INFO, info); -	} +  	return 0;  } @@ -255,205 +249,268 @@ static bool hw_support_mmap(struct snd_pcm_substream *substream)  	return true;  } -#undef RULES_DEBUG - -#ifdef RULES_DEBUG -#define HW_PARAM(v) [SNDRV_PCM_HW_PARAM_##v] = #v -static const char * const snd_pcm_hw_param_names[] = { -	HW_PARAM(ACCESS), -	HW_PARAM(FORMAT), -	HW_PARAM(SUBFORMAT), -	HW_PARAM(SAMPLE_BITS), -	HW_PARAM(FRAME_BITS), -	HW_PARAM(CHANNELS), -	HW_PARAM(RATE), -	HW_PARAM(PERIOD_TIME), -	HW_PARAM(PERIOD_SIZE), -	HW_PARAM(PERIOD_BYTES), -	HW_PARAM(PERIODS), -	HW_PARAM(BUFFER_TIME), -	HW_PARAM(BUFFER_SIZE), -	HW_PARAM(BUFFER_BYTES), -	HW_PARAM(TICK_TIME), -}; -#endif - -int snd_pcm_hw_refine(struct snd_pcm_substream *substream,  -		      struct snd_pcm_hw_params *params) +static int constrain_mask_params(struct snd_pcm_substream *substream, +				 struct snd_pcm_hw_params *params)  { +	struct snd_pcm_hw_constraints *constrs = +					&substream->runtime->hw_constraints; +	struct snd_mask *m;  	unsigned int k; -	struct snd_pcm_hardware *hw; -	struct snd_interval *i = NULL; -	struct snd_mask *m = NULL; -	struct snd_pcm_hw_constraints *constrs = &substream->runtime->hw_constraints; -	unsigned int rstamps[constrs->rules_num]; -	unsigned int vstamps[SNDRV_PCM_HW_PARAM_LAST_INTERVAL + 1]; -	unsigned int stamp = 2; -	int changed, again; - -	params->info = 0; -	params->fifo_size = 0; -	if (params->rmask & (1 << SNDRV_PCM_HW_PARAM_SAMPLE_BITS)) -		params->msbits = 0; -	if (params->rmask & (1 << SNDRV_PCM_HW_PARAM_RATE)) { -		params->rate_num = 0; -		params->rate_den = 0; -	} +	struct snd_mask old_mask; +	int changed;  	for (k = SNDRV_PCM_HW_PARAM_FIRST_MASK; k <= SNDRV_PCM_HW_PARAM_LAST_MASK; k++) {  		m = hw_param_mask(params, k);  		if (snd_mask_empty(m))  			return -EINVAL; + +		/* This parameter is not requested to change by a caller. */  		if (!(params->rmask & (1 << k)))  			continue; -#ifdef RULES_DEBUG -		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 + +		if (trace_hw_mask_param_enabled()) +			old_mask = *m; +  		changed = snd_mask_refine(m, constrs_mask(constrs, k)); -#ifdef RULES_DEBUG -		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;  		if (changed < 0)  			return changed; +		if (changed == 0) +			continue; + +		/* Set corresponding flag so that the caller gets it. */ +		trace_hw_mask_param(substream, k, 0, &old_mask, m); +		params->cmask |= 1 << k;  	} +	return 0; +} + +static int constrain_interval_params(struct snd_pcm_substream *substream, +				     struct snd_pcm_hw_params *params) +{ +	struct snd_pcm_hw_constraints *constrs = +					&substream->runtime->hw_constraints; +	struct snd_interval *i; +	unsigned int k; +	struct snd_interval old_interval; +	int changed; +  	for (k = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++) {  		i = hw_param_interval(params, k);  		if (snd_interval_empty(i))  			return -EINVAL; + +		/* This parameter is not requested to change by a caller. */  		if (!(params->rmask & (1 << k)))  			continue; -#ifdef RULES_DEBUG -		pr_debug("%s = ", snd_pcm_hw_param_names[k]); -		if (i->empty) -			pr_cont("empty"); -		else -			pr_cont("%c%u %u%c", -			       i->openmin ? '(' : '[', i->min, -			       i->max, i->openmax ? ')' : ']'); -		pr_cont(" -> "); -#endif + +		if (trace_hw_interval_param_enabled()) +			old_interval = *i; +  		changed = snd_interval_refine(i, constrs_interval(constrs, k)); -#ifdef RULES_DEBUG -		if (i->empty) -			pr_cont("empty\n"); -		else  -			pr_cont("%c%u %u%c\n", -			       i->openmin ? '(' : '[', i->min, -			       i->max, i->openmax ? ')' : ']'); -#endif -		if (changed) -			params->cmask |= 1 << k;  		if (changed < 0)  			return changed; +		if (changed == 0) +			continue; + +		/* Set corresponding flag so that the caller gets it. */ +		trace_hw_interval_param(substream, k, 0, &old_interval, i); +		params->cmask |= 1 << k;  	} +	return 0; +} + +static int constrain_params_by_rules(struct snd_pcm_substream *substream, +				     struct snd_pcm_hw_params *params) +{ +	struct snd_pcm_hw_constraints *constrs = +					&substream->runtime->hw_constraints; +	unsigned int k; +	unsigned int rstamps[constrs->rules_num]; +	unsigned int vstamps[SNDRV_PCM_HW_PARAM_LAST_INTERVAL + 1]; +	unsigned int stamp; +	struct snd_pcm_hw_rule *r; +	unsigned int d; +	struct snd_mask old_mask; +	struct snd_interval old_interval; +	bool again; +	int changed; + +	/* +	 * Each application of rule has own sequence number. +	 * +	 * Each member of 'rstamps' array represents the sequence number of +	 * recent application of corresponding rule. +	 */  	for (k = 0; k < constrs->rules_num; k++)  		rstamps[k] = 0; -	for (k = 0; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++)  + +	/* +	 * Each member of 'vstamps' array represents the sequence number of +	 * recent application of rule in which corresponding parameters were +	 * changed. +	 * +	 * In initial state, elements corresponding to parameters requested by +	 * a caller is 1. For unrequested parameters, corresponding members +	 * have 0 so that the parameters are never changed anymore. +	 */ +	for (k = 0; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++)  		vstamps[k] = (params->rmask & (1 << k)) ? 1 : 0; -	do { -		again = 0; -		for (k = 0; k < constrs->rules_num; k++) { -			struct snd_pcm_hw_rule *r = &constrs->rules[k]; -			unsigned int d; -			int doit = 0; -			if (r->cond && !(r->cond & params->flags)) -				continue; -			for (d = 0; r->deps[d] >= 0; d++) { -				if (vstamps[r->deps[d]] > rstamps[k]) { -					doit = 1; -					break; -				} -			} -			if (!doit) -				continue; -#ifdef RULES_DEBUG -			pr_debug("Rule %d [%p]: ", k, r->func); -			if (r->var >= 0) { -				pr_cont("%s = ", snd_pcm_hw_param_names[r->var]); -				if (hw_is_mask(r->var)) { -					m = hw_param_mask(params, r->var); -					pr_cont("%x", *m->bits); -				} else { -					i = hw_param_interval(params, r->var); -					if (i->empty) -						pr_cont("empty"); -					else -						pr_cont("%c%u %u%c", -						       i->openmin ? '(' : '[', i->min, -						       i->max, i->openmax ? ')' : ']'); -				} -			} -#endif -			changed = r->func(params, r); -#ifdef RULES_DEBUG -			if (r->var >= 0) { -				pr_cont(" -> "); -				if (hw_is_mask(r->var)) -					pr_cont("%x", *m->bits); -				else { -					if (i->empty) -						pr_cont("empty"); -					else -						pr_cont("%c%u %u%c", -						       i->openmin ? '(' : '[', i->min, -						       i->max, i->openmax ? ')' : ']'); -				} + +	/* Due to the above design, actual sequence number starts at 2. */ +	stamp = 2; +retry: +	/* Apply all rules in order. */ +	again = false; +	for (k = 0; k < constrs->rules_num; k++) { +		r = &constrs->rules[k]; + +		/* +		 * Check condition bits of this rule. When the rule has +		 * some condition bits, parameter without the bits is +		 * never processed. SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP +		 * is an example of the condition bits. +		 */ +		if (r->cond && !(r->cond & params->flags)) +			continue; + +		/* +		 * The 'deps' array includes maximum three dependencies +		 * to SNDRV_PCM_HW_PARAM_XXXs for this rule. The fourth +		 * member of this array is a sentinel and should be +		 * negative value. +		 * +		 * This rule should be processed in this time when dependent +		 * parameters were changed at former applications of the other +		 * rules. +		 */ +		for (d = 0; r->deps[d] >= 0; d++) { +			if (vstamps[r->deps[d]] > rstamps[k]) +				break; +		} +		if (r->deps[d] < 0) +			continue; + +		if (trace_hw_mask_param_enabled()) { +			if (hw_is_mask(r->var)) +				old_mask = *hw_param_mask(params, r->var); +		} +		if (trace_hw_interval_param_enabled()) { +			if (hw_is_interval(r->var)) +				old_interval = *hw_param_interval(params, r->var); +		} + +		changed = r->func(params, r); +		if (changed < 0) +			return changed; + +		/* +		 * When the parameter is changed, notify it to the caller +		 * by corresponding returned bit, then preparing for next +		 * iteration. +		 */ +		if (changed && r->var >= 0) { +			if (hw_is_mask(r->var)) { +				trace_hw_mask_param(substream, r->var, +					k + 1, &old_mask, +					hw_param_mask(params, r->var));  			} -			pr_cont("\n"); -#endif -			rstamps[k] = stamp; -			if (changed && r->var >= 0) { -				params->cmask |= (1 << r->var); -				vstamps[r->var] = stamp; -				again = 1; +			if (hw_is_interval(r->var)) { +				trace_hw_interval_param(substream, r->var, +					k + 1, &old_interval, +					hw_param_interval(params, r->var));  			} -			if (changed < 0) -				return changed; -			stamp++; + +			params->cmask |= (1 << r->var); +			vstamps[r->var] = stamp; +			again = true;  		} -	} while (again); + +		rstamps[k] = stamp++; +	} + +	/* Iterate to evaluate all rules till no parameters are changed. */ +	if (again) +		goto retry; + +	return 0; +} + +static int fixup_unreferenced_params(struct snd_pcm_substream *substream, +				     struct snd_pcm_hw_params *params) +{ +	const struct snd_interval *i; +	const struct snd_mask *m; +	int err; +  	if (!params->msbits) { -		i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); +		i = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS);  		if (snd_interval_single(i))  			params->msbits = snd_interval_value(i);  	}  	if (!params->rate_den) { -		i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); +		i = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE);  		if (snd_interval_single(i)) {  			params->rate_num = snd_interval_value(i);  			params->rate_den = 1;  		}  	} -	hw = &substream->runtime->hw; +	if (!params->fifo_size) { +		m = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT); +		i = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS); +		if (snd_mask_single(m) && snd_interval_single(i)) { +			err = substream->ops->ioctl(substream, +					SNDRV_PCM_IOCTL1_FIFO_SIZE, params); +			if (err < 0) +				return err; +		} +	} +  	if (!params->info) { -		params->info = hw->info & ~(SNDRV_PCM_INFO_FIFO_IN_FRAMES | -					    SNDRV_PCM_INFO_DRAIN_TRIGGER); +		params->info = substream->runtime->hw.info; +		params->info &= ~(SNDRV_PCM_INFO_FIFO_IN_FRAMES | +				  SNDRV_PCM_INFO_DRAIN_TRIGGER);  		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); -		if (snd_mask_min(m) == snd_mask_max(m) && -                    snd_interval_min(i) == snd_interval_max(i)) { -			changed = substream->ops->ioctl(substream, -					SNDRV_PCM_IOCTL1_FIFO_SIZE, params); -			if (changed < 0) -				return changed; -		} + +	return 0; +} + +int snd_pcm_hw_refine(struct snd_pcm_substream *substream, +		      struct snd_pcm_hw_params *params) +{ +	int err; + +	params->info = 0; +	params->fifo_size = 0; +	if (params->rmask & (1 << SNDRV_PCM_HW_PARAM_SAMPLE_BITS)) +		params->msbits = 0; +	if (params->rmask & (1 << SNDRV_PCM_HW_PARAM_RATE)) { +		params->rate_num = 0; +		params->rate_den = 0;  	} + +	err = constrain_mask_params(substream, params); +	if (err < 0) +		return err; + +	err = constrain_interval_params(substream, params); +	if (err < 0) +		return err; + +	err = constrain_params_by_rules(substream, params); +	if (err < 0) +		return err; +  	params->rmask = 0; +  	return 0;  } -  EXPORT_SYMBOL(snd_pcm_hw_refine);  static int snd_pcm_hw_refine_user(struct snd_pcm_substream *substream, @@ -467,11 +524,16 @@ static int snd_pcm_hw_refine_user(struct snd_pcm_substream *substream,  		return PTR_ERR(params);  	err = snd_pcm_hw_refine(substream, params); -	if (copy_to_user(_params, params, sizeof(*params))) { -		if (!err) -			err = -EFAULT; -	} +	if (err < 0) +		goto end; + +	err = fixup_unreferenced_params(substream, params); +	if (err < 0) +		goto end; +	if (copy_to_user(_params, params, sizeof(*params))) +		err = -EFAULT; +end:  	kfree(params);  	return err;  } @@ -509,6 +571,70 @@ static inline void snd_pcm_timer_notify(struct snd_pcm_substream *substream,  #endif  } +/** + * snd_pcm_hw_param_choose - choose a configuration defined by @params + * @pcm: PCM instance + * @params: the hw_params instance + * + * Choose one configuration from configuration space defined by @params. + * The configuration chosen is that obtained fixing in this order: + * first access, first format, first subformat, min channels, + * min rate, min period time, max buffer size, min tick time + * + * Return: Zero if successful, or a negative error code on failure. + */ +static int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm, +				    struct snd_pcm_hw_params *params) +{ +	static const int vars[] = { +		SNDRV_PCM_HW_PARAM_ACCESS, +		SNDRV_PCM_HW_PARAM_FORMAT, +		SNDRV_PCM_HW_PARAM_SUBFORMAT, +		SNDRV_PCM_HW_PARAM_CHANNELS, +		SNDRV_PCM_HW_PARAM_RATE, +		SNDRV_PCM_HW_PARAM_PERIOD_TIME, +		SNDRV_PCM_HW_PARAM_BUFFER_SIZE, +		SNDRV_PCM_HW_PARAM_TICK_TIME, +		-1 +	}; +	const int *v; +	struct snd_mask old_mask; +	struct snd_interval old_interval; +	int changed; + +	for (v = vars; *v != -1; v++) { +		/* Keep old parameter to trace. */ +		if (trace_hw_mask_param_enabled()) { +			if (hw_is_mask(*v)) +				old_mask = *hw_param_mask(params, *v); +		} +		if (trace_hw_interval_param_enabled()) { +			if (hw_is_interval(*v)) +				old_interval = *hw_param_interval(params, *v); +		} +		if (*v != SNDRV_PCM_HW_PARAM_BUFFER_SIZE) +			changed = snd_pcm_hw_param_first(pcm, params, *v, NULL); +		else +			changed = snd_pcm_hw_param_last(pcm, params, *v, NULL); +		if (snd_BUG_ON(changed < 0)) +			return changed; +		if (changed == 0) +			continue; + +		/* Trace the changed parameter. */ +		if (hw_is_mask(*v)) { +			trace_hw_mask_param(pcm, *v, 0, &old_mask, +					    hw_param_mask(params, *v)); +		} +		if (hw_is_interval(*v)) { +			trace_hw_interval_param(pcm, *v, 0, &old_interval, +						hw_param_interval(params, *v)); +		} +	} + +	return 0; +} +  static int snd_pcm_hw_params(struct snd_pcm_substream *substream,  			     struct snd_pcm_hw_params *params)  { @@ -546,6 +672,10 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,  	if (err < 0)  		goto _error; +	err = fixup_unreferenced_params(substream, params); +	if (err < 0) +		goto _error; +  	if (substream->ops->hw_params != NULL) {  		err = substream->ops->hw_params(substream, params);  		if (err < 0) @@ -621,11 +751,12 @@ static int snd_pcm_hw_params_user(struct snd_pcm_substream *substream,  		return PTR_ERR(params);  	err = snd_pcm_hw_params(substream, params); -	if (copy_to_user(_params, params, sizeof(*params))) { -		if (!err) -			err = -EFAULT; -	} +	if (err < 0) +		goto end; +	if (copy_to_user(_params, params, sizeof(*params))) +		err = -EFAULT; +end:  	kfree(params);  	return err;  } @@ -1081,6 +1212,7 @@ static const struct action_ops snd_pcm_action_start = {   * @substream: the PCM substream instance   *   * Return: Zero if successful, or a negative error code. + * The stream lock must be acquired before calling this function.   */  int snd_pcm_start(struct snd_pcm_substream *substream)  { @@ -1088,6 +1220,13 @@ int snd_pcm_start(struct snd_pcm_substream *substream)  			      SNDRV_PCM_STATE_RUNNING);  } +/* take the stream lock and start the streams */ +static int snd_pcm_start_lock_irq(struct snd_pcm_substream *substream) +{ +	return snd_pcm_action_lock_irq(&snd_pcm_action_start, substream, +				       SNDRV_PCM_STATE_RUNNING); +} +  /*   * stop callbacks   */ @@ -1139,7 +1278,6 @@ int snd_pcm_stop(struct snd_pcm_substream *substream, snd_pcm_state_t state)  {  	return snd_pcm_action(&snd_pcm_action_stop, substream, state);  } -  EXPORT_SYMBOL(snd_pcm_stop);  /** @@ -1314,7 +1452,6 @@ int snd_pcm_suspend(struct snd_pcm_substream *substream)  	snd_pcm_stream_unlock_irqrestore(substream, flags);  	return err;  } -  EXPORT_SYMBOL(snd_pcm_suspend);  /** @@ -1346,7 +1483,6 @@ int snd_pcm_suspend_all(struct snd_pcm *pcm)  	}  	return 0;  } -  EXPORT_SYMBOL(snd_pcm_suspend_all);  /* resume */ @@ -1397,14 +1533,7 @@ static const struct action_ops snd_pcm_action_resume = {  static int snd_pcm_resume(struct snd_pcm_substream *substream)  { -	struct snd_card *card = substream->pcm->card; -	int res; - -	snd_power_lock(card); -	if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0)) >= 0) -		res = snd_pcm_action_lock_irq(&snd_pcm_action_resume, substream, 0); -	snd_power_unlock(card); -	return res; +	return snd_pcm_action_lock_irq(&snd_pcm_action_resume, substream, 0);  }  #else @@ -1423,17 +1552,9 @@ static int snd_pcm_resume(struct snd_pcm_substream *substream)   */  static int snd_pcm_xrun(struct snd_pcm_substream *substream)  { -	struct snd_card *card = substream->pcm->card;  	struct snd_pcm_runtime *runtime = substream->runtime;  	int result; -	snd_power_lock(card); -	if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { -		result = snd_power_wait(card, SNDRV_CTL_POWER_D0); -		if (result < 0) -			goto _unlock; -	} -  	snd_pcm_stream_lock_irq(substream);  	switch (runtime->status->state) {  	case SNDRV_PCM_STATE_XRUN: @@ -1446,8 +1567,6 @@ static int snd_pcm_xrun(struct snd_pcm_substream *substream)  		result = -EBADFD;  	}  	snd_pcm_stream_unlock_irq(substream); - _unlock: -	snd_power_unlock(card);  	return result;  } @@ -1551,8 +1670,6 @@ static const struct action_ops snd_pcm_action_prepare = {  static int snd_pcm_prepare(struct snd_pcm_substream *substream,  			   struct file *file)  { -	int res; -	struct snd_card *card = substream->pcm->card;  	int f_flags;  	if (file) @@ -1560,12 +1677,19 @@ static int snd_pcm_prepare(struct snd_pcm_substream *substream,  	else  		f_flags = substream->f_flags; -	snd_power_lock(card); -	if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0)) >= 0) -		res = snd_pcm_action_nonatomic(&snd_pcm_action_prepare, -					       substream, f_flags); -	snd_power_unlock(card); -	return res; +	snd_pcm_stream_lock_irq(substream); +	switch (substream->runtime->status->state) { +	case SNDRV_PCM_STATE_PAUSED: +		snd_pcm_pause(substream, 0); +		/* fallthru */ +	case SNDRV_PCM_STATE_SUSPENDED: +		snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); +		break; +	} +	snd_pcm_stream_unlock_irq(substream); + +	return snd_pcm_action_nonatomic(&snd_pcm_action_prepare, +					substream, f_flags);  }  /* @@ -1652,7 +1776,7 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream,  	struct snd_card *card;  	struct snd_pcm_runtime *runtime;  	struct snd_pcm_substream *s; -	wait_queue_t wait; +	wait_queue_entry_t wait;  	int result = 0;  	int nonblock = 0; @@ -1662,15 +1786,6 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream,  	if (runtime->status->state == SNDRV_PCM_STATE_OPEN)  		return -EBADFD; -	snd_power_lock(card); -	if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { -		result = snd_power_wait(card, SNDRV_CTL_POWER_D0); -		if (result < 0) { -			snd_power_unlock(card); -			return result; -		} -	} -  	if (file) {  		if (file->f_flags & O_NONBLOCK)  			nonblock = 1; @@ -1753,7 +1868,6 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream,   unlock:  	snd_pcm_stream_unlock_irq(substream);  	up_read(&snd_pcm_link_rwsem); -	snd_power_unlock(card);  	return result;  } @@ -1773,8 +1887,7 @@ static int snd_pcm_drop(struct snd_pcm_substream *substream)  	runtime = substream->runtime;  	if (runtime->status->state == SNDRV_PCM_STATE_OPEN || -	    runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED || -	    runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) +	    runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED)  		return -EBADFD;  	snd_pcm_stream_lock_irq(substream); @@ -1940,7 +2053,8 @@ static int snd_pcm_hw_rule_format(struct snd_pcm_hw_params *params,  				  struct snd_pcm_hw_rule *rule)  {  	unsigned int k; -	struct snd_interval *i = hw_param_interval(params, rule->deps[0]); +	const struct snd_interval *i = +				hw_param_interval_c(params, rule->deps[0]);  	struct snd_mask m;  	struct snd_mask *mask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);  	snd_mask_any(&m); @@ -1986,8 +2100,10 @@ static int snd_pcm_hw_rule_sample_bits(struct snd_pcm_hw_params *params,  #error "Change this table"  #endif -static unsigned int rates[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100, -                                 48000, 64000, 88200, 96000, 176400, 192000 }; +static const unsigned int rates[] = { +	5512, 8000, 11025, 16000, 22050, 32000, 44100, +	48000, 64000, 88200, 96000, 176400, 192000 +};  const struct snd_pcm_hw_constraint_list snd_pcm_known_rates = {  	.count = ARRAY_SIZE(rates), @@ -2250,7 +2366,6 @@ void snd_pcm_release_substream(struct snd_pcm_substream *substream)  	}  	snd_pcm_detach_substream(substream);  } -  EXPORT_SYMBOL(snd_pcm_release_substream);  int snd_pcm_open_substream(struct snd_pcm *pcm, int stream, @@ -2292,7 +2407,6 @@ int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,  	snd_pcm_release_substream(substream);  	return err;  } -  EXPORT_SYMBOL(snd_pcm_open_substream);  static int snd_pcm_open_file(struct file *file, @@ -2353,7 +2467,7 @@ static int snd_pcm_capture_open(struct inode *inode, struct file *file)  static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream)  {  	int err; -	wait_queue_t wait; +	wait_queue_entry_t wait;  	if (pcm == NULL) {  		err = -ENODEV; @@ -2428,50 +2542,84 @@ static int snd_pcm_release(struct inode *inode, struct file *file)  	return 0;  } -static snd_pcm_sframes_t snd_pcm_playback_rewind(struct snd_pcm_substream *substream, -						 snd_pcm_uframes_t frames) +/* check and update PCM state; return 0 or a negative error + * call this inside PCM lock + */ +static int do_pcm_hwsync(struct snd_pcm_substream *substream)  { -	struct snd_pcm_runtime *runtime = substream->runtime; -	snd_pcm_sframes_t appl_ptr; -	snd_pcm_sframes_t ret; -	snd_pcm_sframes_t hw_avail; - -	if (frames == 0) -		return 0; - -	snd_pcm_stream_lock_irq(substream); -	switch (runtime->status->state) { -	case SNDRV_PCM_STATE_PREPARED: -		break; +	switch (substream->runtime->status->state) {  	case SNDRV_PCM_STATE_DRAINING: -	case SNDRV_PCM_STATE_RUNNING: -		if (snd_pcm_update_hw_ptr(substream) >= 0) -			break; +		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) +			return -EBADFD;  		/* Fall through */ -	case SNDRV_PCM_STATE_XRUN: -		ret = -EPIPE; -		goto __end; +	case SNDRV_PCM_STATE_RUNNING: +		return snd_pcm_update_hw_ptr(substream); +	case SNDRV_PCM_STATE_PREPARED: +	case SNDRV_PCM_STATE_PAUSED: +		return 0;  	case SNDRV_PCM_STATE_SUSPENDED: -		ret = -ESTRPIPE; -		goto __end; +		return -ESTRPIPE; +	case SNDRV_PCM_STATE_XRUN: +		return -EPIPE;  	default: -		ret = -EBADFD; -		goto __end; +		return -EBADFD;  	} +} -	hw_avail = snd_pcm_playback_hw_avail(runtime); -	if (hw_avail <= 0) { -		ret = 0; -		goto __end; -	} -	if (frames > (snd_pcm_uframes_t)hw_avail) -		frames = hw_avail; +/* increase the appl_ptr; returns the processed frames or a negative error */ +static snd_pcm_sframes_t forward_appl_ptr(struct snd_pcm_substream *substream, +					  snd_pcm_uframes_t frames, +					   snd_pcm_sframes_t avail) +{ +	struct snd_pcm_runtime *runtime = substream->runtime; +	snd_pcm_sframes_t appl_ptr; +	int ret; + +	if (avail <= 0) +		return 0; +	if (frames > (snd_pcm_uframes_t)avail) +		frames = avail; +	appl_ptr = runtime->control->appl_ptr + frames; +	if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary) +		appl_ptr -= runtime->boundary; +	ret = pcm_lib_apply_appl_ptr(substream, appl_ptr); +	return ret < 0 ? ret : frames; +} + +/* decrease the appl_ptr; returns the processed frames or a negative error */ +static snd_pcm_sframes_t rewind_appl_ptr(struct snd_pcm_substream *substream, +					 snd_pcm_uframes_t frames, +					 snd_pcm_sframes_t avail) +{ +	struct snd_pcm_runtime *runtime = substream->runtime; +	snd_pcm_sframes_t appl_ptr; +	int ret; + +	if (avail <= 0) +		return 0; +	if (frames > (snd_pcm_uframes_t)avail) +		frames = avail;  	appl_ptr = runtime->control->appl_ptr - frames;  	if (appl_ptr < 0)  		appl_ptr += runtime->boundary; -	runtime->control->appl_ptr = appl_ptr; -	ret = frames; - __end: +	ret = pcm_lib_apply_appl_ptr(substream, appl_ptr); +	return ret < 0 ? ret : frames; +} + +static snd_pcm_sframes_t snd_pcm_playback_rewind(struct snd_pcm_substream *substream, +						 snd_pcm_uframes_t frames) +{ +	struct snd_pcm_runtime *runtime = substream->runtime; +	snd_pcm_sframes_t ret; + +	if (frames == 0) +		return 0; + +	snd_pcm_stream_lock_irq(substream); +	ret = do_pcm_hwsync(substream); +	if (!ret) +		ret = rewind_appl_ptr(substream, frames, +				      snd_pcm_playback_hw_avail(runtime));  	snd_pcm_stream_unlock_irq(substream);  	return ret;  } @@ -2480,46 +2628,16 @@ static snd_pcm_sframes_t snd_pcm_capture_rewind(struct snd_pcm_substream *substr  						snd_pcm_uframes_t frames)  {  	struct snd_pcm_runtime *runtime = substream->runtime; -	snd_pcm_sframes_t appl_ptr;  	snd_pcm_sframes_t ret; -	snd_pcm_sframes_t hw_avail;  	if (frames == 0)  		return 0;  	snd_pcm_stream_lock_irq(substream); -	switch (runtime->status->state) { -	case SNDRV_PCM_STATE_PREPARED: -	case SNDRV_PCM_STATE_DRAINING: -		break; -	case SNDRV_PCM_STATE_RUNNING: -		if (snd_pcm_update_hw_ptr(substream) >= 0) -			break; -		/* Fall through */ -	case SNDRV_PCM_STATE_XRUN: -		ret = -EPIPE; -		goto __end; -	case SNDRV_PCM_STATE_SUSPENDED: -		ret = -ESTRPIPE; -		goto __end; -	default: -		ret = -EBADFD; -		goto __end; -	} - -	hw_avail = snd_pcm_capture_hw_avail(runtime); -	if (hw_avail <= 0) { -		ret = 0; -		goto __end; -	} -	if (frames > (snd_pcm_uframes_t)hw_avail) -		frames = hw_avail; -	appl_ptr = runtime->control->appl_ptr - frames; -	if (appl_ptr < 0) -		appl_ptr += runtime->boundary; -	runtime->control->appl_ptr = appl_ptr; -	ret = frames; - __end: +	ret = do_pcm_hwsync(substream); +	if (!ret) +		ret = rewind_appl_ptr(substream, frames, +				      snd_pcm_capture_hw_avail(runtime));  	snd_pcm_stream_unlock_irq(substream);  	return ret;  } @@ -2528,47 +2646,16 @@ static snd_pcm_sframes_t snd_pcm_playback_forward(struct snd_pcm_substream *subs  						  snd_pcm_uframes_t frames)  {  	struct snd_pcm_runtime *runtime = substream->runtime; -	snd_pcm_sframes_t appl_ptr;  	snd_pcm_sframes_t ret; -	snd_pcm_sframes_t avail;  	if (frames == 0)  		return 0;  	snd_pcm_stream_lock_irq(substream); -	switch (runtime->status->state) { -	case SNDRV_PCM_STATE_PREPARED: -	case SNDRV_PCM_STATE_PAUSED: -		break; -	case SNDRV_PCM_STATE_DRAINING: -	case SNDRV_PCM_STATE_RUNNING: -		if (snd_pcm_update_hw_ptr(substream) >= 0) -			break; -		/* Fall through */ -	case SNDRV_PCM_STATE_XRUN: -		ret = -EPIPE; -		goto __end; -	case SNDRV_PCM_STATE_SUSPENDED: -		ret = -ESTRPIPE; -		goto __end; -	default: -		ret = -EBADFD; -		goto __end; -	} - -	avail = snd_pcm_playback_avail(runtime); -	if (avail <= 0) { -		ret = 0; -		goto __end; -	} -	if (frames > (snd_pcm_uframes_t)avail) -		frames = avail; -	appl_ptr = runtime->control->appl_ptr + frames; -	if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary) -		appl_ptr -= runtime->boundary; -	runtime->control->appl_ptr = appl_ptr; -	ret = frames; - __end: +	ret = do_pcm_hwsync(substream); +	if (!ret) +		ret = forward_appl_ptr(substream, frames, +				       snd_pcm_playback_avail(runtime));  	snd_pcm_stream_unlock_irq(substream);  	return ret;  } @@ -2577,123 +2664,47 @@ static snd_pcm_sframes_t snd_pcm_capture_forward(struct snd_pcm_substream *subst  						 snd_pcm_uframes_t frames)  {  	struct snd_pcm_runtime *runtime = substream->runtime; -	snd_pcm_sframes_t appl_ptr;  	snd_pcm_sframes_t ret; -	snd_pcm_sframes_t avail;  	if (frames == 0)  		return 0;  	snd_pcm_stream_lock_irq(substream); -	switch (runtime->status->state) { -	case SNDRV_PCM_STATE_PREPARED: -	case SNDRV_PCM_STATE_DRAINING: -	case SNDRV_PCM_STATE_PAUSED: -		break; -	case SNDRV_PCM_STATE_RUNNING: -		if (snd_pcm_update_hw_ptr(substream) >= 0) -			break; -		/* Fall through */ -	case SNDRV_PCM_STATE_XRUN: -		ret = -EPIPE; -		goto __end; -	case SNDRV_PCM_STATE_SUSPENDED: -		ret = -ESTRPIPE; -		goto __end; -	default: -		ret = -EBADFD; -		goto __end; -	} - -	avail = snd_pcm_capture_avail(runtime); -	if (avail <= 0) { -		ret = 0; -		goto __end; -	} -	if (frames > (snd_pcm_uframes_t)avail) -		frames = avail; -	appl_ptr = runtime->control->appl_ptr + frames; -	if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary) -		appl_ptr -= runtime->boundary; -	runtime->control->appl_ptr = appl_ptr; -	ret = frames; - __end: +	ret = do_pcm_hwsync(substream); +	if (!ret) +		ret = forward_appl_ptr(substream, frames, +				       snd_pcm_capture_avail(runtime));  	snd_pcm_stream_unlock_irq(substream);  	return ret;  }  static int snd_pcm_hwsync(struct snd_pcm_substream *substream)  { -	struct snd_pcm_runtime *runtime = substream->runtime;  	int err;  	snd_pcm_stream_lock_irq(substream); -	switch (runtime->status->state) { -	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; -		/* Fall through */ -	case SNDRV_PCM_STATE_PREPARED: -		err = 0; -		break; -	case SNDRV_PCM_STATE_SUSPENDED: -		err = -ESTRPIPE; -		break; -	case SNDRV_PCM_STATE_XRUN: -		err = -EPIPE; -		break; -	default: -	      __badfd: -		err = -EBADFD; -		break; -	} +	err = do_pcm_hwsync(substream);  	snd_pcm_stream_unlock_irq(substream);  	return err;  } -static int snd_pcm_delay(struct snd_pcm_substream *substream, -			 snd_pcm_sframes_t __user *res) +static snd_pcm_sframes_t snd_pcm_delay(struct snd_pcm_substream *substream)  {  	struct snd_pcm_runtime *runtime = substream->runtime;  	int err;  	snd_pcm_sframes_t n = 0;  	snd_pcm_stream_lock_irq(substream); -	switch (runtime->status->state) { -	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; -		/* Fall through */ -	case SNDRV_PCM_STATE_PREPARED: -	case SNDRV_PCM_STATE_SUSPENDED: -		err = 0; +	err = do_pcm_hwsync(substream); +	if (!err) {  		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)  			n = snd_pcm_playback_hw_avail(runtime);  		else  			n = snd_pcm_capture_avail(runtime);  		n += runtime->delay; -		break; -	case SNDRV_PCM_STATE_XRUN: -		err = -EPIPE; -		break; -	default: -	      __badfd: -		err = -EBADFD; -		break;  	}  	snd_pcm_stream_unlock_irq(substream); -	if (!err) -		if (put_user(n, res)) -			err = -EFAULT; -	return err; +	return err < 0 ? err : n;  }  static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream, @@ -2718,10 +2729,16 @@ static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream,  			return err;  	}  	snd_pcm_stream_lock_irq(substream); -	if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) -		control->appl_ptr = sync_ptr.c.control.appl_ptr; -	else +	if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) { +		err = pcm_lib_apply_appl_ptr(substream, +					     sync_ptr.c.control.appl_ptr); +		if (err < 0) { +			snd_pcm_stream_unlock_irq(substream); +			return err; +		} +	} else {  		sync_ptr.c.control.appl_ptr = control->appl_ptr; +	}  	if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))  		control->avail_min = sync_ptr.c.control.avail_min;  	else @@ -2749,10 +2766,12 @@ static int snd_pcm_tstamp(struct snd_pcm_substream *substream, int __user *_arg)  	return 0;  } -static int snd_pcm_common_ioctl1(struct file *file, +static int snd_pcm_common_ioctl(struct file *file,  				 struct snd_pcm_substream *substream,  				 unsigned int cmd, void __user *arg)  { +	struct snd_pcm_file *pcm_file = file->private_data; +  	switch (cmd) {  	case SNDRV_PCM_IOCTL_PVERSION:  		return put_user(SNDRV_PCM_VERSION, (int __user *)arg) ? -EFAULT : 0; @@ -2762,6 +2781,11 @@ static int snd_pcm_common_ioctl1(struct file *file,  		return 0;  	case SNDRV_PCM_IOCTL_TTSTAMP:  		return snd_pcm_tstamp(substream, arg); +	case SNDRV_PCM_IOCTL_USER_PVERSION: +		if (get_user(pcm_file->user_pversion, +			     (unsigned int __user *)arg)) +			return -EFAULT; +		return 0;  	case SNDRV_PCM_IOCTL_HW_REFINE:  		return snd_pcm_hw_refine_user(substream, arg);  	case SNDRV_PCM_IOCTL_HW_PARAMS: @@ -2781,7 +2805,7 @@ static int snd_pcm_common_ioctl1(struct file *file,  	case SNDRV_PCM_IOCTL_RESET:  		return snd_pcm_reset(substream);  	case SNDRV_PCM_IOCTL_START: -		return snd_pcm_action_lock_irq(&snd_pcm_action_start, substream, SNDRV_PCM_STATE_RUNNING); +		return snd_pcm_start_lock_irq(substream);  	case SNDRV_PCM_IOCTL_LINK:  		return snd_pcm_link(substream, (int)(unsigned long) arg);  	case SNDRV_PCM_IOCTL_UNLINK: @@ -2793,7 +2817,16 @@ static int snd_pcm_common_ioctl1(struct file *file,  	case SNDRV_PCM_IOCTL_HWSYNC:  		return snd_pcm_hwsync(substream);  	case SNDRV_PCM_IOCTL_DELAY: -		return snd_pcm_delay(substream, arg); +	{ +		snd_pcm_sframes_t delay = snd_pcm_delay(substream); +		snd_pcm_sframes_t __user *res = arg; + +		if (delay < 0) +			return delay; +		if (put_user(delay, res)) +			return -EFAULT; +		return 0; +	}  	case SNDRV_PCM_IOCTL_SYNC_PTR:  		return snd_pcm_sync_ptr(substream, arg);  #ifdef CONFIG_SND_SUPPORT_OLD_API @@ -2807,23 +2840,34 @@ static int snd_pcm_common_ioctl1(struct file *file,  	case SNDRV_PCM_IOCTL_DROP:  		return snd_pcm_drop(substream);  	case SNDRV_PCM_IOCTL_PAUSE: -	{ -		int res; -		snd_pcm_stream_lock_irq(substream); -		res = snd_pcm_pause(substream, (int)(unsigned long)arg); -		snd_pcm_stream_unlock_irq(substream); -		return res; -	} +		return snd_pcm_action_lock_irq(&snd_pcm_action_pause, +					       substream, +					       (int)(unsigned long)arg);  	}  	pcm_dbg(substream->pcm, "unknown ioctl = 0x%x\n", cmd);  	return -ENOTTY;  } +static int snd_pcm_common_ioctl1(struct file *file, +				 struct snd_pcm_substream *substream, +				 unsigned int cmd, void __user *arg) +{ +	struct snd_card *card = substream->pcm->card; +	int res; + +	snd_power_lock(card); +	res = snd_power_wait(card, SNDRV_CTL_POWER_D0); +	if (res >= 0) +		res = snd_pcm_common_ioctl(file, substream, cmd, arg); +	snd_power_unlock(card); +	return res; +} +  static int snd_pcm_playback_ioctl1(struct file *file,  				   struct snd_pcm_substream *substream,  				   unsigned int cmd, void __user *arg)  { -	if (snd_BUG_ON(!substream)) +	if (PCM_RUNTIME_CHECK(substream))  		return -ENXIO;  	if (snd_BUG_ON(substream->stream != SNDRV_PCM_STREAM_PLAYBACK))  		return -EINVAL; @@ -2903,7 +2947,7 @@ static int snd_pcm_capture_ioctl1(struct file *file,  				  struct snd_pcm_substream *substream,  				  unsigned int cmd, void __user *arg)  { -	if (snd_BUG_ON(!substream)) +	if (PCM_RUNTIME_CHECK(substream))  		return -ENXIO;  	if (snd_BUG_ON(substream->stream != SNDRV_PCM_STREAM_CAPTURE))  		return -EINVAL; @@ -3007,30 +3051,55 @@ static long snd_pcm_capture_ioctl(struct file *file, unsigned int cmd,  				      (void __user *)arg);  } +/** + * snd_pcm_kernel_ioctl - Execute PCM ioctl in the kernel-space + * @substream: PCM substream + * @cmd: IOCTL cmd + * @arg: IOCTL argument + * + * The function is provided primarily for OSS layer and USB gadget drivers, + * and it allows only the limited set of ioctls (hw_params, sw_params, + * prepare, start, drain, drop, forward). + */  int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream,  			 unsigned int cmd, void *arg)  { -	mm_segment_t fs; -	int result; +	snd_pcm_uframes_t *frames = arg; +	snd_pcm_sframes_t result; -	fs = snd_enter_user(); -	switch (substream->stream) { -	case SNDRV_PCM_STREAM_PLAYBACK: -		result = snd_pcm_playback_ioctl1(NULL, substream, cmd, -						 (void __user *)arg); -		break; -	case SNDRV_PCM_STREAM_CAPTURE: -		result = snd_pcm_capture_ioctl1(NULL, substream, cmd, -						(void __user *)arg); -		break; +	switch (cmd) { +	case SNDRV_PCM_IOCTL_FORWARD: +	{ +		/* provided only for OSS; capture-only and no value returned */ +		if (substream->stream != SNDRV_PCM_STREAM_CAPTURE) +			return -EINVAL; +		result = snd_pcm_capture_forward(substream, *frames); +		return result < 0 ? result : 0; +	} +	case SNDRV_PCM_IOCTL_HW_PARAMS: +		return snd_pcm_hw_params(substream, arg); +	case SNDRV_PCM_IOCTL_SW_PARAMS: +		return snd_pcm_sw_params(substream, arg); +	case SNDRV_PCM_IOCTL_PREPARE: +		return snd_pcm_prepare(substream, NULL); +	case SNDRV_PCM_IOCTL_START: +		return snd_pcm_start_lock_irq(substream); +	case SNDRV_PCM_IOCTL_DRAIN: +		return snd_pcm_drain(substream, NULL); +	case SNDRV_PCM_IOCTL_DROP: +		return snd_pcm_drop(substream); +	case SNDRV_PCM_IOCTL_DELAY: +	{ +		result = snd_pcm_delay(substream); +		if (result < 0) +			return result; +		*frames = result; +		return 0; +	}  	default: -		result = -EINVAL; -		break; +		return -EINVAL;  	} -	snd_leave_user(fs); -	return result;  } -  EXPORT_SYMBOL(snd_pcm_kernel_ioctl);  static ssize_t snd_pcm_read(struct file *file, char __user *buf, size_t count, @@ -3314,10 +3383,41 @@ static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file  	area->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;  	return 0;  } + +static bool pcm_status_mmap_allowed(struct snd_pcm_file *pcm_file) +{ +	if (pcm_file->no_compat_mmap) +		return false; +	/* See pcm_control_mmap_allowed() below. +	 * Since older alsa-lib requires both status and control mmaps to be +	 * coupled, we have to disable the status mmap for old alsa-lib, too. +	 */ +	if (pcm_file->user_pversion < SNDRV_PROTOCOL_VERSION(2, 0, 14) && +	    (pcm_file->substream->runtime->hw.info & SNDRV_PCM_INFO_SYNC_APPLPTR)) +		return false; +	return true; +} + +static bool pcm_control_mmap_allowed(struct snd_pcm_file *pcm_file) +{ +	if (pcm_file->no_compat_mmap) +		return false; +	/* Disallow the control mmap when SYNC_APPLPTR flag is set; +	 * it enforces the user-space to fall back to snd_pcm_sync_ptr(), +	 * thus it effectively assures the manual update of appl_ptr. +	 */ +	if (pcm_file->substream->runtime->hw.info & SNDRV_PCM_INFO_SYNC_APPLPTR) +		return false; +	return true; +} +  #else /* ! coherent mmap */  /*   * don't support mmap for status and control records.   */ +#define pcm_status_mmap_allowed(pcm_file)	false +#define pcm_control_mmap_allowed(pcm_file)	false +  static int snd_pcm_mmap_status(struct snd_pcm_substream *substream, struct file *file,  			       struct vm_area_struct *area)  { @@ -3437,7 +3537,6 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream,  	area->vm_page_prot = pgprot_noncached(area->vm_page_prot);  	return vm_iomap_memory(area, runtime->dma_addr, runtime->dma_bytes);  } -  EXPORT_SYMBOL(snd_pcm_lib_mmap_iomem);  #endif /* SNDRV_PCM_INFO_MMAP */ @@ -3486,7 +3585,6 @@ int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file,  		atomic_inc(&substream->mmap_count);  	return err;  } -  EXPORT_SYMBOL(snd_pcm_mmap_data);  static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area) @@ -3503,11 +3601,11 @@ static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area)  	offset = area->vm_pgoff << PAGE_SHIFT;  	switch (offset) {  	case SNDRV_PCM_MMAP_OFFSET_STATUS: -		if (pcm_file->no_compat_mmap) +		if (!pcm_status_mmap_allowed(pcm_file))  			return -ENXIO;  		return snd_pcm_mmap_status(substream, file, area);  	case SNDRV_PCM_MMAP_OFFSET_CONTROL: -		if (pcm_file->no_compat_mmap) +		if (!pcm_control_mmap_allowed(pcm_file))  			return -ENXIO;  		return snd_pcm_mmap_control(substream, file, area);  	default: @@ -3603,12 +3701,17 @@ static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream,  	}  	snd_pcm_hw_convert_from_old_params(params, oparams);  	err = snd_pcm_hw_refine(substream, params); -	snd_pcm_hw_convert_to_old_params(oparams, params); -	if (copy_to_user(_oparams, oparams, sizeof(*oparams))) { -		if (!err) -			err = -EFAULT; -	} +	if (err < 0) +		goto out_old; +	err = fixup_unreferenced_params(substream, params); +	if (err < 0) +		goto out_old; + +	snd_pcm_hw_convert_to_old_params(oparams, params); +	if (copy_to_user(_oparams, oparams, sizeof(*oparams))) +		err = -EFAULT; +out_old:  	kfree(oparams);  out:  	kfree(params); @@ -3631,14 +3734,16 @@ static int snd_pcm_hw_params_old_user(struct snd_pcm_substream *substream,  		err = PTR_ERR(oparams);  		goto out;  	} +  	snd_pcm_hw_convert_from_old_params(params, oparams);  	err = snd_pcm_hw_params(substream, params); -	snd_pcm_hw_convert_to_old_params(oparams, params); -	if (copy_to_user(_oparams, oparams, sizeof(*oparams))) { -		if (!err) -			err = -EFAULT; -	} +	if (err < 0) +		goto out_old; +	snd_pcm_hw_convert_to_old_params(oparams, params); +	if (copy_to_user(_oparams, oparams, sizeof(*oparams))) +		err = -EFAULT; +out_old:  	kfree(oparams);  out:  	kfree(params); diff --git a/sound/core/pcm_param_trace.h b/sound/core/pcm_param_trace.h new file mode 100644 index 000000000000..86c8d658a25c --- /dev/null +++ b/sound/core/pcm_param_trace.h @@ -0,0 +1,142 @@ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM snd_pcm + +#if !defined(_PCM_PARAMS_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) +#define _PCM_PARAMS_TRACE_H + +#include <linux/tracepoint.h> + +#define HW_PARAM_ENTRY(param) {SNDRV_PCM_HW_PARAM_##param, #param} +#define hw_param_labels			\ +	HW_PARAM_ENTRY(ACCESS),		\ +	HW_PARAM_ENTRY(FORMAT),		\ +	HW_PARAM_ENTRY(SUBFORMAT),	\ +	HW_PARAM_ENTRY(SAMPLE_BITS),	\ +	HW_PARAM_ENTRY(FRAME_BITS),	\ +	HW_PARAM_ENTRY(CHANNELS),	\ +	HW_PARAM_ENTRY(RATE),		\ +	HW_PARAM_ENTRY(PERIOD_TIME),	\ +	HW_PARAM_ENTRY(PERIOD_SIZE),	\ +	HW_PARAM_ENTRY(PERIOD_BYTES),	\ +	HW_PARAM_ENTRY(PERIODS),	\ +	HW_PARAM_ENTRY(BUFFER_TIME),	\ +	HW_PARAM_ENTRY(BUFFER_SIZE),	\ +	HW_PARAM_ENTRY(BUFFER_BYTES),	\ +	HW_PARAM_ENTRY(TICK_TIME) + +TRACE_EVENT(hw_mask_param, +	TP_PROTO(struct snd_pcm_substream *substream, snd_pcm_hw_param_t type, int index, const struct snd_mask *prev, const struct snd_mask *curr), +	TP_ARGS(substream, type, index, prev, curr), +	TP_STRUCT__entry( +		__field(int, card) +		__field(int, device) +		__field(int, subdevice) +		__field(int, direction) +		__field(snd_pcm_hw_param_t, type) +		__field(int, index) +		__field(int, total) +		__array(__u32, prev_bits, 8) +		__array(__u32, curr_bits, 8) +	), +	TP_fast_assign( +		__entry->card = substream->pcm->card->number; +		__entry->device = substream->pcm->device; +		__entry->subdevice = substream->number; +		__entry->direction = substream->stream; +		__entry->type = type; +		__entry->index = index; +		__entry->total = substream->runtime->hw_constraints.rules_num; +		memcpy(__entry->prev_bits, prev->bits, sizeof(__u32) * 8); +		memcpy(__entry->curr_bits, curr->bits, sizeof(__u32) * 8); +	), +	TP_printk("pcmC%dD%d%s:%d %03d/%03d %s %08x%08x%08x%08x %08x%08x%08x%08x", +		  __entry->card, +		  __entry->device, +		  __entry->direction ? "c" : "p", +		  __entry->subdevice, +		  __entry->index, +		  __entry->total, +		  __print_symbolic(__entry->type, hw_param_labels), +		  __entry->prev_bits[3], __entry->prev_bits[2], +		  __entry->prev_bits[1], __entry->prev_bits[0], +		  __entry->curr_bits[3], __entry->curr_bits[2], +		  __entry->curr_bits[1], __entry->curr_bits[0] +	) +); + +TRACE_EVENT(hw_interval_param, +	TP_PROTO(struct snd_pcm_substream *substream, snd_pcm_hw_param_t type, int index, const struct snd_interval *prev, const struct snd_interval *curr), +	TP_ARGS(substream, type, index, prev, curr), +	TP_STRUCT__entry( +		__field(int, card) +		__field(int, device) +		__field(int, subdevice) +		__field(int, direction) +		__field(snd_pcm_hw_param_t, type) +		__field(int, index) +		__field(int, total) +		__field(unsigned int, prev_min) +		__field(unsigned int, prev_max) +		__field(unsigned int, prev_openmin) +		__field(unsigned int, prev_openmax) +		__field(unsigned int, prev_integer) +		__field(unsigned int, prev_empty) +		__field(unsigned int, curr_min) +		__field(unsigned int, curr_max) +		__field(unsigned int, curr_openmin) +		__field(unsigned int, curr_openmax) +		__field(unsigned int, curr_integer) +		__field(unsigned int, curr_empty) +	), +	TP_fast_assign( +		__entry->card = substream->pcm->card->number; +		__entry->device = substream->pcm->device; +		__entry->subdevice = substream->number; +		__entry->direction = substream->stream; +		__entry->type = type; +		__entry->index = index; +		__entry->total = substream->runtime->hw_constraints.rules_num; +		__entry->prev_min = prev->min; +		__entry->prev_max = prev->max; +		__entry->prev_openmin = prev->openmin; +		__entry->prev_openmax = prev->openmax; +		__entry->prev_integer = prev->integer; +		__entry->prev_empty = prev->empty; +		__entry->curr_min = curr->min; +		__entry->curr_max = curr->max; +		__entry->curr_openmin = curr->openmin; +		__entry->curr_openmax = curr->openmax; +		__entry->curr_integer = curr->integer; +		__entry->curr_empty = curr->empty; +	), +	TP_printk("pcmC%dD%d%s:%d %03d/%03d %s %d %d %s%u %u%s %d %d %s%u %u%s", +		  __entry->card, +		  __entry->device, +		  __entry->direction ? "c" : "p", +		  __entry->subdevice, +		  __entry->index, +		  __entry->total, +		  __print_symbolic(__entry->type, hw_param_labels), +		  __entry->prev_empty, +		  __entry->prev_integer, +		  __entry->prev_openmin ? "(" : "[", +		  __entry->prev_min, +		  __entry->prev_max, +		  __entry->prev_openmax ? ")" : "]", +		  __entry->curr_empty, +		  __entry->curr_integer, +		  __entry->curr_openmin ? "(" : "[", +		  __entry->curr_min, +		  __entry->curr_max, +		  __entry->curr_openmax ? ")" : "]" +	) +); + +#endif /* _PCM_PARAMS_TRACE_H */ + +/* This part must be outside protection */ +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE pcm_param_trace +#include <trace/define_trace.h> diff --git a/sound/core/pcm_timer.c b/sound/core/pcm_timer.c index 20ecd8f18080..11389f13de73 100644 --- a/sound/core/pcm_timer.c +++ b/sound/core/pcm_timer.c @@ -25,6 +25,8 @@  #include <sound/pcm.h>  #include <sound/timer.h> +#include "pcm_local.h" +  /*   *  Timer functions   */ @@ -33,8 +35,8 @@ void snd_pcm_timer_resolution_change(struct snd_pcm_substream *substream)  {  	unsigned long rate, mult, fsize, l, post;  	struct snd_pcm_runtime *runtime = substream->runtime; -	 -        mult = 1000000000; + +	mult = 1000000000;  	rate = runtime->rate;  	if (snd_BUG_ON(!rate))  		return; @@ -65,7 +67,7 @@ void snd_pcm_timer_resolution_change(struct snd_pcm_substream *substream)  static unsigned long snd_pcm_timer_resolution(struct snd_timer * timer)  {  	struct snd_pcm_substream *substream; -	 +  	substream = timer->private_data;  	return substream->runtime ? substream->runtime->timer_resolution : 0;  } @@ -73,7 +75,7 @@ static unsigned long snd_pcm_timer_resolution(struct snd_timer * timer)  static int snd_pcm_timer_start(struct snd_timer * timer)  {  	struct snd_pcm_substream *substream; -	 +  	substream = snd_timer_chip(timer);  	substream->timer_running = 1;  	return 0; @@ -82,7 +84,7 @@ static int snd_pcm_timer_start(struct snd_timer * timer)  static int snd_pcm_timer_stop(struct snd_timer * timer)  {  	struct snd_pcm_substream *substream; -	 +  	substream = snd_timer_chip(timer);  	substream->timer_running = 0;  	return 0; @@ -112,7 +114,7 @@ void snd_pcm_timer_init(struct snd_pcm_substream *substream)  {  	struct snd_timer_id tid;  	struct snd_timer *timer; -	 +  	tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE;  	tid.dev_class = SNDRV_TIMER_CLASS_PCM;  	tid.card = substream->pcm->card->number; diff --git a/sound/core/pcm_trace.h b/sound/core/pcm_trace.h index b63b654da5ff..3ddec1b8ae46 100644 --- a/sound/core/pcm_trace.h +++ b/sound/core/pcm_trace.h @@ -34,9 +34,9 @@ TRACE_EVENT(hwptr,  		__entry->old_hw_ptr = (substream)->runtime->status->hw_ptr;  		__entry->hw_ptr_base = (substream)->runtime->hw_ptr_base;  	), -	TP_printk("pcmC%dD%d%c/sub%d: %s: pos=%lu, old=%lu, base=%lu, period=%lu, buf=%lu", +	TP_printk("pcmC%dD%d%s/sub%d: %s: pos=%lu, old=%lu, base=%lu, period=%lu, buf=%lu",  		  __entry->card, __entry->device, -		  __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c', +		  __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? "p" : "c",  		  __entry->number,  		  __entry->in_interrupt ? "IRQ" : "POS",  		  (unsigned long)__entry->pos, @@ -69,9 +69,9 @@ TRACE_EVENT(xrun,  		__entry->old_hw_ptr = (substream)->runtime->status->hw_ptr;  		__entry->hw_ptr_base = (substream)->runtime->hw_ptr_base;  	), -	TP_printk("pcmC%dD%d%c/sub%d: XRUN: old=%lu, base=%lu, period=%lu, buf=%lu", +	TP_printk("pcmC%dD%d%s/sub%d: XRUN: old=%lu, base=%lu, period=%lu, buf=%lu",  		  __entry->card, __entry->device, -		  __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c', +		  __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? "p" : "c",  		  __entry->number,  		  (unsigned long)__entry->old_hw_ptr,  		  (unsigned long)__entry->hw_ptr_base, @@ -96,12 +96,50 @@ TRACE_EVENT(hw_ptr_error,  		__entry->stream = (substream)->stream;  		__entry->reason = (why);  	), -	TP_printk("pcmC%dD%d%c/sub%d: ERROR: %s", +	TP_printk("pcmC%dD%d%s/sub%d: ERROR: %s",  		  __entry->card, __entry->device, -		  __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c', +		  __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? "p" : "c",  		  __entry->number, __entry->reason)  ); +TRACE_EVENT(applptr, +	TP_PROTO(struct snd_pcm_substream *substream, snd_pcm_uframes_t prev, snd_pcm_uframes_t curr), +	TP_ARGS(substream, prev, curr), +	TP_STRUCT__entry( +		__field( unsigned int, card ) +		__field( unsigned int, device ) +		__field( unsigned int, number ) +		__field( unsigned int, stream ) +		__field( snd_pcm_uframes_t, prev ) +		__field( snd_pcm_uframes_t, curr ) +		__field( snd_pcm_uframes_t, avail ) +		__field( snd_pcm_uframes_t, period_size ) +		__field( snd_pcm_uframes_t, buffer_size ) +	), +	TP_fast_assign( +		__entry->card = (substream)->pcm->card->number; +		__entry->device = (substream)->pcm->device; +		__entry->number = (substream)->number; +		__entry->stream = (substream)->stream; +		__entry->prev = (prev); +		__entry->curr = (curr); +		__entry->avail = (substream)->stream ? snd_pcm_capture_avail(substream->runtime) : snd_pcm_playback_avail(substream->runtime); +		__entry->period_size = (substream)->runtime->period_size; +		__entry->buffer_size = (substream)->runtime->buffer_size; +	), +	TP_printk("pcmC%dD%d%s/sub%d: prev=%lu, curr=%lu, avail=%lu, period=%lu, buf=%lu", +		__entry->card, +		__entry->device, +		__entry->stream ? "c" : "p", +		__entry->number, +		__entry->prev, +		__entry->curr, +		__entry->avail, +		__entry->period_size, +		__entry->buffer_size +	) +); +  #endif /* _PCM_TRACE_H */  /* This part must be outside protection */ diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index ab890336175f..b3b353d72527 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -368,7 +368,7 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)  	int err;  	struct snd_rawmidi *rmidi;  	struct snd_rawmidi_file *rawmidi_file = NULL; -	wait_queue_t wait; +	wait_queue_entry_t wait;  	if ((file->f_flags & O_APPEND) && !(file->f_flags & O_NONBLOCK))   		return -EINVAL;		/* invalid combination */ @@ -1002,7 +1002,7 @@ static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t coun  	while (count > 0) {  		spin_lock_irq(&runtime->lock);  		while (!snd_rawmidi_ready(substream)) { -			wait_queue_t wait; +			wait_queue_entry_t wait;  			if ((file->f_flags & O_NONBLOCK) != 0 || result > 0) {  				spin_unlock_irq(&runtime->lock);  				return result > 0 ? result : -EAGAIN; @@ -1306,7 +1306,7 @@ static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf,  	while (count > 0) {  		spin_lock_irq(&runtime->lock);  		while (!snd_rawmidi_ready_append(substream, count)) { -			wait_queue_t wait; +			wait_queue_entry_t wait;  			if (file->f_flags & O_NONBLOCK) {  				spin_unlock_irq(&runtime->lock);  				return result > 0 ? result : -EAGAIN; @@ -1338,7 +1338,7 @@ static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf,  	if (file->f_flags & O_DSYNC) {  		spin_lock_irq(&runtime->lock);  		while (runtime->avail != runtime->buffer_size) { -			wait_queue_t wait; +			wait_queue_entry_t wait;  			unsigned int last_avail = runtime->avail;  			init_waitqueue_entry(&wait, current);  			add_wait_queue(&runtime->sleep, &wait); @@ -1610,7 +1610,7 @@ static int snd_rawmidi_dev_free(struct snd_device *device)  	return snd_rawmidi_free(rmidi);  } -#if IS_REACHABLE(CONFIG_SND_SEQUENCER) +#if IS_ENABLED(CONFIG_SND_SEQUENCER)  static void snd_rawmidi_dev_seq_free(struct snd_seq_device *device)  {  	struct snd_rawmidi *rmidi = device->private_data; @@ -1691,7 +1691,7 @@ static int snd_rawmidi_dev_register(struct snd_device *device)  		}  	}  	rmidi->proc_entry = entry; -#if IS_REACHABLE(CONFIG_SND_SEQUENCER) +#if IS_ENABLED(CONFIG_SND_SEQUENCER)  	if (!rmidi->ops || !rmidi->ops->dev_register) { /* own registration mechanism */  		if (snd_seq_device_new(rmidi->card, rmidi->device, SNDRV_SEQ_DEV_ID_MIDISYNTH, 0, &rmidi->seq_dev) >= 0) {  			rmidi->seq_dev->private_data = rmidi; diff --git a/sound/core/seq/Kconfig b/sound/core/seq/Kconfig index b851fd890a89..a536760a94c2 100644 --- a/sound/core/seq/Kconfig +++ b/sound/core/seq/Kconfig @@ -1,16 +1,62 @@ -# define SND_XXX_SEQ to min(SND_SEQUENCER,SND_XXX) +config SND_SEQUENCER +	tristate "Sequencer support" +	select SND_TIMER +	select SND_SEQ_DEVICE +	help +	  Say Y or M to enable MIDI sequencer and router support.  This +	  feature allows routing and enqueueing of MIDI events.  Events +	  can be processed at a given time. -config SND_RAWMIDI_SEQ -	def_tristate SND_SEQUENCER && SND_RAWMIDI +	  Many programs require this feature, so you should enable it +	  unless you know what you're doing. -config SND_OPL3_LIB_SEQ -	def_tristate SND_SEQUENCER && SND_OPL3_LIB +if SND_SEQUENCER -config SND_OPL4_LIB_SEQ -	def_tristate SND_SEQUENCER && SND_OPL4_LIB +config SND_SEQ_DUMMY +	tristate "Sequencer dummy client" +	help +	  Say Y here to enable the dummy sequencer client.  This client +	  is a simple MIDI-through client: all normal input events are +	  redirected to the output port immediately. -config SND_SBAWE_SEQ -	def_tristate SND_SEQUENCER && SND_SBAWE +	  You don't need this unless you want to connect many MIDI +	  devices or applications together. -config SND_EMU10K1_SEQ -	def_tristate SND_SEQUENCER && SND_EMU10K1 +	  To compile this driver as a module, choose M here: the module +	  will be called snd-seq-dummy. + +config SND_SEQUENCER_OSS +	tristate "OSS Sequencer API" +	depends on SND_OSSEMUL +	select SND_SEQ_MIDI_EVENT +	help +	  Say Y here to enable OSS sequencer emulation (both +	  /dev/sequencer and /dev/music interfaces). + +	  Many programs still use the OSS API, so say Y. + +	  To compile this driver as a module, choose M here: the module +	  will be called snd-seq-oss. + +config SND_SEQ_HRTIMER_DEFAULT +	bool "Use HR-timer as default sequencer timer" +	depends on SND_HRTIMER +	default y +	help +	  Say Y here to use the HR-timer backend as the default sequencer +	  timer. + +config SND_SEQ_MIDI_EVENT +	def_tristate SND_RAWMIDI + +config SND_SEQ_MIDI +	tristate +	select SND_SEQ_MIDI_EVENT + +config SND_SEQ_MIDI_EMUL +	tristate + +config SND_SEQ_VIRMIDI +	tristate + +endif # SND_SEQUENCER diff --git a/sound/core/seq/Makefile b/sound/core/seq/Makefile index b65fa5a1943b..68fd367ac39c 100644 --- a/sound/core/seq/Makefile +++ b/sound/core/seq/Makefile @@ -3,7 +3,6 @@  # Copyright (c) 1999 by Jaroslav Kysela <[email protected]>  # -snd-seq-device-objs := seq_device.o  snd-seq-objs := seq.o seq_lock.o seq_clientmgr.o seq_memory.o seq_queue.o \                  seq_fifo.o seq_prioq.o seq_timer.o \                  seq_system.o seq_ports.o @@ -14,17 +13,11 @@ snd-seq-midi-event-objs := seq_midi_event.o  snd-seq-dummy-objs := seq_dummy.o  snd-seq-virmidi-objs := seq_virmidi.o -obj-$(CONFIG_SND_SEQUENCER) += snd-seq.o snd-seq-device.o -ifeq ($(CONFIG_SND_SEQUENCER_OSS),y) -  obj-$(CONFIG_SND_SEQUENCER) += snd-seq-midi-event.o -  obj-$(CONFIG_SND_SEQUENCER) += oss/ -endif -obj-$(CONFIG_SND_SEQ_DUMMY) += snd-seq-dummy.o +obj-$(CONFIG_SND_SEQUENCER) += snd-seq.o +obj-$(CONFIG_SND_SEQUENCER_OSS) += oss/ -# Toplevel Module Dependency -obj-$(CONFIG_SND_VIRMIDI) += snd-seq-virmidi.o snd-seq-midi-event.o -obj-$(CONFIG_SND_RAWMIDI_SEQ) += snd-seq-midi.o snd-seq-midi-event.o -obj-$(CONFIG_SND_OPL3_LIB_SEQ) += snd-seq-midi-event.o snd-seq-midi-emul.o -obj-$(CONFIG_SND_OPL4_LIB_SEQ) += snd-seq-midi-event.o snd-seq-midi-emul.o -obj-$(CONFIG_SND_SBAWE_SEQ) += snd-seq-midi-emul.o snd-seq-virmidi.o -obj-$(CONFIG_SND_EMU10K1_SEQ) += snd-seq-midi-emul.o snd-seq-virmidi.o +obj-$(CONFIG_SND_SEQ_DUMMY) += snd-seq-dummy.o +obj-$(CONFIG_SND_SEQ_MIDI) += snd-seq-midi.o +obj-$(CONFIG_SND_SEQ_MIDI_EMUL) += snd-seq-midi-emul.o +obj-$(CONFIG_SND_SEQ_MIDI_EVENT) += snd-seq-midi-event.o +obj-$(CONFIG_SND_SEQ_VIRMIDI) += snd-seq-virmidi.o diff --git a/sound/core/seq/oss/Makefile b/sound/core/seq/oss/Makefile index b38406b8463c..4ea4e3eea6b7 100644 --- a/sound/core/seq/oss/Makefile +++ b/sound/core/seq/oss/Makefile @@ -7,4 +7,4 @@ snd-seq-oss-objs  := seq_oss.o seq_oss_init.o seq_oss_timer.o seq_oss_ioctl.o \  		     seq_oss_event.o seq_oss_rw.o seq_oss_synth.o \  		     seq_oss_midi.o seq_oss_readq.o seq_oss_writeq.o -obj-$(CONFIG_SND_SEQUENCER) += snd-seq-oss.o +obj-$(CONFIG_SND_SEQUENCER_OSS) += snd-seq-oss.o diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index f3b1d7f50b81..272c55fe17c8 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -1668,7 +1668,6 @@ int snd_seq_set_queue_tempo(int client, struct snd_seq_queue_tempo *tempo)  		return -EPERM;  	return snd_seq_queue_timer_set_tempo(tempo->queue, client, tempo);  } -  EXPORT_SYMBOL(snd_seq_set_queue_tempo);  static int snd_seq_ioctl_set_queue_tempo(struct snd_seq_client *client, @@ -2200,7 +2199,6 @@ int snd_seq_create_kernel_client(struct snd_card *card, int client_index,  	/* return client number to caller */  	return client->number;  } -  EXPORT_SYMBOL(snd_seq_create_kernel_client);  /* exported to kernel modules */ @@ -2219,7 +2217,6 @@ int snd_seq_delete_kernel_client(int client)  	kfree(ptr);  	return 0;  } -  EXPORT_SYMBOL(snd_seq_delete_kernel_client);  /* skeleton to enqueue event, called from snd_seq_kernel_client_enqueue @@ -2269,7 +2266,6 @@ int snd_seq_kernel_client_enqueue(int client, struct snd_seq_event * ev,  {  	return kernel_client_enqueue(client, ev, NULL, 0, atomic, hop);  } -  EXPORT_SYMBOL(snd_seq_kernel_client_enqueue);  /* @@ -2283,7 +2279,6 @@ int snd_seq_kernel_client_enqueue_blocking(int client, struct snd_seq_event * ev  {  	return kernel_client_enqueue(client, ev, file, 1, atomic, hop);  } -  EXPORT_SYMBOL(snd_seq_kernel_client_enqueue_blocking);  /*  @@ -2321,7 +2316,6 @@ int snd_seq_kernel_client_dispatch(int client, struct snd_seq_event * ev,  	snd_seq_client_unlock(cptr);  	return result;  } -  EXPORT_SYMBOL(snd_seq_kernel_client_dispatch);  /** @@ -2354,7 +2348,6 @@ int snd_seq_kernel_client_ctl(int clientid, unsigned int cmd, void *arg)  		 cmd, _IOC_TYPE(cmd), _IOC_NR(cmd));  	return -ENOTTY;  } -  EXPORT_SYMBOL(snd_seq_kernel_client_ctl);  /* exported (for OSS emulator) */ @@ -2372,7 +2365,6 @@ int snd_seq_kernel_client_write_poll(int clientid, struct file *file, poll_table  		return 1;  	return 0;  } -  EXPORT_SYMBOL(snd_seq_kernel_client_write_poll);  /*---------------------------------------------------------------------------*/ diff --git a/sound/core/seq/seq_fifo.c b/sound/core/seq/seq_fifo.c index 01c4cfe30c9f..a8c2822e0198 100644 --- a/sound/core/seq/seq_fifo.c +++ b/sound/core/seq/seq_fifo.c @@ -179,7 +179,7 @@ int snd_seq_fifo_cell_out(struct snd_seq_fifo *f,  {  	struct snd_seq_event_cell *cell;  	unsigned long flags; -	wait_queue_t wait; +	wait_queue_entry_t wait;  	if (snd_BUG_ON(!f))  		return -EINVAL; diff --git a/sound/core/seq/seq_lock.c b/sound/core/seq/seq_lock.c index 12ba83367b1b..0ff7926a5a69 100644 --- a/sound/core/seq/seq_lock.c +++ b/sound/core/seq/seq_lock.c @@ -40,7 +40,6 @@ void snd_use_lock_sync_helper(snd_use_lock_t *lockp, const char *file, int line)  		schedule_timeout_uninterruptible(1);  	}  } -  EXPORT_SYMBOL(snd_use_lock_sync_helper);  #endif diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c index d4c61ec9be13..f763682584a8 100644 --- a/sound/core/seq/seq_memory.c +++ b/sound/core/seq/seq_memory.c @@ -118,7 +118,6 @@ int snd_seq_dump_var_event(const struct snd_seq_event *event,  	}  	return 0;  } -  EXPORT_SYMBOL(snd_seq_dump_var_event); @@ -169,7 +168,6 @@ int snd_seq_expand_var_event(const struct snd_seq_event *event, int count, char  				     &buf);  	return err < 0 ? err : newlen;  } -  EXPORT_SYMBOL(snd_seq_expand_var_event);  /* @@ -227,7 +225,7 @@ static int snd_seq_cell_alloc(struct snd_seq_pool *pool,  	struct snd_seq_event_cell *cell;  	unsigned long flags;  	int err = -EAGAIN; -	wait_queue_t wait; +	wait_queue_entry_t wait;  	if (pool == NULL)  		return -EINVAL; diff --git a/sound/core/seq/seq_midi_emul.c b/sound/core/seq/seq_midi_emul.c index 7ba937399ac7..9e2912e3e80f 100644 --- a/sound/core/seq/seq_midi_emul.c +++ b/sound/core/seq/seq_midi_emul.c @@ -236,6 +236,7 @@ snd_midi_process_event(struct snd_midi_op *ops,  		break;  	}  } +EXPORT_SYMBOL(snd_midi_process_event);  /* @@ -409,6 +410,7 @@ snd_midi_channel_set_clear(struct snd_midi_channel_set *chset)  			chan->drum_channel = 0;  	}  } +EXPORT_SYMBOL(snd_midi_channel_set_clear);  /*   * Process a rpn message. @@ -701,6 +703,7 @@ struct snd_midi_channel_set *snd_midi_channel_alloc_set(int n)  	}  	return chset;  } +EXPORT_SYMBOL(snd_midi_channel_alloc_set);  /*   * Reset the midi controllers on a particular channel to default values. @@ -724,6 +727,7 @@ void snd_midi_channel_free_set(struct snd_midi_channel_set *chset)  	kfree(chset->channels);  	kfree(chset);  } +EXPORT_SYMBOL(snd_midi_channel_free_set);  static int __init alsa_seq_midi_emul_init(void)  { @@ -736,8 +740,3 @@ static void __exit alsa_seq_midi_emul_exit(void)  module_init(alsa_seq_midi_emul_init)  module_exit(alsa_seq_midi_emul_exit) - -EXPORT_SYMBOL(snd_midi_process_event); -EXPORT_SYMBOL(snd_midi_channel_set_clear); -EXPORT_SYMBOL(snd_midi_channel_alloc_set); -EXPORT_SYMBOL(snd_midi_channel_free_set); diff --git a/sound/core/seq/seq_midi_event.c b/sound/core/seq/seq_midi_event.c index 37db7ba492a6..90bbbdbeba03 100644 --- a/sound/core/seq/seq_midi_event.c +++ b/sound/core/seq/seq_midi_event.c @@ -134,6 +134,7 @@ int snd_midi_event_new(int bufsize, struct snd_midi_event **rdev)  	*rdev = dev;  	return 0;  } +EXPORT_SYMBOL(snd_midi_event_new);  void snd_midi_event_free(struct snd_midi_event *dev)  { @@ -142,6 +143,7 @@ void snd_midi_event_free(struct snd_midi_event *dev)  		kfree(dev);  	}  } +EXPORT_SYMBOL(snd_midi_event_free);  /*   * initialize record @@ -161,6 +163,7 @@ void snd_midi_event_reset_encode(struct snd_midi_event *dev)  	reset_encode(dev);  	spin_unlock_irqrestore(&dev->lock, flags);  } +EXPORT_SYMBOL(snd_midi_event_reset_encode);  void snd_midi_event_reset_decode(struct snd_midi_event *dev)  { @@ -170,6 +173,7 @@ void snd_midi_event_reset_decode(struct snd_midi_event *dev)  	dev->lastcmd = 0xff;  	spin_unlock_irqrestore(&dev->lock, flags);  } +EXPORT_SYMBOL(snd_midi_event_reset_decode);  #if 0  void snd_midi_event_init(struct snd_midi_event *dev) @@ -183,6 +187,7 @@ void snd_midi_event_no_status(struct snd_midi_event *dev, int on)  {  	dev->nostat = on ? 1 : 0;  } +EXPORT_SYMBOL(snd_midi_event_no_status);  /*   * resize buffer @@ -232,6 +237,7 @@ long snd_midi_event_encode(struct snd_midi_event *dev, unsigned char *buf, long  	return result;  } +EXPORT_SYMBOL(snd_midi_event_encode);  /*   *  read one byte and encode to sequencer event: @@ -307,6 +313,7 @@ int snd_midi_event_encode_byte(struct snd_midi_event *dev, int c,  	spin_unlock_irqrestore(&dev->lock, flags);  	return rc;  } +EXPORT_SYMBOL(snd_midi_event_encode_byte);  /* encode note event */  static void note_event(struct snd_midi_event *dev, struct snd_seq_event *ev) @@ -408,6 +415,7 @@ long snd_midi_event_decode(struct snd_midi_event *dev, unsigned char *buf, long  		return qlen;  	}  } +EXPORT_SYMBOL(snd_midi_event_decode);  /* decode note event */ @@ -524,19 +532,6 @@ static int extra_decode_xrpn(struct snd_midi_event *dev, unsigned char *buf,  	return idx;  } -/* - *  exports - */ -  -EXPORT_SYMBOL(snd_midi_event_new); -EXPORT_SYMBOL(snd_midi_event_free); -EXPORT_SYMBOL(snd_midi_event_reset_encode); -EXPORT_SYMBOL(snd_midi_event_reset_decode); -EXPORT_SYMBOL(snd_midi_event_no_status); -EXPORT_SYMBOL(snd_midi_event_encode); -EXPORT_SYMBOL(snd_midi_event_encode_byte); -EXPORT_SYMBOL(snd_midi_event_decode); -  static int __init alsa_seq_midi_event_init(void)  {  	return 0; diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c index fe686ee41c6d..0a7020c82bfc 100644 --- a/sound/core/seq/seq_ports.c +++ b/sound/core/seq/seq_ports.c @@ -685,7 +685,6 @@ int snd_seq_event_port_attach(int client,  	return ret;  } -  EXPORT_SYMBOL(snd_seq_event_port_attach);  /* @@ -706,5 +705,4 @@ int snd_seq_event_port_detach(int client, int port)  	return err;  } -  EXPORT_SYMBOL(snd_seq_event_port_detach); diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c index 52f31f1498f9..8d93a4021c78 100644 --- a/sound/core/seq/seq_virmidi.c +++ b/sound/core/seq/seq_virmidi.c @@ -534,6 +534,7 @@ int snd_virmidi_new(struct snd_card *card, int device, struct snd_rawmidi **rrmi  	*rrmidi = rmidi;  	return 0;  } +EXPORT_SYMBOL(snd_virmidi_new);  /*   *  ENTRY functions @@ -550,5 +551,3 @@ static void __exit alsa_virmidi_exit(void)  module_init(alsa_virmidi_init)  module_exit(alsa_virmidi_exit) - -EXPORT_SYMBOL(snd_virmidi_new); diff --git a/sound/core/seq/seq_device.c b/sound/core/seq_device.c index c4acf17e9f5e..c4acf17e9f5e 100644 --- a/sound/core/seq/seq_device.c +++ b/sound/core/seq_device.c diff --git a/sound/core/sound.c b/sound/core/sound.c index 175f9e4e01c8..b30f027eb0fe 100644 --- a/sound/core/sound.c +++ b/sound/core/sound.c @@ -74,7 +74,6 @@ void snd_request_card(int card)  		return;  	request_module("snd-card-%i", card);  } -  EXPORT_SYMBOL(snd_request_card);  static void snd_request_other(int minor) @@ -124,7 +123,6 @@ void *snd_lookup_minor_data(unsigned int minor, int type)  	mutex_unlock(&sound_mutex);  	return private_data;  } -  EXPORT_SYMBOL(snd_lookup_minor_data);  #ifdef CONFIG_MODULES diff --git a/sound/core/sound_oss.c b/sound/core/sound_oss.c index 0ca9d72b2273..0a5c66229a22 100644 --- a/sound/core/sound_oss.c +++ b/sound/core/sound_oss.c @@ -55,7 +55,6 @@ void *snd_lookup_oss_minor_data(unsigned int minor, int type)  	mutex_unlock(&sound_oss_mutex);  	return private_data;  } -  EXPORT_SYMBOL(snd_lookup_oss_minor_data);  static int snd_oss_kernel_minor(int type, struct snd_card *card, int dev) @@ -159,7 +158,6 @@ int snd_register_oss_device(int type, struct snd_card *card, int dev,  	kfree(preg);        	return -EBUSY;  } -  EXPORT_SYMBOL(snd_register_oss_device);  int snd_unregister_oss_device(int type, struct snd_card *card, int dev) @@ -200,7 +198,6 @@ int snd_unregister_oss_device(int type, struct snd_card *card, int dev)  	kfree(mptr);  	return 0;  } -  EXPORT_SYMBOL(snd_unregister_oss_device);  /* diff --git a/sound/core/timer.c b/sound/core/timer.c index 2f836ca09860..a9b9a277e00c 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -319,6 +319,7 @@ int snd_timer_open(struct snd_timer_instance **ti,  	*ti = timeri;  	return 0;  } +EXPORT_SYMBOL(snd_timer_open);  /*   * close a timer instance @@ -384,6 +385,7 @@ int snd_timer_close(struct snd_timer_instance *timeri)  	mutex_unlock(®ister_mutex);  	return 0;  } +EXPORT_SYMBOL(snd_timer_close);  unsigned long snd_timer_resolution(struct snd_timer_instance *timeri)  { @@ -398,6 +400,7 @@ unsigned long snd_timer_resolution(struct snd_timer_instance *timeri)  	}  	return 0;  } +EXPORT_SYMBOL(snd_timer_resolution);  static void snd_timer_notify1(struct snd_timer_instance *ti, int event)  { @@ -589,6 +592,7 @@ int snd_timer_start(struct snd_timer_instance *timeri, unsigned int ticks)  	else  		return snd_timer_start1(timeri, true, ticks);  } +EXPORT_SYMBOL(snd_timer_start);  /*   * stop the timer instance. @@ -602,6 +606,7 @@ int snd_timer_stop(struct snd_timer_instance *timeri)  	else  		return snd_timer_stop1(timeri, true);  } +EXPORT_SYMBOL(snd_timer_stop);  /*   * start again..  the tick is kept. @@ -617,6 +622,7 @@ int snd_timer_continue(struct snd_timer_instance *timeri)  	else  		return snd_timer_start1(timeri, false, 0);  } +EXPORT_SYMBOL(snd_timer_continue);  /*   * pause.. remember the ticks left @@ -628,6 +634,7 @@ int snd_timer_pause(struct snd_timer_instance * timeri)  	else  		return snd_timer_stop1(timeri, false);  } +EXPORT_SYMBOL(snd_timer_pause);  /*   * reschedule the timer @@ -809,6 +816,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)  	if (use_tasklet)  		tasklet_schedule(&timer->task_queue);  } +EXPORT_SYMBOL(snd_timer_interrupt);  /* @@ -859,6 +867,7 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid,  		*rtimer = timer;  	return 0;  } +EXPORT_SYMBOL(snd_timer_new);  static int snd_timer_free(struct snd_timer *timer)  { @@ -978,6 +987,7 @@ void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstam  	}  	spin_unlock_irqrestore(&timer->lock, flags);  } +EXPORT_SYMBOL(snd_timer_notify);  /*   * exported functions for global timers @@ -993,11 +1003,13 @@ int snd_timer_global_new(char *id, int device, struct snd_timer **rtimer)  	tid.subdevice = 0;  	return snd_timer_new(NULL, id, &tid, rtimer);  } +EXPORT_SYMBOL(snd_timer_global_new);  int snd_timer_global_free(struct snd_timer *timer)  {  	return snd_timer_free(timer);  } +EXPORT_SYMBOL(snd_timer_global_free);  int snd_timer_global_register(struct snd_timer *timer)  { @@ -1007,6 +1019,7 @@ int snd_timer_global_register(struct snd_timer *timer)  	dev.device_data = timer;  	return snd_timer_dev_register(&dev);  } +EXPORT_SYMBOL(snd_timer_global_register);  /*   *  System timer @@ -1327,6 +1340,33 @@ static void snd_timer_user_tinterrupt(struct snd_timer_instance *timeri,  	wake_up(&tu->qchange_sleep);  } +static int realloc_user_queue(struct snd_timer_user *tu, int size) +{ +	struct snd_timer_read *queue = NULL; +	struct snd_timer_tread *tqueue = NULL; + +	if (tu->tread) { +		tqueue = kcalloc(size, sizeof(*tqueue), GFP_KERNEL); +		if (!tqueue) +			return -ENOMEM; +	} else { +		queue = kcalloc(size, sizeof(*queue), GFP_KERNEL); +		if (!queue) +			return -ENOMEM; +	} + +	spin_lock_irq(&tu->qlock); +	kfree(tu->queue); +	kfree(tu->tqueue); +	tu->queue_size = size; +	tu->queue = queue; +	tu->tqueue = tqueue; +	tu->qhead = tu->qtail = tu->qused = 0; +	spin_unlock_irq(&tu->qlock); + +	return 0; +} +  static int snd_timer_user_open(struct inode *inode, struct file *file)  {  	struct snd_timer_user *tu; @@ -1343,10 +1383,7 @@ static int snd_timer_user_open(struct inode *inode, struct file *file)  	init_waitqueue_head(&tu->qchange_sleep);  	mutex_init(&tu->ioctl_lock);  	tu->ticks = 1; -	tu->queue_size = 128; -	tu->queue = kmalloc(tu->queue_size * sizeof(struct snd_timer_read), -			    GFP_KERNEL); -	if (tu->queue == NULL) { +	if (realloc_user_queue(tu, 128) < 0) {  		kfree(tu);  		return -ENOMEM;  	} @@ -1618,33 +1655,12 @@ static int snd_timer_user_tselect(struct file *file,  	if (err < 0)  		goto __err; -	kfree(tu->queue); -	tu->queue = NULL; -	kfree(tu->tqueue); -	tu->tqueue = NULL; -	if (tu->tread) { -		tu->tqueue = kmalloc(tu->queue_size * sizeof(struct snd_timer_tread), -				     GFP_KERNEL); -		if (tu->tqueue == NULL) -			err = -ENOMEM; -	} else { -		tu->queue = kmalloc(tu->queue_size * sizeof(struct snd_timer_read), -				    GFP_KERNEL); -		if (tu->queue == NULL) -			err = -ENOMEM; -	} - -      	if (err < 0) { -		snd_timer_close(tu->timeri); -      		tu->timeri = NULL; -      	} else { -		tu->timeri->flags |= SNDRV_TIMER_IFLG_FAST; -		tu->timeri->callback = tu->tread +	tu->timeri->flags |= SNDRV_TIMER_IFLG_FAST; +	tu->timeri->callback = tu->tread  			? snd_timer_user_tinterrupt : snd_timer_user_interrupt; -		tu->timeri->ccallback = snd_timer_user_ccallback; -		tu->timeri->callback_data = (void *)tu; -		tu->timeri->disconnect = snd_timer_user_disconnect; -	} +	tu->timeri->ccallback = snd_timer_user_ccallback; +	tu->timeri->callback_data = (void *)tu; +	tu->timeri->disconnect = snd_timer_user_disconnect;        __err:  	return err; @@ -1686,8 +1702,6 @@ static int snd_timer_user_params(struct file *file,  	struct snd_timer_user *tu;  	struct snd_timer_params params;  	struct snd_timer *t; -	struct snd_timer_read *tr; -	struct snd_timer_tread *ttr;  	int err;  	tu = file->private_data; @@ -1750,24 +1764,11 @@ static int snd_timer_user_params(struct file *file,  	spin_unlock_irq(&t->lock);  	if (params.queue_size > 0 &&  	    (unsigned int)tu->queue_size != params.queue_size) { -		if (tu->tread) { -			ttr = kmalloc(params.queue_size * sizeof(*ttr), -				      GFP_KERNEL); -			if (ttr) { -				kfree(tu->tqueue); -				tu->queue_size = params.queue_size; -				tu->tqueue = ttr; -			} -		} else { -			tr = kmalloc(params.queue_size * sizeof(*tr), -				     GFP_KERNEL); -			if (tr) { -				kfree(tu->queue); -				tu->queue_size = params.queue_size; -				tu->queue = tr; -			} -		} +		err = realloc_user_queue(tu, params.queue_size); +		if (err < 0) +			goto _end;  	} +	spin_lock_irq(&tu->qlock);  	tu->qhead = tu->qtail = tu->qused = 0;  	if (tu->timeri->flags & SNDRV_TIMER_IFLG_EARLY_EVENT) {  		if (tu->tread) { @@ -1788,6 +1789,7 @@ static int snd_timer_user_params(struct file *file,  	}  	tu->filter = params.filter;  	tu->ticks = params.ticks; +	spin_unlock_irq(&tu->qlock);  	err = 0;   _end:  	if (copy_to_user(_params, ¶ms, sizeof(params))) @@ -1890,13 +1892,19 @@ static long __snd_timer_user_ioctl(struct file *file, unsigned int cmd,  		return snd_timer_user_next_device(argp);  	case SNDRV_TIMER_IOCTL_TREAD:  	{ -		int xarg; +		int xarg, old_tread;  		if (tu->timeri)	/* too late */  			return -EBUSY;  		if (get_user(xarg, p))  			return -EFAULT; +		old_tread = tu->tread;  		tu->tread = xarg ? 1 : 0; +		if (tu->tread != old_tread && +		    realloc_user_queue(tu, tu->queue_size) < 0) { +			tu->tread = old_tread; +			return -ENOMEM; +		}  		return 0;  	}  	case SNDRV_TIMER_IOCTL_GINFO: @@ -1959,10 +1967,11 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer,  	tu = file->private_data;  	unit = tu->tread ? sizeof(struct snd_timer_tread) : sizeof(struct snd_timer_read); +	mutex_lock(&tu->ioctl_lock);  	spin_lock_irq(&tu->qlock);  	while ((long)count - result >= unit) {  		while (!tu->qused) { -			wait_queue_t wait; +			wait_queue_entry_t wait;  			if ((file->f_flags & O_NONBLOCK) != 0 || result > 0) {  				err = -EAGAIN; @@ -1974,7 +1983,9 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer,  			add_wait_queue(&tu->qchange_sleep, &wait);  			spin_unlock_irq(&tu->qlock); +			mutex_unlock(&tu->ioctl_lock);  			schedule(); +			mutex_lock(&tu->ioctl_lock);  			spin_lock_irq(&tu->qlock);  			remove_wait_queue(&tu->qchange_sleep, &wait); @@ -1994,7 +2005,6 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer,  		tu->qused--;  		spin_unlock_irq(&tu->qlock); -		mutex_lock(&tu->ioctl_lock);  		if (tu->tread) {  			if (copy_to_user(buffer, &tu->tqueue[qhead],  					 sizeof(struct snd_timer_tread))) @@ -2004,7 +2014,6 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer,  					 sizeof(struct snd_timer_read)))  				err = -EFAULT;  		} -		mutex_unlock(&tu->ioctl_lock);  		spin_lock_irq(&tu->qlock);  		if (err < 0) @@ -2014,6 +2023,7 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer,  	}   _error:  	spin_unlock_irq(&tu->qlock); +	mutex_unlock(&tu->ioctl_lock);  	return result > 0 ? result : err;  } @@ -2027,10 +2037,12 @@ static unsigned int snd_timer_user_poll(struct file *file, poll_table * wait)          poll_wait(file, &tu->qchange_sleep, wait);  	mask = 0; +	spin_lock_irq(&tu->qlock);  	if (tu->qused)  		mask |= POLLIN | POLLRDNORM;  	if (tu->disconnected)  		mask |= POLLERR; +	spin_unlock_irq(&tu->qlock);  	return mask;  } @@ -2114,17 +2126,3 @@ static void __exit alsa_timer_exit(void)  module_init(alsa_timer_init)  module_exit(alsa_timer_exit) - -EXPORT_SYMBOL(snd_timer_open); -EXPORT_SYMBOL(snd_timer_close); -EXPORT_SYMBOL(snd_timer_resolution); -EXPORT_SYMBOL(snd_timer_start); -EXPORT_SYMBOL(snd_timer_stop); -EXPORT_SYMBOL(snd_timer_continue); -EXPORT_SYMBOL(snd_timer_pause); -EXPORT_SYMBOL(snd_timer_new); -EXPORT_SYMBOL(snd_timer_notify); -EXPORT_SYMBOL(snd_timer_global_new); -EXPORT_SYMBOL(snd_timer_global_free); -EXPORT_SYMBOL(snd_timer_global_register); -EXPORT_SYMBOL(snd_timer_interrupt); |