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