aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--configfs.c9
-rw-r--r--core.c51
-rw-r--r--core.h4
-rw-r--r--loopback/loopback.c11
-rw-r--r--sound/avirt.h3
5 files changed, 73 insertions, 5 deletions
diff --git a/configfs.c b/configfs.c
index 4f88bf8..8f2d452 100644
--- a/configfs.c
+++ b/configfs.c
@@ -285,8 +285,7 @@ static void cfg_snd_avirt_stream_release(struct config_item *item)
}
D_INFOK("Release stream: %s", stream->name);
- kfree(stream->pcm_ops);
- kfree(stream);
+ snd_avirt_stream_try_destroy(stream);
}
static void cfg_snd_avirt_route_release(struct config_item *item)
@@ -420,12 +419,12 @@ cfg_snd_avirt_stream_group_configured_store(struct config_item *item,
CHK_ERR(kstrtoul(p, 10, &tmp));
- if (tmp != 1) {
- D_ERRORK("streams can only be sealed, not unsealed!");
+ if (tmp > 1) {
+ D_ERRORK("Configure streams must be 0 or 1!");
return -ERANGE;
}
- snd_avirt_streams_seal();
+ (tmp) ? snd_avirt_streams_configure() : snd_avirt_streams_unconfigure();
return count;
}
diff --git a/core.c b/core.c
index d9e264c..c2e32c5 100644
--- a/core.c
+++ b/core.c
@@ -112,6 +112,30 @@ static struct snd_pcm *snd_avirt_pcm_create(struct snd_avirt_stream *stream)
return pcm;
}
+void snd_avirt_stream_try_destroy(struct snd_avirt_stream *stream)
+{
+ unsigned long _flags;
+ struct snd_pcm_substream *substream =
+ stream->pcm->streams[stream->direction].substream;
+
+ snd_pcm_stream_lock_irqsave(substream, _flags);
+ if (substream->runtime) {
+ if (snd_pcm_running(substream)) {
+ if (0 !=
+ snd_pcm_stop(substream, SNDRV_PCM_STATE_SUSPENDED))
+ D_ERRORK("Could not stop PCM '%s'",
+ stream->name);
+ }
+ }
+ snd_pcm_stream_unlock_irqrestore(substream, _flags);
+
+ snd_device_free(core.card, stream->pcm);
+ kfree(stream->pcm_ops);
+ kfree(stream);
+
+ core.stream_count--;
+}
+
static struct snd_avirt_route *snd_avirt_route_get(const char *uid)
{
struct list_head *entry;
@@ -620,6 +644,33 @@ int snd_avirt_streams_configure(void)
return err;
}
+int snd_avirt_streams_unconfigure(void)
+{
+ int i = 0, err = 0;
+ struct snd_avirt_audiopath_obj *ap_obj;
+ struct snd_avirt_stream_array stream_array;
+
+ if (!core.streams_configured) {
+ D_ERRORK("streams are already unconfigured!");
+ return -1;
+ }
+
+ list_for_each_entry (ap_obj, &audiopath_list, list) {
+ if (!ap_obj->path->unconfigure) {
+ D_ERRORK("Cannot do 'unconfigure' for AP: %s",
+ ap_obj->path->uid);
+ return -EFAULT;
+ }
+
+ D_INFOK("Do 'unconfigure' for AP: %s", ap_obj->path->uid);
+ ap_obj->path->unconfigure();
+ }
+
+ core.streams_configured = false;
+
+ return 0;
+}
+
bool snd_avirt_streams_configured(void)
{
return core.streams_configured;
diff --git a/core.h b/core.h
index 6f63e8c..c39002a 100644
--- a/core.h
+++ b/core.h
@@ -81,6 +81,8 @@ void snd_avirt_audiopath_destroy_obj(struct snd_avirt_audiopath_obj *p);
*/
int snd_avirt_streams_configure(void);
+int snd_avirt_streams_unconfigure(void);
+
/**
* snd_avirt_streams_configured - Check if streams have been configured or not
* @return: true if configured, false otherwise
@@ -122,6 +124,8 @@ int snd_avirt_route_try_complete(struct snd_avirt_route *route);
* @return: 0 on success, negative ERRNO on failure
*/
int snd_avirt_stream_try_complete(struct snd_avirt_stream *stream);
+void snd_avirt_stream_try_destroy(struct snd_avirt_stream *stream);
+
/**
* snd_avirt_stream_set_map - Set Audio Path mapping for a given stream
* @stream: The stream to assign the mapping to.
diff --git a/loopback/loopback.c b/loopback/loopback.c
index de0f38a..49c188d 100644
--- a/loopback/loopback.c
+++ b/loopback/loopback.c
@@ -1080,6 +1080,14 @@ static int loopbackap_configure(struct snd_card *card,
return 0;
}
+static int loopbackap_unconfigure(void)
+{
+ mutex_destroy(&loopback->cable_lock);
+ kfree(loopback);
+
+ return 0;
+}
+
/*******************************************************************************
* Loopback Audio Path AVIRT registration
******************************************************************************/
@@ -1091,6 +1099,7 @@ static struct snd_avirt_audiopath loopbackap_module = {
.pcm_playback_ops = &loopbackap_pcm_ops,
.pcm_capture_ops = &loopbackap_pcm_ops,
.configure = loopbackap_configure,
+ .unconfigure = loopbackap_unconfigure,
};
static int __init alsa_card_loopback_init(void)
@@ -1108,6 +1117,8 @@ static int __init alsa_card_loopback_init(void)
static void __exit alsa_card_loopback_exit(void)
{
+ mutex_destroy(&loopback->cable_lock);
+ kfree(loopback);
snd_avirt_audiopath_deregister(&loopbackap_module);
}
diff --git a/sound/avirt.h b/sound/avirt.h
index 9259d83..46756b3 100644
--- a/sound/avirt.h
+++ b/sound/avirt.h
@@ -36,6 +36,8 @@ struct snd_avirt_stream_array; /* Forward declaration */
typedef int (*snd_avirt_audiopath_configure)(
struct snd_card *card, struct snd_avirt_stream_array *stream_array);
+typedef int (*snd_avirt_audiopath_unconfigure)(void);
+
typedef void (*snd_avirt_pcm_exttrigger)(void);
/**
@@ -79,6 +81,7 @@ struct snd_avirt_audiopath {
const struct snd_pcm_ops *pcm_playback_ops; /* ALSA PCM playback ops */
const struct snd_pcm_ops *pcm_capture_ops; /* ALSA PCM capture ops */
snd_avirt_audiopath_configure configure; /* Config callback function */
+ snd_avirt_audiopath_unconfigure unconfigure; /* Unconfig cb function */
snd_avirt_pcm_exttrigger pcm_exttrigger; /* External trigger callback */
void *context;
};