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