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