summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--configfs.c43
-rw-r--r--core.c103
-rw-r--r--core.h21
-rw-r--r--sound/avirt.h2
4 files changed, 140 insertions, 29 deletions
diff --git a/configfs.c b/configfs.c
index bc10efb..2751d66 100644
--- a/configfs.c
+++ b/configfs.c
@@ -59,6 +59,7 @@
if ((tmp > INT_MAX) || (tmp == 0)) \
return -ERANGE; \
s->channels = tmp; \
+ snd_avirt_##type##_try_complete(s); \
return count; \
} \
CONFIGFS_ATTR(cfg_snd_avirt_##type##_, channels);
@@ -140,12 +141,30 @@ static ssize_t cfg_snd_avirt_stream_map_show(struct config_item *item,
static ssize_t cfg_snd_avirt_stream_map_store(struct config_item *item,
const char *page, size_t count)
{
- char *split;
+ char *map;
+ struct snd_avirt_audiopath *audiopath;
struct snd_avirt_stream *stream =
snd_avirt_stream_from_config_item(item);
- split = strsep((char **)&page, "\n");
- snd_avirt_stream_set_map(stream, split);
+ map = strsep((char **)&page, "\n");
+
+ /* If already sealed, we cannot create the stream */
+ if (snd_avirt_streams_sealed()) {
+ D_ERRORK("Streams already sealed. Cannot set map: '%s'", map);
+ return -EPERM;
+ }
+
+ if (!strcmp(stream->map, map))
+ return -1;
+
+ audiopath = snd_avirt_audiopath_get(map);
+ if (!audiopath) {
+ D_ERRORK("Cannot find Audio Path uid: '%s'!", stream->map);
+ }
+
+ memcpy(stream->map, (char *)map, strlen(map));
+
+ snd_avirt_stream_try_complete(stream);
return count;
}
@@ -304,7 +323,8 @@ static struct config_item_type cfg_snd_avirt_route_type = {
static struct config_item *
cfg_snd_avirt_stream_make_item(struct config_group *group, const char *name)
{
- char *split;
+ char *split, *stream_name;
+ bool internal = false;
int direction;
struct snd_avirt_stream *stream;
@@ -326,16 +346,23 @@ cfg_snd_avirt_stream_make_item(struct config_group *group, const char *name)
}
// Get stream name, and create PCM for stream
- split = strsep((char **)&name, "\n");
- stream = snd_avirt_stream_create(split, direction);
+ stream_name = strsep((char **)&name, "\n");
+
+ // If internal, get internal
+ split = strstr(stream_name, "__internal");
+ if (split) {
+ stream_name = strsep((char **)&stream_name, "__");
+ internal = true;
+ }
+
+ // Finally, create stream
+ stream = snd_avirt_stream_create(stream_name, direction, internal);
if (IS_ERR(stream))
return ERR_PTR(PTR_ERR(stream));
config_item_init_type_name(&stream->item, name,
&cfg_snd_avirt_stream_type);
- D_INFOK("Make stream: %s", stream->name);
-
return &stream->item;
}
diff --git a/core.c b/core.c
index 41d6b40..d66ee2a 100644
--- a/core.c
+++ b/core.c
@@ -77,8 +77,14 @@ static struct snd_pcm *snd_avirt_pcm_create(struct snd_avirt_stream *stream)
capture = true;
}
- err = snd_pcm_new(core.card, stream->name, stream->device, playback,
- capture, &pcm);
+ if (stream->internal) {
+ err = snd_pcm_new_internal(core.card, stream->name,
+ stream->device, playback, capture,
+ &pcm);
+ } else {
+ err = snd_pcm_new(core.card, stream->name, stream->device,
+ playback, capture, &pcm);
+ }
if (err < 0) {
D_ERRORK("Failed to create PCM device for stream: '%s'",
@@ -122,29 +128,56 @@ static struct snd_avirt_route *snd_avirt_route_get(const char *uid)
return NULL;
}
-int snd_avirt_stream_set_map(struct snd_avirt_stream *stream, const char *map)
+/**
+ * int snd_avirt_route_try_complete - Set up remaining parameters for a route.
+ * Channels, sink, and source Audio Paths
+ * should be set when calling this function.
+ * @stream: The route to attempt to finalize parameters for.
+ * @return: 0 on success, negative ERRNO on failure
+ */
+int snd_avirt_route_try_complete(struct snd_avirt_route *route)
+{
+ return 0;
+}
+
+/**
+ * int snd_avirt_stream_try_complete - Set up remaining parameters for a stream.
+ * Channels and map should be set when
+ * calling this function.
+ * @stream: The stream to attempt to finalize parameters for.
+ * @return: 0 on success, negative ERRNO on failure
+ */
+int snd_avirt_stream_try_complete(struct snd_avirt_stream *stream)
{
struct snd_avirt_audiopath *audiopath;
+ struct snd_avirt_route *route;
struct snd_pcm_ops *pcm_ops_ap;
- /* If already sealed, we cannot create the stream */
- if (snd_avirt_streams_sealed()) {
- D_ERRORK("Streams already sealed. Cannot set map: '%s'", map);
+ if (snd_avirt_streams_sealed())
return -EPERM;
- }
- if (!strcmp(stream->map, map))
- return -1;
+ if ((stream->channels == 0) || (!strcmp(stream->map, "none")))
+ return -EPERM;
- memcpy(stream->map, (char *)map, strlen(map));
- audiopath = snd_avirt_audiopath_get(map);
+ audiopath = snd_avirt_audiopath_get(stream->map);
if (!audiopath) {
D_ERRORK("Cannot find Audio Path uid: '%s'!", stream->map);
- return -EFAULT;
}
/* Check for any routes that have been created for this stream */
- stream->route = snd_avirt_route_get(stream->name);
+ route = snd_avirt_route_get(stream->name);
+ if (route) {
+ if (audiopath == route->endpoint_ap[SND_AVIRT_ROUTE_SOURCE])
+ route->endpoint_stream[SND_AVIRT_ROUTE_SOURCE] = stream;
+ else if (audiopath == route->endpoint_ap[SND_AVIRT_ROUTE_SINK])
+ route->endpoint_stream[SND_AVIRT_ROUTE_SINK] = stream;
+ else {
+ D_INFOK("Cannot set route. Audio Path not compatible");
+ return -EPERM;
+ }
+
+ stream->route = route;
+ }
/* Set up PCM ops */
if (!stream->direction)
@@ -348,11 +381,21 @@ int snd_avirt_audiopath_set_private_data(struct snd_avirt_audiopath *ap,
{
int err = 0;
snd_avirt_route_endpoint endpoint = SND_AVIRT_ROUTE_SOURCE;
- struct snd_avirt_private_data *avirt_private_data = pcm->private_data;
+ struct snd_avirt_stream *stream;
+ struct snd_avirt_private_data *avirt_private_data;
+
+ stream = snd_avirt_stream_find_by_device(pcm->device);
+ if (IS_ERR_VALUE(stream) || !stream)
+ goto exit_err;
err = snd_avirt_route_endpoint_pos(pcm, ap->uid, &endpoint);
if (err == -2)
goto exit_err;
+
+ if (stream->internal && stream->route)
+ pcm = stream->route->endpoint_stream[!endpoint]->pcm;
+
+ avirt_private_data = pcm->private_data;
if (!avirt_private_data)
goto exit_err;
@@ -361,6 +404,8 @@ int snd_avirt_audiopath_set_private_data(struct snd_avirt_audiopath *ap,
return 0;
exit_err:
+ D_ERRORK("Error setting private data for ap:%s, stream:%s, endpoint:%d",
+ ap->uid, pcm->name, endpoint);
return -1;
}
EXPORT_SYMBOL_GPL(snd_avirt_audiopath_set_private_data);
@@ -376,17 +421,29 @@ void *snd_avirt_audiopath_get_private_data(struct snd_avirt_audiopath *ap,
{
int err = 0;
snd_avirt_route_endpoint endpoint = SND_AVIRT_ROUTE_SOURCE;
- struct snd_avirt_private_data *avirt_private_data = pcm->private_data;
+ struct snd_avirt_stream *stream;
+ struct snd_avirt_private_data *avirt_private_data;
+
+ stream = snd_avirt_stream_find_by_device(pcm->device);
+ if (IS_ERR_VALUE(stream) || !stream)
+ return NULL;
err = snd_avirt_route_endpoint_pos(pcm, ap->uid, &endpoint);
if (err == -2)
goto exit_err;
+
+ if (stream->internal && stream->route)
+ pcm = stream->route->endpoint_stream[!endpoint]->pcm;
+
+ avirt_private_data = pcm->private_data;
if (!avirt_private_data)
goto exit_err;
return avirt_private_data->ap_private_data[endpoint];
exit_err:
+ D_ERRORK("Error getting private data for ap:%s, stream:%s, endpoint:%d",
+ ap->uid, pcm->name, endpoint);
return NULL;
}
EXPORT_SYMBOL_GPL(snd_avirt_audiopath_get_private_data);
@@ -485,10 +542,11 @@ struct snd_avirt_route *snd_avirt_route_create(const char *uid, int direction)
* @name: The name designated to the audio stream
* @direction: The PCM direction (SNDRV_PCM_STREAM_PLAYBACK or
* SNDRV_PCM_STREAM_CAPTURE)
+ * @internal: Whether the PCM should be internal or not
* @return: The newly created audio stream if successful, or an error pointer
*/
struct snd_avirt_stream *snd_avirt_stream_create(const char *name,
- int direction)
+ int direction, bool internal)
{
struct snd_avirt_stream *stream;
@@ -505,6 +563,7 @@ struct snd_avirt_stream *snd_avirt_stream_create(const char *name,
strncpy(stream->map, "none", MAX_NAME_LEN);
stream->channels = 0;
stream->direction = direction;
+ stream->internal = internal;
stream->device = core.stream_count++;
/* Initialize PCM ops table for this stream.
@@ -516,7 +575,12 @@ struct snd_avirt_stream *snd_avirt_stream_create(const char *name,
}
memcpy(stream->pcm_ops, &pcm_ops_avirt, sizeof(struct snd_pcm_ops));
- D_INFOK("name:%s device:%d", name, stream->device);
+ if (stream->internal) {
+ D_INFOK("name:%s device:%d internal:%d", name, stream->device,
+ stream->internal);
+ } else {
+ D_INFOK("name:%s device:%d", name, stream->device);
+ }
return stream;
}
@@ -540,9 +604,8 @@ int snd_avirt_streams_seal(void)
0)
continue;
- D_INFOK("Do configure for AP: %s streams:%d cb:%p",
- ap_obj->path->uid, stream_array.count,
- ap_obj->path->configure);
+ D_INFOK("Do configure for AP: %s streams:%d", ap_obj->path->uid,
+ stream_array.count);
ap_obj->path->configure(core.card, &stream_array);
}
diff --git a/core.h b/core.h
index f915c04..38fee35 100644
--- a/core.h
+++ b/core.h
@@ -99,10 +99,29 @@ struct snd_avirt_stream *snd_avirt_stream_find_by_device(unsigned int device);
* @name: The name designated to the audio stream
* @direction: The PCM direction (SNDRV_PCM_STREAM_PLAYBACK or
* SNDRV_PCM_STREAM_CAPTURE)
+ * @internal: Whether the PCM should be internal or not
* @return: The newly created audio stream if successful, or an error pointer
*/
struct snd_avirt_stream *snd_avirt_stream_create(const char *name,
- int direction);
+ int direction, bool internal);
+
+/**
+ * int snd_avirt_route_try_complete - Set up remaining parameters for a route.
+ * Channels, sink, and source Audio Paths
+ * should be set when calling this function.
+ * @stream: The route to attempt to finalize parameters for.
+ * @return: 0 on success, negative ERRNO on failure
+ */
+int snd_avirt_route_try_complete(struct snd_avirt_route *route);
+
+/**
+ * int snd_avirt_stream_try_complete - Set up remaining parameters for a stream.
+ * Channels and map should be set when
+ * calling this function.
+ * @stream: The stream to attempt to finalize parameters for.
+ * @return: 0 on success, negative ERRNO on failure
+ */
+int snd_avirt_stream_try_complete(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/sound/avirt.h b/sound/avirt.h
index ecb0a21..9259d83 100644
--- a/sound/avirt.h
+++ b/sound/avirt.h
@@ -63,6 +63,7 @@ struct snd_avirt_route {
unsigned int channels; /* Route stream channel count */
unsigned int direction; /* Route stream direction */
struct snd_avirt_audiopath *endpoint_ap[2]; /* Source/sink */
+ struct snd_avirt_stream *endpoint_stream[2]; /* Router PCM */
struct config_item item; /* configfs item reference */
};
@@ -91,6 +92,7 @@ struct snd_avirt_stream {
unsigned int channels; /* Stream channel count */
unsigned int device; /* Stream PCM device no. */
unsigned int direction; /* Stream direction */
+ bool internal; /* Stream is internal only? */
struct snd_pcm *pcm; /* ALSA PCM */
struct snd_pcm_ops *pcm_ops; /* ALSA PCM ops */
struct snd_avirt_route *route; /* Associated route, if any */