aboutsummaryrefslogtreecommitdiffstats
path: root/sound/core/compress_offload.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--sound/core/compress_offload.c168
1 files changed, 88 insertions, 80 deletions
diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c
index 9de1c9a0173e..243acad89fd3 100644
--- a/sound/core/compress_offload.c
+++ b/sound/core/compress_offload.c
@@ -47,8 +47,6 @@
* driver should be able to register multiple nodes
*/
-static DEFINE_MUTEX(device_mutex);
-
struct snd_compr_file {
unsigned long caps;
struct snd_compr_stream stream;
@@ -488,6 +486,49 @@ out:
}
#endif /* !COMPR_CODEC_CAPS_OVERFLOW */
+int snd_compr_malloc_pages(struct snd_compr_stream *stream, size_t size)
+{
+ struct snd_dma_buffer *dmab;
+ int ret;
+
+ if (snd_BUG_ON(!(stream) || !(stream)->runtime))
+ return -EINVAL;
+ dmab = kzalloc(sizeof(*dmab), GFP_KERNEL);
+ if (!dmab)
+ return -ENOMEM;
+ dmab->dev = stream->dma_buffer.dev;
+ ret = snd_dma_alloc_pages(dmab->dev.type, dmab->dev.dev, size, dmab);
+ if (ret < 0) {
+ kfree(dmab);
+ return ret;
+ }
+
+ snd_compr_set_runtime_buffer(stream, dmab);
+ stream->runtime->dma_bytes = size;
+ return 1;
+}
+EXPORT_SYMBOL(snd_compr_malloc_pages);
+
+int snd_compr_free_pages(struct snd_compr_stream *stream)
+{
+ struct snd_compr_runtime *runtime;
+
+ if (snd_BUG_ON(!(stream) || !(stream)->runtime))
+ return -EINVAL;
+ runtime = stream->runtime;
+ if (runtime->dma_area == NULL)
+ return 0;
+ if (runtime->dma_buffer_p != &stream->dma_buffer) {
+ /* It's a newly allocated buffer. Release it now. */
+ snd_dma_free_pages(runtime->dma_buffer_p);
+ kfree(runtime->dma_buffer_p);
+ }
+
+ snd_compr_set_runtime_buffer(stream, NULL);
+ return 0;
+}
+EXPORT_SYMBOL(snd_compr_free_pages);
+
/* revisit this with snd_pcm_preallocate_xxx */
static int snd_compr_allocate_buffer(struct snd_compr_stream *stream,
struct snd_compr_params *params)
@@ -666,11 +707,22 @@ static int snd_compr_pause(struct snd_compr_stream *stream)
{
int retval;
- if (stream->runtime->state != SNDRV_PCM_STATE_RUNNING)
+ switch (stream->runtime->state) {
+ case SNDRV_PCM_STATE_RUNNING:
+ retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_PAUSE_PUSH);
+ if (!retval)
+ stream->runtime->state = SNDRV_PCM_STATE_PAUSED;
+ break;
+ case SNDRV_PCM_STATE_DRAINING:
+ if (!stream->device->use_pause_in_draining)
+ return -EPERM;
+ retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_PAUSE_PUSH);
+ if (!retval)
+ stream->pause_in_draining = true;
+ break;
+ default:
return -EPERM;
- retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_PAUSE_PUSH);
- if (!retval)
- stream->runtime->state = SNDRV_PCM_STATE_PAUSED;
+ }
return retval;
}
@@ -678,11 +730,22 @@ static int snd_compr_resume(struct snd_compr_stream *stream)
{
int retval;
- if (stream->runtime->state != SNDRV_PCM_STATE_PAUSED)
+ switch (stream->runtime->state) {
+ case SNDRV_PCM_STATE_PAUSED:
+ retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_PAUSE_RELEASE);
+ if (!retval)
+ stream->runtime->state = SNDRV_PCM_STATE_RUNNING;
+ break;
+ case SNDRV_PCM_STATE_DRAINING:
+ if (!stream->pause_in_draining)
+ return -EPERM;
+ retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_PAUSE_RELEASE);
+ if (!retval)
+ stream->pause_in_draining = false;
+ break;
+ default:
return -EPERM;
- retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_PAUSE_RELEASE);
- if (!retval)
- stream->runtime->state = SNDRV_PCM_STATE_RUNNING;
+ }
return retval;
}
@@ -722,6 +785,10 @@ static int snd_compr_stop(struct snd_compr_stream *stream)
retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_STOP);
if (!retval) {
+ /* clear flags and stop any drain wait */
+ stream->partial_drain = false;
+ stream->metadata_set = false;
+ stream->pause_in_draining = false;
snd_compr_drain_notify(stream);
stream->runtime->total_bytes_available = 0;
stream->runtime->total_bytes_transferred = 0;
@@ -743,7 +810,7 @@ static void error_delayed_work(struct work_struct *work)
mutex_unlock(&stream->device->lock);
}
-/*
+/**
* snd_compr_stop_error: Report a fatal error on a stream
* @stream: pointer to stream
* @state: state to transition the stream to
@@ -751,6 +818,8 @@ static void error_delayed_work(struct work_struct *work)
* Stop the stream and set its state.
*
* Should be called with compressed device lock held.
+ *
+ * Return: zero if successful, or a negative error code
*/
int snd_compr_stop_error(struct snd_compr_stream *stream,
snd_pcm_state_t state)
@@ -879,6 +948,7 @@ static int snd_compr_partial_drain(struct snd_compr_stream *stream)
if (stream->next_track == false)
return -EPERM;
+ stream->partial_drain = true;
retval = stream->ops->trigger(stream, SND_COMPR_TRIGGER_PARTIAL_DRAIN);
if (retval) {
pr_debug("Partial drain returned failure\n");
@@ -985,7 +1055,7 @@ static const struct file_operations snd_compr_file_ops = {
static int snd_compress_dev_register(struct snd_device *device)
{
- int ret = -EINVAL;
+ int ret;
struct snd_compr *compr;
if (snd_BUG_ON(!device || !device->device_data))
@@ -1062,7 +1132,7 @@ static void snd_compress_proc_done(struct snd_compr *compr)
static inline void snd_compress_set_id(struct snd_compr *compr, const char *id)
{
- strlcpy(compr->id, id, sizeof(compr->id));
+ strscpy(compr->id, id, sizeof(compr->id));
}
#else
static inline int snd_compress_proc_init(struct snd_compr *compr)
@@ -1089,12 +1159,15 @@ static int snd_compress_dev_free(struct snd_device *device)
return 0;
}
-/*
+/**
* snd_compress_new: create new compress device
* @card: sound card pointer
* @device: device number
* @dirn: device direction, should be of type enum snd_compr_direction
+ * @id: ID string
* @compr: compress device pointer
+ *
+ * Return: zero if successful, or a negative error code
*/
int snd_compress_new(struct snd_card *card, int device,
int dirn, const char *id, struct snd_compr *compr)
@@ -1109,6 +1182,7 @@ int snd_compress_new(struct snd_card *card, int device,
compr->card = card;
compr->device = device;
compr->direction = dirn;
+ mutex_init(&compr->lock);
snd_compress_set_id(compr, id);
@@ -1123,72 +1197,6 @@ int snd_compress_new(struct snd_card *card, int device,
}
EXPORT_SYMBOL_GPL(snd_compress_new);
-static int snd_compress_add_device(struct snd_compr *device)
-{
- int ret;
-
- if (!device->card)
- return -EINVAL;
-
- /* register the card */
- ret = snd_card_register(device->card);
- if (ret)
- goto out;
- return 0;
-
-out:
- pr_err("failed with %d\n", ret);
- return ret;
-
-}
-
-static int snd_compress_remove_device(struct snd_compr *device)
-{
- return snd_card_free(device->card);
-}
-
-/**
- * snd_compress_register - register compressed device
- *
- * @device: compressed device to register
- */
-int snd_compress_register(struct snd_compr *device)
-{
- int retval;
-
- if (device->name == NULL || device->ops == NULL)
- return -EINVAL;
-
- pr_debug("Registering compressed device %s\n", device->name);
- if (snd_BUG_ON(!device->ops->open))
- return -EINVAL;
- if (snd_BUG_ON(!device->ops->free))
- return -EINVAL;
- if (snd_BUG_ON(!device->ops->set_params))
- return -EINVAL;
- if (snd_BUG_ON(!device->ops->trigger))
- return -EINVAL;
-
- mutex_init(&device->lock);
-
- /* register a compressed card */
- mutex_lock(&device_mutex);
- retval = snd_compress_add_device(device);
- mutex_unlock(&device_mutex);
- return retval;
-}
-EXPORT_SYMBOL_GPL(snd_compress_register);
-
-int snd_compress_deregister(struct snd_compr *device)
-{
- pr_debug("Removing compressed device %s\n", device->name);
- mutex_lock(&device_mutex);
- snd_compress_remove_device(device);
- mutex_unlock(&device_mutex);
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_compress_deregister);
-
MODULE_DESCRIPTION("ALSA Compressed offload framework");
MODULE_AUTHOR("Vinod Koul <vinod.koul@linux.intel.com>");
MODULE_LICENSE("GPL v2");