brintos

brintos / linux-shallow public Read only

0
0
Text · 29.7 KiB · bdf1d78 Raw
1168 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 *  compress_core.c - compress offload core4 *5 *  Copyright (C) 2011 Intel Corporation6 *  Authors:	Vinod Koul <vinod.koul@linux.intel.com>7 *		Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>8 *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~9 *10 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~11 */12#define FORMAT(fmt) "%s: %d: " fmt, __func__, __LINE__13#define pr_fmt(fmt) KBUILD_MODNAME ": " FORMAT(fmt)14 15#include <linux/file.h>16#include <linux/fs.h>17#include <linux/list.h>18#include <linux/math64.h>19#include <linux/mm.h>20#include <linux/mutex.h>21#include <linux/poll.h>22#include <linux/slab.h>23#include <linux/sched.h>24#include <linux/types.h>25#include <linux/uio.h>26#include <linux/uaccess.h>27#include <linux/module.h>28#include <linux/compat.h>29#include <sound/core.h>30#include <sound/initval.h>31#include <sound/info.h>32#include <sound/compress_params.h>33#include <sound/compress_offload.h>34#include <sound/compress_driver.h>35 36/* struct snd_compr_codec_caps overflows the ioctl bit size for some37 * architectures, so we need to disable the relevant ioctls.38 */39#if _IOC_SIZEBITS < 1440#define COMPR_CODEC_CAPS_OVERFLOW41#endif42 43/* TODO:44 * - add substream support for multiple devices in case of45 *	SND_DYNAMIC_MINORS is not used46 * - Multiple node representation47 *	driver should be able to register multiple nodes48 */49 50struct snd_compr_file {51	unsigned long caps;52	struct snd_compr_stream stream;53};54 55static void error_delayed_work(struct work_struct *work);56 57/*58 * a note on stream states used:59 * we use following states in the compressed core60 * SNDRV_PCM_STATE_OPEN: When stream has been opened.61 * SNDRV_PCM_STATE_SETUP: When stream has been initialized. This is done by62 *	calling SNDRV_COMPRESS_SET_PARAMS. Running streams will come to this63 *	state at stop by calling SNDRV_COMPRESS_STOP, or at end of drain.64 * SNDRV_PCM_STATE_PREPARED: When a stream has been written to (for65 *	playback only). User after setting up stream writes the data buffer66 *	before starting the stream.67 * SNDRV_PCM_STATE_RUNNING: When stream has been started and is68 *	decoding/encoding and rendering/capturing data.69 * SNDRV_PCM_STATE_DRAINING: When stream is draining current data. This is done70 *	by calling SNDRV_COMPRESS_DRAIN.71 * SNDRV_PCM_STATE_PAUSED: When stream is paused. This is done by calling72 *	SNDRV_COMPRESS_PAUSE. It can be stopped or resumed by calling73 *	SNDRV_COMPRESS_STOP or SNDRV_COMPRESS_RESUME respectively.74 */75static int snd_compr_open(struct inode *inode, struct file *f)76{77	struct snd_compr *compr;78	struct snd_compr_file *data;79	struct snd_compr_runtime *runtime;80	enum snd_compr_direction dirn;81	int maj = imajor(inode);82	int ret;83 84	if ((f->f_flags & O_ACCMODE) == O_WRONLY)85		dirn = SND_COMPRESS_PLAYBACK;86	else if ((f->f_flags & O_ACCMODE) == O_RDONLY)87		dirn = SND_COMPRESS_CAPTURE;88	else89		return -EINVAL;90 91	if (maj == snd_major)92		compr = snd_lookup_minor_data(iminor(inode),93					SNDRV_DEVICE_TYPE_COMPRESS);94	else95		return -EBADFD;96 97	if (compr == NULL) {98		pr_err("no device data!!!\n");99		return -ENODEV;100	}101 102	if (dirn != compr->direction) {103		pr_err("this device doesn't support this direction\n");104		snd_card_unref(compr->card);105		return -EINVAL;106	}107 108	data = kzalloc(sizeof(*data), GFP_KERNEL);109	if (!data) {110		snd_card_unref(compr->card);111		return -ENOMEM;112	}113 114	INIT_DELAYED_WORK(&data->stream.error_work, error_delayed_work);115 116	data->stream.ops = compr->ops;117	data->stream.direction = dirn;118	data->stream.private_data = compr->private_data;119	data->stream.device = compr;120	runtime = kzalloc(sizeof(*runtime), GFP_KERNEL);121	if (!runtime) {122		kfree(data);123		snd_card_unref(compr->card);124		return -ENOMEM;125	}126	runtime->state = SNDRV_PCM_STATE_OPEN;127	init_waitqueue_head(&runtime->sleep);128	data->stream.runtime = runtime;129	f->private_data = (void *)data;130	scoped_guard(mutex, &compr->lock)131		ret = compr->ops->open(&data->stream);132	if (ret) {133		kfree(runtime);134		kfree(data);135	}136	snd_card_unref(compr->card);137	return ret;138}139 140static int snd_compr_free(struct inode *inode, struct file *f)141{142	struct snd_compr_file *data = f->private_data;143	struct snd_compr_runtime *runtime = data->stream.runtime;144 145	cancel_delayed_work_sync(&data->stream.error_work);146 147	switch (runtime->state) {148	case SNDRV_PCM_STATE_RUNNING:149	case SNDRV_PCM_STATE_DRAINING:150	case SNDRV_PCM_STATE_PAUSED:151		data->stream.ops->trigger(&data->stream, SNDRV_PCM_TRIGGER_STOP);152		break;153	default:154		break;155	}156 157	data->stream.ops->free(&data->stream);158	if (!data->stream.runtime->dma_buffer_p)159		kfree(data->stream.runtime->buffer);160	kfree(data->stream.runtime);161	kfree(data);162	return 0;163}164 165static int snd_compr_update_tstamp(struct snd_compr_stream *stream,166		struct snd_compr_tstamp *tstamp)167{168	if (!stream->ops->pointer)169		return -ENOTSUPP;170	stream->ops->pointer(stream, tstamp);171	pr_debug("dsp consumed till %d total %d bytes\n",172		tstamp->byte_offset, tstamp->copied_total);173	if (stream->direction == SND_COMPRESS_PLAYBACK)174		stream->runtime->total_bytes_transferred = tstamp->copied_total;175	else176		stream->runtime->total_bytes_available = tstamp->copied_total;177	return 0;178}179 180static size_t snd_compr_calc_avail(struct snd_compr_stream *stream,181		struct snd_compr_avail *avail)182{183	memset(avail, 0, sizeof(*avail));184	snd_compr_update_tstamp(stream, &avail->tstamp);185	/* Still need to return avail even if tstamp can't be filled in */186 187	if (stream->runtime->total_bytes_available == 0 &&188			stream->runtime->state == SNDRV_PCM_STATE_SETUP &&189			stream->direction == SND_COMPRESS_PLAYBACK) {190		pr_debug("detected init and someone forgot to do a write\n");191		return stream->runtime->buffer_size;192	}193	pr_debug("app wrote %lld, DSP consumed %lld\n",194			stream->runtime->total_bytes_available,195			stream->runtime->total_bytes_transferred);196	if (stream->runtime->total_bytes_available ==197				stream->runtime->total_bytes_transferred) {198		if (stream->direction == SND_COMPRESS_PLAYBACK) {199			pr_debug("both pointers are same, returning full avail\n");200			return stream->runtime->buffer_size;201		} else {202			pr_debug("both pointers are same, returning no avail\n");203			return 0;204		}205	}206 207	avail->avail = stream->runtime->total_bytes_available -208			stream->runtime->total_bytes_transferred;209	if (stream->direction == SND_COMPRESS_PLAYBACK)210		avail->avail = stream->runtime->buffer_size - avail->avail;211 212	pr_debug("ret avail as %lld\n", avail->avail);213	return avail->avail;214}215 216static inline size_t snd_compr_get_avail(struct snd_compr_stream *stream)217{218	struct snd_compr_avail avail;219 220	return snd_compr_calc_avail(stream, &avail);221}222 223static int224snd_compr_ioctl_avail(struct snd_compr_stream *stream, unsigned long arg)225{226	struct snd_compr_avail ioctl_avail;227	size_t avail;228 229	avail = snd_compr_calc_avail(stream, &ioctl_avail);230	ioctl_avail.avail = avail;231 232	switch (stream->runtime->state) {233	case SNDRV_PCM_STATE_OPEN:234		return -EBADFD;235	case SNDRV_PCM_STATE_XRUN:236		return -EPIPE;237	default:238		break;239	}240 241	if (copy_to_user((__u64 __user *)arg,242				&ioctl_avail, sizeof(ioctl_avail)))243		return -EFAULT;244	return 0;245}246 247static int snd_compr_write_data(struct snd_compr_stream *stream,248	       const char __user *buf, size_t count)249{250	void *dstn;251	size_t copy;252	struct snd_compr_runtime *runtime = stream->runtime;253	/* 64-bit Modulus */254	u64 app_pointer = div64_u64(runtime->total_bytes_available,255				    runtime->buffer_size);256	app_pointer = runtime->total_bytes_available -257		      (app_pointer * runtime->buffer_size);258 259	dstn = runtime->buffer + app_pointer;260	pr_debug("copying %ld at %lld\n",261			(unsigned long)count, app_pointer);262	if (count < runtime->buffer_size - app_pointer) {263		if (copy_from_user(dstn, buf, count))264			return -EFAULT;265	} else {266		copy = runtime->buffer_size - app_pointer;267		if (copy_from_user(dstn, buf, copy))268			return -EFAULT;269		if (copy_from_user(runtime->buffer, buf + copy, count - copy))270			return -EFAULT;271	}272	/* if DSP cares, let it know data has been written */273	if (stream->ops->ack)274		stream->ops->ack(stream, count);275	return count;276}277 278static ssize_t snd_compr_write(struct file *f, const char __user *buf,279		size_t count, loff_t *offset)280{281	struct snd_compr_file *data = f->private_data;282	struct snd_compr_stream *stream;283	size_t avail;284	int retval;285 286	if (snd_BUG_ON(!data))287		return -EFAULT;288 289	stream = &data->stream;290	guard(mutex)(&stream->device->lock);291	/* write is allowed when stream is running or has been setup */292	switch (stream->runtime->state) {293	case SNDRV_PCM_STATE_SETUP:294	case SNDRV_PCM_STATE_PREPARED:295	case SNDRV_PCM_STATE_RUNNING:296		break;297	default:298		return -EBADFD;299	}300 301	avail = snd_compr_get_avail(stream);302	pr_debug("avail returned %ld\n", (unsigned long)avail);303	/* calculate how much we can write to buffer */304	if (avail > count)305		avail = count;306 307	if (stream->ops->copy) {308		char __user* cbuf = (char __user*)buf;309		retval = stream->ops->copy(stream, cbuf, avail);310	} else {311		retval = snd_compr_write_data(stream, buf, avail);312	}313	if (retval > 0)314		stream->runtime->total_bytes_available += retval;315 316	/* while initiating the stream, write should be called before START317	 * call, so in setup move state */318	if (stream->runtime->state == SNDRV_PCM_STATE_SETUP) {319		stream->runtime->state = SNDRV_PCM_STATE_PREPARED;320		pr_debug("stream prepared, Houston we are good to go\n");321	}322 323	return retval;324}325 326 327static ssize_t snd_compr_read(struct file *f, char __user *buf,328		size_t count, loff_t *offset)329{330	struct snd_compr_file *data = f->private_data;331	struct snd_compr_stream *stream;332	size_t avail;333	int retval;334 335	if (snd_BUG_ON(!data))336		return -EFAULT;337 338	stream = &data->stream;339	guard(mutex)(&stream->device->lock);340 341	/* read is allowed when stream is running, paused, draining and setup342	 * (yes setup is state which we transition to after stop, so if user343	 * wants to read data after stop we allow that)344	 */345	switch (stream->runtime->state) {346	case SNDRV_PCM_STATE_OPEN:347	case SNDRV_PCM_STATE_PREPARED:348	case SNDRV_PCM_STATE_SUSPENDED:349	case SNDRV_PCM_STATE_DISCONNECTED:350		return -EBADFD;351	case SNDRV_PCM_STATE_XRUN:352		return -EPIPE;353	}354 355	avail = snd_compr_get_avail(stream);356	pr_debug("avail returned %ld\n", (unsigned long)avail);357	/* calculate how much we can read from buffer */358	if (avail > count)359		avail = count;360 361	if (stream->ops->copy)362		retval = stream->ops->copy(stream, buf, avail);363	else364		return -ENXIO;365	if (retval > 0)366		stream->runtime->total_bytes_transferred += retval;367 368	return retval;369}370 371static int snd_compr_mmap(struct file *f, struct vm_area_struct *vma)372{373	return -ENXIO;374}375 376static __poll_t snd_compr_get_poll(struct snd_compr_stream *stream)377{378	if (stream->direction == SND_COMPRESS_PLAYBACK)379		return EPOLLOUT | EPOLLWRNORM;380	else381		return EPOLLIN | EPOLLRDNORM;382}383 384static __poll_t snd_compr_poll(struct file *f, poll_table *wait)385{386	struct snd_compr_file *data = f->private_data;387	struct snd_compr_stream *stream;388	size_t avail;389	__poll_t retval = 0;390 391	if (snd_BUG_ON(!data))392		return EPOLLERR;393 394	stream = &data->stream;395 396	guard(mutex)(&stream->device->lock);397 398	switch (stream->runtime->state) {399	case SNDRV_PCM_STATE_OPEN:400	case SNDRV_PCM_STATE_XRUN:401		return snd_compr_get_poll(stream) | EPOLLERR;402	default:403		break;404	}405 406	poll_wait(f, &stream->runtime->sleep, wait);407 408	avail = snd_compr_get_avail(stream);409	pr_debug("avail is %ld\n", (unsigned long)avail);410	/* check if we have at least one fragment to fill */411	switch (stream->runtime->state) {412	case SNDRV_PCM_STATE_DRAINING:413		/* stream has been woken up after drain is complete414		 * draining done so set stream state to stopped415		 */416		retval = snd_compr_get_poll(stream);417		stream->runtime->state = SNDRV_PCM_STATE_SETUP;418		break;419	case SNDRV_PCM_STATE_RUNNING:420	case SNDRV_PCM_STATE_PREPARED:421	case SNDRV_PCM_STATE_PAUSED:422		if (avail >= stream->runtime->fragment_size)423			retval = snd_compr_get_poll(stream);424		break;425	default:426		return snd_compr_get_poll(stream) | EPOLLERR;427	}428 429	return retval;430}431 432static int433snd_compr_get_caps(struct snd_compr_stream *stream, unsigned long arg)434{435	int retval;436	struct snd_compr_caps caps;437 438	if (!stream->ops->get_caps)439		return -ENXIO;440 441	memset(&caps, 0, sizeof(caps));442	retval = stream->ops->get_caps(stream, &caps);443	if (retval)444		goto out;445	if (copy_to_user((void __user *)arg, &caps, sizeof(caps)))446		retval = -EFAULT;447out:448	return retval;449}450 451#ifndef COMPR_CODEC_CAPS_OVERFLOW452static int453snd_compr_get_codec_caps(struct snd_compr_stream *stream, unsigned long arg)454{455	int retval;456	struct snd_compr_codec_caps *caps __free(kfree) = NULL;457 458	if (!stream->ops->get_codec_caps)459		return -ENXIO;460 461	caps = kzalloc(sizeof(*caps), GFP_KERNEL);462	if (!caps)463		return -ENOMEM;464 465	retval = stream->ops->get_codec_caps(stream, caps);466	if (retval)467		return retval;468	if (copy_to_user((void __user *)arg, caps, sizeof(*caps)))469		return -EFAULT;470	return retval;471}472#endif /* !COMPR_CODEC_CAPS_OVERFLOW */473 474int snd_compr_malloc_pages(struct snd_compr_stream *stream, size_t size)475{476	struct snd_dma_buffer *dmab;477	int ret;478 479	if (snd_BUG_ON(!(stream) || !(stream)->runtime))480		return -EINVAL;481	dmab = kzalloc(sizeof(*dmab), GFP_KERNEL);482	if (!dmab)483		return -ENOMEM;484	dmab->dev = stream->dma_buffer.dev;485	ret = snd_dma_alloc_pages(dmab->dev.type, dmab->dev.dev, size, dmab);486	if (ret < 0) {487		kfree(dmab);488		return ret;489	}490 491	snd_compr_set_runtime_buffer(stream, dmab);492	stream->runtime->dma_bytes = size;493	return 1;494}495EXPORT_SYMBOL(snd_compr_malloc_pages);496 497int snd_compr_free_pages(struct snd_compr_stream *stream)498{499	struct snd_compr_runtime *runtime;500 501	if (snd_BUG_ON(!(stream) || !(stream)->runtime))502		return -EINVAL;503	runtime = stream->runtime;504	if (runtime->dma_area == NULL)505		return 0;506	if (runtime->dma_buffer_p != &stream->dma_buffer) {507		/* It's a newly allocated buffer. Release it now. */508		snd_dma_free_pages(runtime->dma_buffer_p);509		kfree(runtime->dma_buffer_p);510	}511 512	snd_compr_set_runtime_buffer(stream, NULL);513	return 0;514}515EXPORT_SYMBOL(snd_compr_free_pages);516 517/* revisit this with snd_pcm_preallocate_xxx */518static int snd_compr_allocate_buffer(struct snd_compr_stream *stream,519		struct snd_compr_params *params)520{521	unsigned int buffer_size;522	void *buffer = NULL;523 524	buffer_size = params->buffer.fragment_size * params->buffer.fragments;525	if (stream->ops->copy) {526		buffer = NULL;527		/* if copy is defined the driver will be required to copy528		 * the data from core529		 */530	} else {531		if (stream->runtime->dma_buffer_p) {532 533			if (buffer_size > stream->runtime->dma_buffer_p->bytes)534				dev_err(stream->device->dev,535						"Not enough DMA buffer");536			else537				buffer = stream->runtime->dma_buffer_p->area;538 539		} else {540			buffer = kmalloc(buffer_size, GFP_KERNEL);541		}542 543		if (!buffer)544			return -ENOMEM;545	}546	stream->runtime->fragment_size = params->buffer.fragment_size;547	stream->runtime->fragments = params->buffer.fragments;548	stream->runtime->buffer = buffer;549	stream->runtime->buffer_size = buffer_size;550	return 0;551}552 553static int snd_compress_check_input(struct snd_compr_params *params)554{555	/* first let's check the buffer parameter's */556	if (params->buffer.fragment_size == 0 ||557	    params->buffer.fragments > U32_MAX / params->buffer.fragment_size ||558	    params->buffer.fragments == 0)559		return -EINVAL;560 561	/* now codec parameters */562	if (params->codec.id == 0 || params->codec.id > SND_AUDIOCODEC_MAX)563		return -EINVAL;564 565	if (params->codec.ch_in == 0 || params->codec.ch_out == 0)566		return -EINVAL;567 568	return 0;569}570 571static int572snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg)573{574	struct snd_compr_params *params __free(kfree) = NULL;575	int retval;576 577	if (stream->runtime->state == SNDRV_PCM_STATE_OPEN || stream->next_track) {578		/*579		 * we should allow parameter change only when stream has been580		 * opened not in other cases581		 */582		params = memdup_user((void __user *)arg, sizeof(*params));583		if (IS_ERR(params))584			return PTR_ERR(params);585 586		retval = snd_compress_check_input(params);587		if (retval)588			return retval;589 590		retval = snd_compr_allocate_buffer(stream, params);591		if (retval)592			return -ENOMEM;593 594		retval = stream->ops->set_params(stream, params);595		if (retval)596			return retval;597 598		if (stream->next_track)599			return retval;600 601		stream->metadata_set = false;602		stream->next_track = false;603 604		stream->runtime->state = SNDRV_PCM_STATE_SETUP;605	} else {606		return -EPERM;607	}608	return retval;609}610 611static int612snd_compr_get_params(struct snd_compr_stream *stream, unsigned long arg)613{614	struct snd_codec *params __free(kfree) = NULL;615	int retval;616 617	if (!stream->ops->get_params)618		return -EBADFD;619 620	params = kzalloc(sizeof(*params), GFP_KERNEL);621	if (!params)622		return -ENOMEM;623	retval = stream->ops->get_params(stream, params);624	if (retval)625		return retval;626	if (copy_to_user((char __user *)arg, params, sizeof(*params)))627		return -EFAULT;628	return retval;629}630 631static int632snd_compr_get_metadata(struct snd_compr_stream *stream, unsigned long arg)633{634	struct snd_compr_metadata metadata;635	int retval;636 637	if (!stream->ops->get_metadata)638		return -ENXIO;639 640	if (copy_from_user(&metadata, (void __user *)arg, sizeof(metadata)))641		return -EFAULT;642 643	retval = stream->ops->get_metadata(stream, &metadata);644	if (retval != 0)645		return retval;646 647	if (copy_to_user((void __user *)arg, &metadata, sizeof(metadata)))648		return -EFAULT;649 650	return 0;651}652 653static int654snd_compr_set_metadata(struct snd_compr_stream *stream, unsigned long arg)655{656	struct snd_compr_metadata metadata;657	int retval;658 659	if (!stream->ops->set_metadata)660		return -ENXIO;661	/*662	* we should allow parameter change only when stream has been663	* opened not in other cases664	*/665	if (copy_from_user(&metadata, (void __user *)arg, sizeof(metadata)))666		return -EFAULT;667 668	retval = stream->ops->set_metadata(stream, &metadata);669	stream->metadata_set = true;670 671	return retval;672}673 674static inline int675snd_compr_tstamp(struct snd_compr_stream *stream, unsigned long arg)676{677	struct snd_compr_tstamp tstamp = {0};678	int ret;679 680	ret = snd_compr_update_tstamp(stream, &tstamp);681	if (ret == 0)682		ret = copy_to_user((struct snd_compr_tstamp __user *)arg,683			&tstamp, sizeof(tstamp)) ? -EFAULT : 0;684	return ret;685}686 687static int snd_compr_pause(struct snd_compr_stream *stream)688{689	int retval;690 691	switch (stream->runtime->state) {692	case SNDRV_PCM_STATE_RUNNING:693		retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_PAUSE_PUSH);694		if (!retval)695			stream->runtime->state = SNDRV_PCM_STATE_PAUSED;696		break;697	case SNDRV_PCM_STATE_DRAINING:698		if (!stream->device->use_pause_in_draining)699			return -EPERM;700		retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_PAUSE_PUSH);701		if (!retval)702			stream->pause_in_draining = true;703		break;704	default:705		return -EPERM;706	}707	return retval;708}709 710static int snd_compr_resume(struct snd_compr_stream *stream)711{712	int retval;713 714	switch (stream->runtime->state) {715	case SNDRV_PCM_STATE_PAUSED:716		retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_PAUSE_RELEASE);717		if (!retval)718			stream->runtime->state = SNDRV_PCM_STATE_RUNNING;719		break;720	case SNDRV_PCM_STATE_DRAINING:721		if (!stream->pause_in_draining)722			return -EPERM;723		retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_PAUSE_RELEASE);724		if (!retval)725			stream->pause_in_draining = false;726		break;727	default:728		return -EPERM;729	}730	return retval;731}732 733static int snd_compr_start(struct snd_compr_stream *stream)734{735	int retval;736 737	switch (stream->runtime->state) {738	case SNDRV_PCM_STATE_SETUP:739		if (stream->direction != SND_COMPRESS_CAPTURE)740			return -EPERM;741		break;742	case SNDRV_PCM_STATE_PREPARED:743		break;744	default:745		return -EPERM;746	}747 748	retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_START);749	if (!retval)750		stream->runtime->state = SNDRV_PCM_STATE_RUNNING;751	return retval;752}753 754static int snd_compr_stop(struct snd_compr_stream *stream)755{756	int retval;757 758	switch (stream->runtime->state) {759	case SNDRV_PCM_STATE_OPEN:760	case SNDRV_PCM_STATE_SETUP:761	case SNDRV_PCM_STATE_PREPARED:762		return -EPERM;763	default:764		break;765	}766 767	retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_STOP);768	if (!retval) {769		/* clear flags and stop any drain wait */770		stream->partial_drain = false;771		stream->metadata_set = false;772		stream->pause_in_draining = false;773		snd_compr_drain_notify(stream);774		stream->runtime->total_bytes_available = 0;775		stream->runtime->total_bytes_transferred = 0;776	}777	return retval;778}779 780static void error_delayed_work(struct work_struct *work)781{782	struct snd_compr_stream *stream;783 784	stream = container_of(work, struct snd_compr_stream, error_work.work);785 786	guard(mutex)(&stream->device->lock);787 788	stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_STOP);789	wake_up(&stream->runtime->sleep);790}791 792/**793 * snd_compr_stop_error: Report a fatal error on a stream794 * @stream: pointer to stream795 * @state: state to transition the stream to796 *797 * Stop the stream and set its state.798 *799 * Should be called with compressed device lock held.800 *801 * Return: zero if successful, or a negative error code802 */803int snd_compr_stop_error(struct snd_compr_stream *stream,804			 snd_pcm_state_t state)805{806	if (stream->runtime->state == state)807		return 0;808 809	stream->runtime->state = state;810 811	pr_debug("Changing state to: %d\n", state);812 813	queue_delayed_work(system_power_efficient_wq, &stream->error_work, 0);814 815	return 0;816}817EXPORT_SYMBOL_GPL(snd_compr_stop_error);818 819static int snd_compress_wait_for_drain(struct snd_compr_stream *stream)820{821	int ret;822 823	/*824	 * We are called with lock held. So drop the lock while we wait for825	 * drain complete notification from the driver826	 *827	 * It is expected that driver will notify the drain completion and then828	 * stream will be moved to SETUP state, even if draining resulted in an829	 * error. We can trigger next track after this.830	 */831	stream->runtime->state = SNDRV_PCM_STATE_DRAINING;832	mutex_unlock(&stream->device->lock);833 834	/* we wait for drain to complete here, drain can return when835	 * interruption occurred, wait returned error or success.836	 * For the first two cases we don't do anything different here and837	 * return after waking up838	 */839 840	ret = wait_event_interruptible(stream->runtime->sleep,841			(stream->runtime->state != SNDRV_PCM_STATE_DRAINING));842	if (ret == -ERESTARTSYS)843		pr_debug("wait aborted by a signal\n");844	else if (ret)845		pr_debug("wait for drain failed with %d\n", ret);846 847 848	wake_up(&stream->runtime->sleep);849	mutex_lock(&stream->device->lock);850 851	return ret;852}853 854static int snd_compr_drain(struct snd_compr_stream *stream)855{856	int retval;857 858	switch (stream->runtime->state) {859	case SNDRV_PCM_STATE_OPEN:860	case SNDRV_PCM_STATE_SETUP:861	case SNDRV_PCM_STATE_PREPARED:862	case SNDRV_PCM_STATE_PAUSED:863		return -EPERM;864	case SNDRV_PCM_STATE_XRUN:865		return -EPIPE;866	default:867		break;868	}869 870	retval = stream->ops->trigger(stream, SND_COMPR_TRIGGER_DRAIN);871	if (retval) {872		pr_debug("SND_COMPR_TRIGGER_DRAIN failed %d\n", retval);873		wake_up(&stream->runtime->sleep);874		return retval;875	}876 877	return snd_compress_wait_for_drain(stream);878}879 880static int snd_compr_next_track(struct snd_compr_stream *stream)881{882	int retval;883 884	/* only a running stream can transition to next track */885	if (stream->runtime->state != SNDRV_PCM_STATE_RUNNING)886		return -EPERM;887 888	/* next track doesn't have any meaning for capture streams */889	if (stream->direction == SND_COMPRESS_CAPTURE)890		return -EPERM;891 892	/* you can signal next track if this is intended to be a gapless stream893	 * and current track metadata is set894	 */895	if (stream->metadata_set == false)896		return -EPERM;897 898	retval = stream->ops->trigger(stream, SND_COMPR_TRIGGER_NEXT_TRACK);899	if (retval != 0)900		return retval;901	stream->metadata_set = false;902	stream->next_track = true;903	return 0;904}905 906static int snd_compr_partial_drain(struct snd_compr_stream *stream)907{908	int retval;909 910	switch (stream->runtime->state) {911	case SNDRV_PCM_STATE_OPEN:912	case SNDRV_PCM_STATE_SETUP:913	case SNDRV_PCM_STATE_PREPARED:914	case SNDRV_PCM_STATE_PAUSED:915		return -EPERM;916	case SNDRV_PCM_STATE_XRUN:917		return -EPIPE;918	default:919		break;920	}921 922	/* partial drain doesn't have any meaning for capture streams */923	if (stream->direction == SND_COMPRESS_CAPTURE)924		return -EPERM;925 926	/* stream can be drained only when next track has been signalled */927	if (stream->next_track == false)928		return -EPERM;929 930	stream->partial_drain = true;931	retval = stream->ops->trigger(stream, SND_COMPR_TRIGGER_PARTIAL_DRAIN);932	if (retval) {933		pr_debug("Partial drain returned failure\n");934		wake_up(&stream->runtime->sleep);935		return retval;936	}937 938	stream->next_track = false;939	return snd_compress_wait_for_drain(stream);940}941 942static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg)943{944	struct snd_compr_file *data = f->private_data;945	struct snd_compr_stream *stream;946 947	if (snd_BUG_ON(!data))948		return -EFAULT;949 950	stream = &data->stream;951 952	guard(mutex)(&stream->device->lock);953	switch (_IOC_NR(cmd)) {954	case _IOC_NR(SNDRV_COMPRESS_IOCTL_VERSION):955		return put_user(SNDRV_COMPRESS_VERSION,956				(int __user *)arg) ? -EFAULT : 0;957	case _IOC_NR(SNDRV_COMPRESS_GET_CAPS):958		return snd_compr_get_caps(stream, arg);959#ifndef COMPR_CODEC_CAPS_OVERFLOW960	case _IOC_NR(SNDRV_COMPRESS_GET_CODEC_CAPS):961		return snd_compr_get_codec_caps(stream, arg);962#endif963	case _IOC_NR(SNDRV_COMPRESS_SET_PARAMS):964		return snd_compr_set_params(stream, arg);965	case _IOC_NR(SNDRV_COMPRESS_GET_PARAMS):966		return snd_compr_get_params(stream, arg);967	case _IOC_NR(SNDRV_COMPRESS_SET_METADATA):968		return snd_compr_set_metadata(stream, arg);969	case _IOC_NR(SNDRV_COMPRESS_GET_METADATA):970		return snd_compr_get_metadata(stream, arg);971	case _IOC_NR(SNDRV_COMPRESS_TSTAMP):972		return snd_compr_tstamp(stream, arg);973	case _IOC_NR(SNDRV_COMPRESS_AVAIL):974		return snd_compr_ioctl_avail(stream, arg);975	case _IOC_NR(SNDRV_COMPRESS_PAUSE):976		return snd_compr_pause(stream);977	case _IOC_NR(SNDRV_COMPRESS_RESUME):978		return snd_compr_resume(stream);979	case _IOC_NR(SNDRV_COMPRESS_START):980		return snd_compr_start(stream);981	case _IOC_NR(SNDRV_COMPRESS_STOP):982		return snd_compr_stop(stream);983	case _IOC_NR(SNDRV_COMPRESS_DRAIN):984		return snd_compr_drain(stream);985	case _IOC_NR(SNDRV_COMPRESS_PARTIAL_DRAIN):986		return snd_compr_partial_drain(stream);987	case _IOC_NR(SNDRV_COMPRESS_NEXT_TRACK):988		return snd_compr_next_track(stream);989	}990 991	return -ENOTTY;992}993 994/* support of 32bit userspace on 64bit platforms */995#ifdef CONFIG_COMPAT996static long snd_compr_ioctl_compat(struct file *file, unsigned int cmd,997						unsigned long arg)998{999	return snd_compr_ioctl(file, cmd, (unsigned long)compat_ptr(arg));1000}1001#endif1002 1003static const struct file_operations snd_compr_file_ops = {1004		.owner =	THIS_MODULE,1005		.open =		snd_compr_open,1006		.release =	snd_compr_free,1007		.write =	snd_compr_write,1008		.read =		snd_compr_read,1009		.unlocked_ioctl = snd_compr_ioctl,1010#ifdef CONFIG_COMPAT1011		.compat_ioctl = snd_compr_ioctl_compat,1012#endif1013		.mmap =		snd_compr_mmap,1014		.poll =		snd_compr_poll,1015};1016 1017static int snd_compress_dev_register(struct snd_device *device)1018{1019	int ret;1020	struct snd_compr *compr;1021 1022	if (snd_BUG_ON(!device || !device->device_data))1023		return -EBADFD;1024	compr = device->device_data;1025 1026	pr_debug("reg device %s, direction %d\n", compr->name,1027			compr->direction);1028	/* register compressed device */1029	ret = snd_register_device(SNDRV_DEVICE_TYPE_COMPRESS,1030				  compr->card, compr->device,1031				  &snd_compr_file_ops, compr, compr->dev);1032	if (ret < 0) {1033		pr_err("snd_register_device failed %d\n", ret);1034		return ret;1035	}1036	return ret;1037 1038}1039 1040static int snd_compress_dev_disconnect(struct snd_device *device)1041{1042	struct snd_compr *compr;1043 1044	compr = device->device_data;1045	snd_unregister_device(compr->dev);1046	return 0;1047}1048 1049#ifdef CONFIG_SND_VERBOSE_PROCFS1050static void snd_compress_proc_info_read(struct snd_info_entry *entry,1051					struct snd_info_buffer *buffer)1052{1053	struct snd_compr *compr = (struct snd_compr *)entry->private_data;1054 1055	snd_iprintf(buffer, "card: %d\n", compr->card->number);1056	snd_iprintf(buffer, "device: %d\n", compr->device);1057	snd_iprintf(buffer, "stream: %s\n",1058			compr->direction == SND_COMPRESS_PLAYBACK1059				? "PLAYBACK" : "CAPTURE");1060	snd_iprintf(buffer, "id: %s\n", compr->id);1061}1062 1063static int snd_compress_proc_init(struct snd_compr *compr)1064{1065	struct snd_info_entry *entry;1066	char name[16];1067 1068	sprintf(name, "compr%i", compr->device);1069	entry = snd_info_create_card_entry(compr->card, name,1070					   compr->card->proc_root);1071	if (!entry)1072		return -ENOMEM;1073	entry->mode = S_IFDIR | 0555;1074	compr->proc_root = entry;1075 1076	entry = snd_info_create_card_entry(compr->card, "info",1077					   compr->proc_root);1078	if (entry)1079		snd_info_set_text_ops(entry, compr,1080				      snd_compress_proc_info_read);1081	compr->proc_info_entry = entry;1082 1083	return 0;1084}1085 1086static void snd_compress_proc_done(struct snd_compr *compr)1087{1088	snd_info_free_entry(compr->proc_info_entry);1089	compr->proc_info_entry = NULL;1090	snd_info_free_entry(compr->proc_root);1091	compr->proc_root = NULL;1092}1093 1094static inline void snd_compress_set_id(struct snd_compr *compr, const char *id)1095{1096	strscpy(compr->id, id, sizeof(compr->id));1097}1098#else1099static inline int snd_compress_proc_init(struct snd_compr *compr)1100{1101	return 0;1102}1103 1104static inline void snd_compress_proc_done(struct snd_compr *compr)1105{1106}1107 1108static inline void snd_compress_set_id(struct snd_compr *compr, const char *id)1109{1110}1111#endif1112 1113static int snd_compress_dev_free(struct snd_device *device)1114{1115	struct snd_compr *compr;1116 1117	compr = device->device_data;1118	snd_compress_proc_done(compr);1119	put_device(compr->dev);1120	return 0;1121}1122 1123/**1124 * snd_compress_new: create new compress device1125 * @card: sound card pointer1126 * @device: device number1127 * @dirn: device direction, should be of type enum snd_compr_direction1128 * @id: ID string1129 * @compr: compress device pointer1130 *1131 * Return: zero if successful, or a negative error code1132 */1133int snd_compress_new(struct snd_card *card, int device,1134			int dirn, const char *id, struct snd_compr *compr)1135{1136	static const struct snd_device_ops ops = {1137		.dev_free = snd_compress_dev_free,1138		.dev_register = snd_compress_dev_register,1139		.dev_disconnect = snd_compress_dev_disconnect,1140	};1141	int ret;1142 1143	compr->card = card;1144	compr->device = device;1145	compr->direction = dirn;1146	mutex_init(&compr->lock);1147 1148	snd_compress_set_id(compr, id);1149 1150	ret = snd_device_alloc(&compr->dev, card);1151	if (ret)1152		return ret;1153	dev_set_name(compr->dev, "comprC%iD%i", card->number, device);1154 1155	ret = snd_device_new(card, SNDRV_DEV_COMPRESS, compr, &ops);1156	if (ret == 0)1157		snd_compress_proc_init(compr);1158	else1159		put_device(compr->dev);1160 1161	return ret;1162}1163EXPORT_SYMBOL_GPL(snd_compress_new);1164 1165MODULE_DESCRIPTION("ALSA Compressed offload framework");1166MODULE_AUTHOR("Vinod Koul <vinod.koul@linux.intel.com>");1167MODULE_LICENSE("GPL v2");1168